5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <sys/utsname.h> /* for aim_directim_initiate */
8 #include <arpa/inet.h> /* for inet_ntoa */
11 /* aim_msgcookies.c is mostly new. just look at the diff and replace yours, easiest. */
14 function name where i had it
15 aim_send_im_direct aim_im.c
16 aim_directim_initiate aim_im.c
17 aim_filetransfer_accept aim_im.c
18 aim_getlisting aim_misc.c (?!) -- prototype function. can be ignored.
20 aim_get_command_rendezvous aim_r
21 oft_getfh aim_rxqueue.c
24 faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_conn_t *cur)
27 rxcallback_t userfunc;
28 struct sockaddr cliaddr;
29 socklen_t clilen = sizeof(cliaddr);
33 * Listener sockets only have incoming connections. No data.
35 if( (acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1)
38 if (cliaddr.sa_family != AF_INET) /* just in case IPv6 really is happening */
41 switch(cur->subtype) {
42 case AIM_CONN_SUBTYPE_OFT_DIRECTIM: {
43 struct aim_directim_priv *priv;
45 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
47 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
50 cur->priv = priv; /* what happens if there is one?! -- mid */
52 cur->type = AIM_CONN_TYPE_RENDEZVOUS;
53 close(cur->fd); /* should we really do this? seems like the client should decide. maybe clone the connection and keep the listener open. -- mid */
56 if ( (userfunc = aim_callhandler(cur, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE)))
57 ret = userfunc(sess, NULL, cur);
61 case AIM_CONN_SUBTYPE_OFT_GETFILE: {
62 struct aim_filetransfer_priv *priv;
64 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
66 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
71 if ( (userfunc = aim_callhandler(cur, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE)))
72 ret = userfunc(sess, NULL, cur);
86 * conn - directim connection
87 * msg - null-terminated string to send
90 faim_export int aim_send_im_direct(struct aim_session_t *sess,
91 struct aim_conn_t *conn,
94 struct command_tx_struct *newpacket , *newpacket2;
96 /* newpacket contains a real header with data, newpacket2 is just a
97 null packet, with a cookie and a lot of 0x00s. newpacket is the
98 "i'm sending", newpacket2 is the "i'm typing".*/
100 /* uhm. the client should send those as two seperate things -- mid */
102 struct aim_directim_priv *priv = NULL;
105 if (!sess || !conn || !(conn->type) || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !conn->priv || !msg) {
106 printf("faim: directim: invalid arguments\n");
110 if (strlen(msg) >= MAXMSGLEN)
113 priv = (struct aim_directim_priv *)conn->priv;
117 if (!(newpacket2 = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0001, conn, 0))) {
118 printf("faim: directim: tx_new2 failed\n");
122 newpacket2->lock = 1; /* lock struct */
124 memcpy(newpacket2->hdr.oft.magic, "ODC2", 4);
125 newpacket2->hdr.oft.hdr2len = 0x44;
127 if (!(newpacket2->hdr.oft.hdr2 = calloc(1,newpacket2->hdr.oft.hdr2len))) {
133 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0006);
134 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
136 i += aimutil_putstr(newpacket2->hdr.oft.hdr2+i, (char *)priv->cookie, 8);
138 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
139 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
140 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
141 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
143 i += aimutil_put32(newpacket2->hdr.oft.hdr2+i, 0x00000000);
145 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
146 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
147 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
149 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x000e);
151 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
152 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
154 i += aimutil_putstr(newpacket2->hdr.oft.hdr2+i, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
157 i += aimutil_put8(newpacket2->hdr.oft.hdr2+i, 0x00); /* 53 */
158 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000); /* 55 */
159 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
160 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
161 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);/* 61 */
162 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
163 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);/* 65 */
164 i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);/* end of hdr2 */
166 newpacket2->lock = 0;
167 newpacket2->data = NULL;
169 aim_tx_enqueue(sess, newpacket2);
173 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0001, conn, strlen(msg)))) {
174 printf("faim: directim: tx_new failed\n");
178 newpacket->lock = 1; /* lock struct */
180 memcpy(newpacket->hdr.oft.magic, "ODC2", 4);
181 newpacket->hdr.oft.hdr2len = 0x54;
183 if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) {
189 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0006);
190 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
192 i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, (char *)priv->cookie, 8);
194 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
195 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
196 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
197 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
199 i += aimutil_put32(newpacket->hdr.oft.hdr2+i, strlen(msg));
201 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
202 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
203 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
204 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
205 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
206 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
208 i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
211 i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00); /* 53 */
212 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); /* 55 */
213 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
214 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
215 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);/* 61 */
216 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
217 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);/* 65 */
218 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);/* end of hdr2 */
220 /* values grabbed from a dump */
221 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); /* 69 */
222 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);
223 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);/* 71 */
224 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);/* 73 */
225 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);/* 73 */
226 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
227 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
228 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
230 memcpy(newpacket->data, msg, strlen(msg));
234 aim_tx_enqueue(sess, newpacket);
240 * aim_directim_intitiate:
241 * For those times when we want to open up the directim channel ourselves.
242 * sess is your session,
243 * conn is the BOS conn,
244 * priv is a dummy priv value (we'll let it get filled in later) (if
245 * you pass a NULL, we alloc one)
246 * destsn is the SN to connect to.
250 faim_export struct aim_conn_t *aim_directim_initiate(struct aim_session_t *sess,
251 struct aim_conn_t *conn,
252 struct aim_directim_priv *priv,
255 struct command_tx_struct *newpacket;
256 struct aim_conn_t *newconn;
258 struct aim_msgcookie_t *cookie;
260 int curbyte, i, listenfd;
263 struct hostent *hptr;
266 unsigned char cap[16];
267 char d[4]; /* XXX: IPv6. *cough* */
273 if( (listenfd = aim_listenestablish(port)) == -1)
280 if(gethostname(localhost, 128) < 0)
283 if( (hptr = gethostbyname(localhost)) == NULL)
286 memcpy(&d, hptr->h_addr_list[0], 4); /* XXX: this probably isn't quite kosher, but it works */
288 aim_putcap(cap, 16, AIM_CAPS_IMIMAGE);
291 * create the OSCAR packet
294 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(destsn)+4+4+0x32)))
297 newpacket->lock = 1; /* lock struct */
300 curbyte += aim_putsnac(newpacket->data+curbyte,
301 0x0004, 0x0006, 0x0000, sess->snac_nextid);
304 * Generate a random message cookie
305 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible.
308 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) rand() % 20));
309 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
312 * grab all the data for cookie caching.
314 cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t));
316 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
317 cookie->type = AIM_COOKIETYPE_OFTIM;
320 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
322 memcpy(priv->cookie, cookie, 8);
323 memcpy(priv->sn, destsn, sizeof(priv->sn));
327 aim_cachecookie(sess, cookie); /* cache da cookie */
332 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
335 * Destination SN (prepended with byte length)
337 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
338 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
340 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
341 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
346 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
347 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0032);
350 * Flag data / ICBM Parameters?
352 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
353 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
358 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
363 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
368 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
369 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
370 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
373 * 0003/0004: IP address
376 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
377 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
379 for(i = 0; i < 4; i++)
380 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); /* already in network byte order */
386 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
387 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
388 curbyte += aimutil_put16(newpacket->data+curbyte, port);
391 * 000f/0000: umm.. dunno. Zigamorph[1]?
392 * [1]: see esr's TNHD.
395 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
396 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
398 printf("curbyte: 0x%x\n",curbyte);
400 newpacket->commandlen = curbyte;
403 aim_tx_enqueue(sess, newpacket);
406 * allocate and set up our connection
409 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
411 perror("aim_newconn");
412 aim_conn_kill(sess, &newconn);
416 newconn->fd = listenfd;
417 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
418 newconn->priv = priv;
419 printf("faim: listening (fd = %d, unconnected)\n", newconn->fd);
422 * XXX We need some way of closing the listener socket after
423 * n seconds of no connection. -- mid
426 #ifdef USE_SNAC_FOR_IMS
428 struct aim_snac_t snac;
430 snac.id = sess->snac_nextid;
431 snac.family = 0x0004;
435 snac.data = malloc(strlen(destsn)+1);
436 memcpy(snac.data, destsn, strlen(destsn)+1);
438 aim_newsnac(sess, &snac);
440 aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */
448 * struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_directim_priv *priv)
449 * sess is the session to append the conn to,
450 * conn is the BOS connection,
451 * priv is the filled-in priv data structure for the connection
452 * returns conn if connected, NULL on error
456 faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess,
457 struct aim_conn_t *conn,
458 struct aim_directim_priv *priv )
460 struct aim_conn_t *newconn = NULL;;
462 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, priv->ip);
463 if (!newconn || (newconn->fd == -1)) {
464 printf("could not connect to %s\n", priv->ip);
465 perror("aim_newconn");
466 aim_conn_kill(sess, &newconn);
469 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
470 newconn->priv = priv;
471 printf("faim: connected to peer (fd = %d)\n", newconn->fd);
478 * struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, const char *name)
479 * sess is your session,
480 * name is the name to get,
481 * returns conn for directim with name, NULL if none found.
484 faim_export struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, const char *name)
486 struct aim_conn_t *cur;
487 struct aim_directim_priv *priv;
489 faim_mutex_lock(&sess->connlistlock);
490 for (cur = sess->connlist; cur; cur = cur->next) {
491 if (cur->type != AIM_CONN_TYPE_RENDEZVOUS || cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)
495 if (aim_sncmp(priv->sn, name) == 0)
498 faim_mutex_unlock(&sess->connlistlock);
504 * aim_accepttransfer:
505 * accept a file transfer request.
506 * sess is the session,
507 * conn is the BOS conn for the CAP reply
508 * sn is the screenname to send it to,
509 * cookie is the cookie used
510 * ip is the ip to connect to
511 * file is the listing file to use
517 faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess,
518 struct aim_conn_t *conn,
523 unsigned short rendid)
525 struct command_tx_struct *newpacket, *newoft;
527 struct aim_conn_t *newconn;
528 struct aim_fileheader_t *listingfh;
529 struct aim_filetransfer_priv *priv;
530 struct aim_msgcookie_t *cachedcook;
534 if(rendid == AIM_CAPS_GETFILE) {
536 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip);
538 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
540 if (!newconn || (newconn->fd == -1)) {
541 perror("aim_newconn");
542 faimdprintf(2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
543 aim_conn_kill(sess, &newconn);
546 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
547 memcpy(priv->cookie, cookie, 8);
548 strncpy(priv->sn, sn, MAXSNLEN);
549 strncpy(priv->ip, ip, sizeof(priv->ip));
550 newconn->priv = (void *)priv;
551 faimdprintf(2, "faim: connected to peer (fd = %d)\n", newconn->fd);
554 /* cache da cookie. COOOOOKIES! */
556 if(!(cachedcook = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) {
557 faimdprintf(1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
558 /* XXX die here, or go on? search for cachedcook for future references */
562 memcpy(cachedcook->cookie, cookie, 8);
564 /* strncpy(ft->fh.name, miscinfo->value+8, sizeof(ft->fh.name)); */
566 if(cachedcook) { /* see above calloc of cachedcook */
567 cachedcook->type = AIM_COOKIETYPE_OFTGET;
568 cachedcook->data = (void *)priv;
570 if (aim_cachecookie(sess, cachedcook) != 0)
571 faimdprintf(1, "faim: ERROR caching message cookie\n");
574 if(rendid == AIM_CAPS_GETFILE) {
575 faimdprintf(2, "faim: getfile request accept\n");
576 if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x1108, newconn, 0))) {
577 faimdprintf(2, "faim: aim_accepttransfer: tx_new OFT failed\n");
578 /* XXX: what else do we need to clean up here? */
584 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
585 newoft->hdr.oft.hdr2len = 0xf8; /* 0x100 - 8 */
587 if(!(listingfh = aim_getlisting(file))) {
591 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
596 memcpy(listingfh->bcookie, cookie, 8);
598 aim_oft_buildheader((void *)newoft->hdr.oft.hdr2, listingfh);
603 aim_tx_enqueue(sess, newoft);
604 printf("faim: getfile: OFT listing enqueued.\n");
608 /* OSCAR CAP accept packet */
610 if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sn)+4+2+8+16)))
615 curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
616 for (i = 0; i < 8; i++)
617 curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
618 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
619 curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn));
620 curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn));
621 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
622 curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a);
623 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept */);
624 for (i = 0; i < 8; i++)
625 curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
626 curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid);
629 aim_tx_enqueue(sess, newpacket);
637 * aim_getlisting(FILE *file)
639 * file is an opened listing file
640 * returns a pointer to the filled-in fileheader_t
642 * currently omits checksum. we'll fix this when AOL breaks us, i
647 faim_internal struct aim_fileheader_t *aim_getlisting(FILE *file)
649 struct aim_fileheader_t *fh;
650 u_long totsize = 0, size = 0, checksum = 0xffff0000;
652 char *linebuf, sizebuf[9];
654 int linelength = 1024;
656 /* XXX: if we have a line longer than 1024chars, God help us. */
657 if( (linebuf = (char *)calloc(1, linelength)) == NULL ) {
658 faimdprintf(2, "linebuf calloc failed\n");
662 if(fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
663 perror("getlisting END1 fseek:");
664 faimdprintf(2, "getlising fseek END1 error\n");
667 if(fgetpos(file, &size) == -1) {
668 perror("getlisting END1 getpos:");
669 faimdprintf(2, "getlising getpos END1 error\n");
672 if(fseek(file, 0, SEEK_SET) != 0) {
673 perror("getlesting fseek(SET):");
674 faimdprintf(2, "faim: getlisting: couldn't seek to beginning of listing file\n");
677 bzero(linebuf, linelength);
681 while(fgets(linebuf, linelength, file)) {
685 size += strlen(linebuf);
687 if(strlen(linebuf) < 23) {
688 faimdprintf(2, "line \"%s\" too short. skipping\n", linebuf);
691 if(linebuf[strlen(linebuf)-1] != '\n') {
692 faimdprintf(2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
695 memcpy(sizebuf, linebuf+17, 8);
697 totsize += strtol(sizebuf, NULL, 10);
698 bzero(linebuf, linelength);
702 faimdprintf(2, "faim: getlisting: size != 0 after while.. %i\n", size);
705 if(fseek(file, 0, SEEK_SET) == -1) {
706 perror("getlisting END2 fseek:");
707 faimdprintf(2, "getlising fseek END2 error\n");
712 /* we're going to ignore checksumming the data for now -- that
713 * requires walking the whole listing.txt. it should probably be
714 * done at register time and cached, but, eh. */
716 if(!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
719 printf( "faim: OFT: getlisting: totfiles: %u, totsize: %lu, size: %lu\n", totfiles, totsize, size);
721 fh->encrypt = 0x0000;
722 fh->compress = 0x0000;
723 fh->totfiles = totfiles;
724 fh->filesleft = totfiles; /* is this right ?*/
725 fh->totparts = 0x0001;
726 fh->partsleft = 0x0001;
727 fh->totsize = totsize;
728 fh->size = size; /* ls -l listing.txt */
729 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
730 fh->checksum = checksum; /* XXX: checksum ! */
731 fh->rfcsum = 0x00000000;
732 fh->rfsize = 0x00000000;
733 fh->cretime = 0x00000000;
734 fh->rfcsum = 0x00000000;
735 fh->nrecvd = 0x00000000;
736 fh->recvcsum = 0x00000000;
738 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */
739 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
740 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
743 fh->lnameoffset = 0x1a;
744 fh->lsizeoffset = 0x10;
746 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */
747 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
749 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */
750 fh->nlanguage = 0x0000;
752 /* memset(fh->name, 0, sizeof(fh->name)); */
753 memcpy(fh->name, "listing.txt", sizeof(fh->name));
754 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
756 faimdprintf(2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
761 * establish: create a listening socket on a port. you need to call
762 * accept() when it's connected.
763 * portnum is the port number to bind to.
767 faim_internal int aim_listenestablish(u_short portnum)
769 #if defined(__linux__) /* XXX what other OS's support getaddrinfo? */
772 struct addrinfo hints, *res, *ressave;
774 sprintf(serv, "%d", portnum);
775 memset(&hints, 0, sizeof(struct addrinfo));
776 hints.ai_flags = AI_PASSIVE;
777 hints.ai_family = AF_UNSPEC;
778 hints.ai_socktype = SOCK_STREAM;
779 if (getaddrinfo(NULL/*any IP*/, serv, &hints, &res) != 0) {
780 perror("getaddrinfo");
785 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
788 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
789 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
792 } while ( (res = res->ai_next) );
795 if (listen(listenfd, 1024)!=0) {
799 freeaddrinfo(ressave);
804 struct sockaddr_in sockin;
806 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
807 perror("socket(listenfd)");
810 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) != 0)) {
811 perror("setsockopt(listenfd)");
815 memset(&sockin, 0, sizeof(struct sockaddr_in));
816 sockin.sin_family = AF_INET;
817 sockin.sin_port = htons(portnum);
818 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
819 perror("bind(listenfd)");
823 if (listen(listenfd, 4) != 0) {
824 perror("listen(listenfd)");
833 faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
835 unsigned char hdrbuf1[6];
836 unsigned char *hdr = NULL;
839 rxcallback_t userfunc = NULL;
842 memset(hdrbuf1, 0, sizeof(hdrbuf1));
844 faim_mutex_lock(&conn->active); /* gets locked down for the entirety */
846 if ( (hdrlen = aim_recv(conn->fd, hdrbuf1, 6)) < 6) {
848 faimdprintf(2, "faim: rend: read error (fd: %i) %02x%02x%02x%02x%02x%02x (%i)\n", conn->fd, hdrbuf1[0],hdrbuf1[1],hdrbuf1[0],hdrbuf1[0],hdrbuf1[0],hdrbuf1[0],hdrlen);
849 faim_mutex_unlock(&conn->active);
853 else { /* disconnected */
854 switch(conn->subtype) {
855 case AIM_CONN_SUBTYPE_OFT_DIRECTIM: { /* XXX: clean up cookies here ? */
856 struct aim_directim_priv *priv = NULL;
857 if(!(priv = (struct aim_directim_priv *)conn->priv) )
858 return -1; /* not much we can do */
859 aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTIM);
862 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT)) ) {
863 aim_conn_close(conn);
864 return userfunc(sess, NULL, conn, priv->sn);
870 case AIM_CONN_SUBTYPE_OFT_GETFILE: {
871 struct aim_filetransfer_priv *priv;
872 if(!(priv = (struct aim_filetransfer_priv *)conn->priv))
875 aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET);
877 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT)) ) {
878 aim_conn_close(conn);
879 return userfunc(sess, NULL, conn, priv->sn);
885 case AIM_CONN_SUBTYPE_OFT_SENDFILE: {
886 struct aim_filetransfer_priv *priv;
887 if(!(priv = (struct aim_filetransfer_priv *)conn->priv))
890 aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND);
892 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEDISCONNECT)) ) {
893 aim_conn_close(conn);
894 return userfunc(sess, NULL, conn, priv->sn);
901 aim_conn_close(conn);
902 aim_conn_kill(sess, &conn);
908 hdrlen = aimutil_get16(hdrbuf1+4);
911 if (!(hdr = malloc(hdrlen))) {
912 faim_mutex_unlock(&conn->active);
916 if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) {
918 faimdprintf(2,"faim: rend: read2 error\n");
920 faim_mutex_unlock(&conn->active);
921 aim_conn_close(conn);
925 hdrtype = aimutil_get16(hdr);
928 case 0x0001: { /* directim */
929 int payloadlength = 0;
931 struct aim_directim_priv *priv;
934 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
936 payloadlength = aimutil_get32(hdr+22);
937 flags = aimutil_get16(hdr+32);
938 snptr = (char *)hdr+38;
940 strncpy(priv->sn, snptr, MAXSNLEN);
942 faimdprintf(2, "faim: OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
944 if (flags == 0x000e) {
945 faim_mutex_unlock(&conn->active);
946 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)) )
947 return userfunc(sess, NULL, snptr);
948 } else if ((flags == 0x0000) && payloadlength) {
951 if(! (msg = calloc(1, payloadlength+1)) ) {
952 faim_mutex_unlock(&conn->active);
956 if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) {
958 printf("faim: rend: read3 error\n");
960 faim_mutex_unlock(&conn->active);
961 aim_conn_close(conn);
964 faim_mutex_unlock(&conn->active);
965 msg[payloadlength] = '\0';
966 faimdprintf(2, "faim: directim: %s/%04x/%04x/%s\n", snptr, payloadlength, flags, msg);
969 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
970 i = userfunc(sess, NULL, conn, snptr, msg);
978 /* currently experimental to a non-compiling degree */
979 case 0x1108: { /* getfile listing.txt incoming tx->rx */
980 struct aim_filetransfer_priv *ft;
981 struct aim_fileheader_t *fh;
982 struct aim_msgcookie_t *cook;
983 struct aim_conn_type *newoft;
988 faimdprintf(2,"faim: rend: fileget 0x1108\n");
990 if(!(ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) {
991 faimdprintf(2, "faim: couldn't malloc ft. um. bad. bad bad. file transfer will likely fail, sorry.\n");
992 faim_mutex_unlock(&conn->active);
996 ft->state = 1; /* we're waaaaiiiting.. */
998 fh = aim_oft_getfh(hdr);
1000 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1002 if(!(cook = aim_checkcookie(sess, ft->fh.bcookie, AIM_COOKIETYPE_OFTGET))) {
1003 faim_mutex_unlock(&conn->active);
1012 aim_cachecookie(sess, cook);
1014 if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x1209, conn, 0))) {
1015 /* XXX: what else do we need to clean up here? */
1016 faim_mutex_unlock(&conn->active);
1021 aim_oft_buildheader((void *)newoft->hdr.oft.hdr2, ft->fh); /* no change */
1023 aim_tx_enqueue(sess, newoft);
1027 case 0x1209: { /* get file listing ack rx->tx */
1028 struct aim_filetransfer_priv *ft;
1029 struct aim_fileheader_t *fh;
1030 struct aim_msgcookie_t *cook;
1035 faimdprintf(2,"faim: rend: fileget 0x1209\n");
1037 if(!(ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) {
1038 faimdprintf(2, "faim: couldn't malloc ft. um. bad. bad bad. file transfer will likely fail, sorry.\n");
1039 faim_mutex_unlock(&conn->active);
1043 fh = aim_oft_getfh(hdr);
1045 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1047 cook = aim_checkcookie(sess, ft->fh.bcookie, AIM_COOKIETYPE_OFTGET);
1049 /* we currently trust the other client to be giving us Valid
1050 * Enough input, else this gets to be a messy function (and we
1051 * won't break like winaim does when it gets bad input =) */
1054 free(cook->data); /* XXX */
1058 aim_cachecookie(sess, cook);
1060 /* XXX: have this send chunks of the file instead of the whole
1061 * file. requires rethinking some code. */
1063 if(fseek(sess->oft.listing, 0, SEEK_SET) != 0) {
1064 perror("get_command_rendezvous 1209 fseek(SET):");
1065 faimdprintf(2, "faim: getlisting: couldn't seek to beginning of listing file\n");
1067 commandlen = ft->fh.size;
1069 if((data = (char *)calloc(1, commandlen)) == NULL) {
1070 faimdprintf(2, "faim: get_command_rendezvous 1209: couldn't malloc data.\n");
1071 faim_mutex_unlock(&conn->active);
1076 for(commandlen = 0; commandlen < ft->fh.size; commandlen++)
1077 if( (data[commandlen] = (unsigned char)fgetc(sess->oft.listing)) == EOF)
1078 faimdprintf(2, "faim: get_command_rendezvous 1209: got early EOF (error?)\n");
1080 commandlen = ft->fh.size;
1082 if (write(conn->fd, data, commandlen) != commandlen) {
1083 perror("listing write error");
1085 faim_mutex_unlock(&conn->active);
1087 faimdprintf(2, "faim: get_command_rendezvous: hit end of 1209\n");
1093 case 0x120b: { /* get file second */
1094 struct aim_filetransfer_priv *ft;
1095 struct aim_msgcookie_t *cook;
1097 struct aim_fileheader_t *fh;
1099 faimdprintf(2, "faim: rend: fileget 120b\n");
1101 if(!(ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) {
1102 faimdprintf(2, "faim: couldn't malloc ft. um. bad. bad bad. file transfer will likely fail, sorry.\n");
1103 faim_mutex_unlock(&conn->active);
1107 fh = aim_oft_getfh(hdr);
1109 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1111 if(!(cook = aim_checkcookie(sess, ft->fh.bcookie, AIM_COOKIETYPE_OFTGET))) {
1112 faim_mutex_unlock(&conn->active);
1117 free(cook->data); /* XXX: integrate cookie caching */
1121 aim_cachecookie(sess, cook);
1123 faim_mutex_unlock(&conn->active);
1125 /* call listing.txt rx confirm */
1129 case 0x120c: { /* yet more get file */
1130 struct aim_filetransfer_priv *ft;
1131 struct aim_msgcookie_t *cook;
1132 struct aim_fileheader_t *listingfh;
1133 struct command_tx_struct *newoft;
1137 rxcallback_t userfunc;
1139 printf("faim: rend: fileget 120c\n");
1141 if(!(ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) {
1142 printf("faim: couldn't malloc ft. um. bad. bad bad. file transfer will likely fail, sorry.\n");
1143 faim_mutex_unlock(&conn->active);
1148 printf("faim: fileget_command(120c): um. hdrlen != 0x100..\n");
1150 listingfh = aim_oft_getfh((char *)hdr);
1152 memcpy(&(ft->fh), listingfh, sizeof(struct aim_fileheader_t));
1154 if(!(cook = aim_checkcookie(sess, ft->fh.bcookie, AIM_COOKIETYPE_OFTGET))) {
1155 faim_mutex_unlock(&conn->active);
1160 free(cook->data); /* XXX */
1164 aim_cachecookie(sess, cook);
1166 faim_mutex_unlock(&conn->active);
1168 faimdprintf(2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name);
1170 if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) )
1171 i = userfunc(sess, NULL, conn, &ft->fh, cook->cookie);
1176 if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0101, conn, 0))) {
1177 faimdprintf(2, "faim: send_final_transfer: tx_new OFT failed\n");
1183 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1184 newoft->hdr.oft.hdr2len = 0xf8; /* 0x100 - 8 */
1186 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1188 aim_tx_destroy(newoft);
1192 /* memcpy(listingfh->bcookie, ft->fh.bcookie, 8); */
1194 listingfh->nrecvd = 0; /* these need reset for protocol-correctness */
1195 listingfh->recvcsum = 0;
1197 aim_oft_buildheader((void *)newoft->hdr.oft.hdr2, listingfh);
1200 aim_tx_enqueue(sess, newoft);
1201 faimdprintf(2, "faim: OFT: OFT file enqueued.\n");
1203 if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL)
1206 i = userfunc(sess, NULL, conn, listingfh, listingfh->bcookie);
1214 case 0x0202: { /* get file: ready to recieve data */
1215 struct aim_fileheader_t *fh;
1216 fh = aim_oft_getfh((char *)hdr);
1218 faimdprintf(2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n");
1220 faim_mutex_unlock(&conn->active);
1222 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) == NULL)
1225 return userfunc(sess, NULL, conn, fh);
1231 case 0x0204: { /* get file: finished. close it up */
1234 struct aim_fileheader_t *fh;
1235 fh = aim_oft_getfh((char *)hdr);
1237 faimdprintf(2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n");
1239 faim_mutex_unlock(&conn->active);
1241 if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) )
1242 i = userfunc(sess, NULL, conn, fh);
1248 /* not sure where to do this yet, as we need to keep it to allow multiple file sends... bleh */
1254 printf("OFT frame: type %04x\n", hdrtype);
1255 /* data connection may be unreliable here */
1256 faim_mutex_unlock(&conn->active);
1267 * aim_oft_registerlisting()
1269 * file: opened FILE *
1270 * listingdir: the path to listing.txt
1271 * returns -1 on error, 0 on success.
1273 * it's not my problem if the listing fd is already set.
1276 faim_export int aim_oft_registerlisting(struct aim_session_t *sess, FILE *file, char* listingdir)
1281 /* XXX: checksum each file in the listing */
1284 if(sess->oft.listing) {
1285 faimdprintf(1, "We already have a file pointer. Closing and overwriting.\n");
1286 fclose(sess->oft.listing);
1289 sess->oft.listing = file;
1291 if(sess->oft.listingdir) {
1292 faimdprintf(1, "We already have a directory string. Freeing and overwriting\n");
1293 free(sess->oft.listingdir);
1297 if( (sess->oft.listingdir = (char *)calloc(1, strlen(listingdir)+1)) )
1298 memcpy(sess->oft.listingdir, listingdir, strlen(listingdir));
1304 faim_internal struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr)
1306 struct aim_fileheader_t *fh;
1309 if(!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
1312 /* [0] and [1] are the type. we can ignore those here. */
1316 for(j = 0; j < 8; j++, i++)
1317 fh->bcookie[j] = hdr[i];
1318 fh->encrypt = aimutil_get16(hdr+i);
1320 fh->compress = aimutil_get16(hdr+i);
1322 fh->totfiles = aimutil_get16(hdr+i);
1324 fh->filesleft = aimutil_get16(hdr+i);
1326 fh->totparts = aimutil_get16(hdr+i);
1328 fh->partsleft = aimutil_get16(hdr+i);
1330 fh->totsize = aimutil_get32(hdr+i);
1332 fh->size = aimutil_get32(hdr+i);
1334 fh->modtime = aimutil_get32(hdr+i);
1336 fh->checksum = aimutil_get32(hdr+i);
1338 fh->rfrcsum = aimutil_get32(hdr+i);
1340 fh->rfsize = aimutil_get32(hdr+i);
1342 fh->cretime = aimutil_get32(hdr+i);
1344 fh->rfcsum = aimutil_get32(hdr+i);
1346 fh->nrecvd = aimutil_get32(hdr+i);
1348 fh->recvcsum = aimutil_get32(hdr+i);
1351 memcpy(fh->idstring, hdr+i, 32);
1354 fh->flags = aimutil_get8(hdr+i);
1356 fh->lnameoffset = aimutil_get8(hdr+i);
1358 fh->lsizeoffset = aimutil_get8(hdr+i);
1361 memcpy(fh->dummy, hdr+i, 69);
1364 memcpy(fh->macfileinfo, hdr+i, 16);
1367 fh->nencode = aimutil_get16(hdr+i);
1369 fh->nlanguage = aimutil_get16(hdr+i);
1372 memcpy(fh->name, hdr+i, 64);
1378 faim_export int aim_oft_checksum(char *buffer, int bufsize, int *checksum)
1380 short check0, check1;
1383 check0 = ((*checksum & 0xFF000000) >> 16);
1384 check1 = ((*checksum & 0x00ff0000) >> 16);
1386 for(i = 0; i < bufsize; i++) {
1388 if(i % 2) { /* use check1 -- second byte */
1389 if ( (short)buffer[i] > check1 ) { /* wrapping */
1391 check1 += 0x100; /* this is a cheap way to wrap */
1393 /* if we're wrapping, decrement the other one */
1394 if(check0 == 0) /* XXX: check this corner case */
1400 check1 -= buffer[i];
1401 } else { /* use check0 -- first byte */
1402 if ( (short)buffer[i] > check0 ) { /* wrapping */
1404 check0 += 0x100; /* this is a cheap way to wrap */
1406 /* if we're wrapping, decrement the other one */
1407 if(check1 == 0) /* XXX: check this corner case */
1413 check0 -= buffer[i];
1417 if(check0 > 0xff || check1 > 0xff) { /* they shouldn't be able to do this. error! */
1418 faimdprintf(2, "check0 or check1 is too high: 0x%04x, 0x%04x\n", check0, check1);
1422 check0 &= 0xff; /* grab just the lowest byte */
1423 check1 &= 0xff; /* this should be clean, but just in case */
1425 *checksum = ((check0 * 0x1000000) + (check1 * 0x10000));
1432 * aim_oft_buildheader:
1433 * fills a buffer with network-order fh data.
1434 * returns length written; -1 on error.
1435 * dest: buffer to fill -- pre-alloced
1436 * listingfh: fh to get data from
1438 * DOES NOT DO BOUNDS CHECKING!
1442 faim_internal int aim_oft_buildheader(char *dest,struct aim_fileheader_t *listingfh)
1446 if(!dest || !listingfh)
1450 for(i = 0; i < 8; i++)
1451 curbyte += aimutil_put8(dest+curbyte, listingfh->bcookie[i]);
1452 curbyte += aimutil_put16(dest+curbyte, listingfh->encrypt);
1453 curbyte += aimutil_put16(dest+curbyte, listingfh->compress);
1454 curbyte += aimutil_put16(dest+curbyte, listingfh->totfiles);
1455 curbyte += aimutil_put16(dest+curbyte, listingfh->filesleft);
1456 curbyte += aimutil_put16(dest+curbyte, listingfh->totparts);
1457 curbyte += aimutil_put16(dest+curbyte, listingfh->partsleft);
1458 curbyte += aimutil_put32(dest+curbyte, listingfh->totsize);
1459 curbyte += aimutil_put32(dest+curbyte, listingfh->size);
1460 curbyte += aimutil_put32(dest+curbyte, listingfh->modtime);
1461 curbyte += aimutil_put32(dest+curbyte, listingfh->checksum);
1462 curbyte += aimutil_put32(dest+curbyte, listingfh->rfrcsum);
1463 curbyte += aimutil_put32(dest+curbyte, listingfh->rfsize);
1464 curbyte += aimutil_put32(dest+curbyte, listingfh->cretime);
1465 curbyte += aimutil_put32(dest+curbyte, listingfh->rfcsum);
1466 curbyte += aimutil_put32(dest+curbyte, listingfh->nrecvd);
1467 curbyte += aimutil_put32(dest+curbyte, listingfh->recvcsum);
1469 memcpy(dest+curbyte, listingfh->idstring, 32);
1472 curbyte += aimutil_put8(dest+curbyte, listingfh->flags);
1473 curbyte += aimutil_put8(dest+curbyte, listingfh->lnameoffset);
1474 curbyte += aimutil_put8(dest+curbyte, listingfh->lsizeoffset);
1476 memcpy(dest+curbyte, listingfh->dummy, 69);
1479 memcpy(dest+curbyte, listingfh->macfileinfo, 16);
1482 curbyte += aimutil_put16(dest+curbyte, listingfh->nencode);
1483 curbyte += aimutil_put16(dest+curbyte, listingfh->nlanguage);
1485 memcpy(dest+curbyte, listingfh->name, 64); /* XXX: Filenames longer than 64B */
1492 * int aim_getfile_send(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh)
1493 * conn is the OFT connection to shove the data down,
1494 * tosend is the FILE * for the file to send
1495 * fh is the filled-in fh value
1496 * returns -1 on error, 1 on success.
1499 faim_export int aim_getfile_send(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh)
1502 const int bufsize = 4096;
1506 if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->subtype != AIM_CONN_SUBTYPE_OFT_GETFILE) {
1507 faimdprintf(1, "getfile_send: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
1512 faimdprintf(1, "getfile_send: file pointer isn't valid\n");
1517 faimdprintf(1, "getfile_send: fh isn't valid\n");
1523 if(!(buf = (char *)calloc(1, bufsize))) {
1524 perror("faim: getfile_send: calloc:");
1525 faimdprintf(2, "getfile_send calloc error\n");
1531 if( fseek(tosend, 0, SEEK_SET) == -1) {
1532 perror("faim: getfile_send: fseek:");
1533 faimdprintf(2, "getfile_send fseek error\n");
1536 faimdprintf(2, "faim: getfile_send: using %i byte blocks\n", bufsize);
1538 for(pos = 0; pos < fh->size; pos++) {
1539 bufpos = pos % bufsize;
1541 if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1542 if ( (i = write(conn->fd, buf, bufsize)) != bufsize ) {
1543 perror("faim: getfile_send: write1: ");
1544 faimdprintf(1, "faim: getfile_send: whoopsy, didn't write it all...\n");
1549 if( (buf[bufpos] = fgetc(tosend)) == EOF) {
1550 if(pos != fh->size) {
1551 printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1552 faimdprintf(1, "faim: getfile_send: hrm... apparent early EOF at pos 0x%lx of 0x%lx\n", pos, fh->size);
1561 if( (i = write(conn->fd, buf, bufpos+1)) != (bufpos+1)) {
1562 perror("faim: getfile_send: write2: ");
1563 faimdprintf(1, "faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1575 * int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
1576 * conn is the OFT connection to shove the data down,
1577 * tosend is the FILE * for the file to send
1578 * fh is the filled-in fh value
1579 * pos is the position to start at (at beginning should be 0, after 5
1580 * bytes are sent should be 5); -1 for "don't seek"
1581 * bufsize is the size of the chunk to send
1583 * returns -1 on error, new pos on success.
1587 * You don't really have to keep track of pos if you don't want
1588 * to. just always call with -1 for pos, and it'll use the one
1589 * contained within the FILE *.
1591 * if (pos + chunksize > fh->size), we only send as much data as we
1592 * can get (ie: up to fh->size.
1595 faim_export int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
1601 if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->type != AIM_CONN_SUBTYPE_OFT_GETFILE) {
1602 faimdprintf(1, "faim: getfile_send_chunk: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
1607 faimdprintf(1, "faim: getfile_send_chunk: file pointer isn't valid\n");
1612 faimdprintf(1, "faim: getfile_send_chunk: fh isn't valid\n");
1618 if(!(buf = (char *)calloc(1, bufsize))) {
1619 perror("faim: getfile_send_chunk: calloc:");
1620 faimdprintf(2, "faim: getfile_send_chunk calloc error\n");
1625 if( fseek(tosend, pos, SEEK_SET) == -1) {
1626 perror("faim: getfile_send_chunk: fseek:");
1627 faimdprintf(2, "faim: getfile_send_chunk fseek error\n");
1631 faimdprintf(2, "faim: getfile_send_chunk: using %i byte blocks\n", bufsize);
1633 for(bufpos = 0; pos < fh->size; bufpos++, pos++) {
1634 if( (buf[bufpos] = fgetc(tosend)) == EOF) {
1635 if(pos != fh->size) {
1636 faimdprintf(1, "faim: getfile_send_chunk: hrm... apparent early EOF at pos 0x%x of 0x%x\n", pos, fh->size);
1643 if( write(conn->fd, buf, bufpos+1) != (bufpos+1)) {
1644 faimdprintf(1, "faim: getfile_send_chunk cleanup: whoopsy, didn't write it all...\n");
1651 return (pos + bufpos);
1656 * free's tx_command_t's. if command is locked, doesn't free.
1657 * returns -1 on error (locked struct); 0 on success.
1658 * command is the command to free
1661 faim_internal int aim_tx_destroy(struct command_tx_struct *command)
1666 free(command->data);
1674 * aim_getfile_intitiate:
1675 * For those times when we want to open up the directim channel ourselves.
1676 * sess is your session,
1677 * conn is the BOS conn,
1678 * priv is a dummy priv value (we'll let it get filled in later) (if
1679 * you pass a NULL, we alloc one)
1680 * destsn is the SN to connect to.
1684 faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess,
1685 struct aim_conn_t *conn,
1686 struct aim_getfile_priv *priv,
1689 struct command_tx_struct *newpacket;
1690 struct aim_conn_t *newconn;
1692 struct aim_msgcookie_t *cookie;
1694 int curbyte, i, listenfd;
1697 struct hostent *hptr;
1698 struct utsname myname;
1701 char d[4]; /* XXX: IPv6. *cough* */
1707 if( (listenfd = aim_listenestablish(port)) == -1)
1714 if(uname(&myname) < 0)
1717 if( (hptr = gethostbyname(myname.nodename)) == NULL)
1720 memcpy(&d, hptr->h_addr_list[0], 4); /* XXX: this probably isn't quite kosher, but it works */
1722 aim_putcap(cap, 16, AIM_CAPS_IMIMAGE);
1725 * create the OSCAR packet
1728 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(destsn)+4+4+0x32)))
1731 newpacket->lock = 1; /* lock struct */
1734 curbyte += aim_putsnac(newpacket->data+curbyte,
1735 0x0004, 0x0006, 0x0000, sess->snac_nextid);
1738 * Generate a random message cookie
1739 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible.
1742 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 20));
1743 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1746 * grab all the data for cookie caching.
1748 cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t));
1750 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
1751 cookie->type = AIM_COOKIETYPE_OFTIM;
1754 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
1756 memcpy(priv->cookie, cookie, 8);
1757 memcpy(priv->sn, destsn, sizeof(priv->sn));
1759 cookie->data = priv;
1761 aim_cachecookie(sess, cookie); /* cache da cookie */
1766 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
1769 * Destination SN (prepended with byte length)
1771 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
1772 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
1774 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1775 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1780 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1781 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0032);
1784 * Flag data / ICBM Parameters?
1786 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1787 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1792 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
1797 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
1802 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
1803 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1804 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
1807 * 0003/0004: IP address
1810 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1811 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
1813 for(i = 0; i < 4; i++)
1814 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); /* already in network byte order */
1820 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1821 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1822 curbyte += aimutil_put16(newpacket->data+curbyte, port);
1825 * 000f/0000: umm.. dunno. Zigamorph[1]?
1826 * [1]: see esr's TNHD.
1829 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
1830 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1832 printf("curbyte: 0x%x\n",curbyte);
1834 newpacket->commandlen = curbyte;
1835 newpacket->lock = 0;
1837 aim_tx_enqueue(sess, newpacket);
1840 * allocate and set up our connection
1843 i = fcntl(listenfd, F_GETFL, 0);
1844 fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
1846 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
1848 perror("aim_newconn");
1849 aim_conn_kill(sess, &newconn);
1853 newconn->fd = listenfd;
1854 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
1855 newconn->priv = priv;
1856 printf("faim: listening (fd = %d, unconnected)\n", newconn->fd);
1859 * XXX We need some way of closing the listener socket after
1860 * n seconds of no connection. -- mid
1863 #ifdef USE_SNAC_FOR_IMS
1865 struct aim_snac_t snac;
1867 snac.id = sess->snac_nextid;
1868 snac.family = 0x0004;
1870 snac.flags = 0x0000;
1872 snac.data = malloc(strlen(destsn)+1);
1873 memcpy(snac.data, destsn, strlen(destsn)+1);
1875 aim_newsnac(sess, &snac);
1877 aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */