]> andersk Git - libfaim.git/blob - aim_ft.c
- Sun Feb 11 01:07:36 UTC 2001
[libfaim.git] / aim_ft.c
1 /*
2  * File transfer (OFT) and DirectIM.
3  */
4
5 #define FAIM_INTERNAL_FT
6 #define FAIM_INTERNAL
7 #include <faim/aim.h>
8
9 #ifndef _WIN32
10 #include <netdb.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <sys/utsname.h> /* for aim_directim_initiate */
14
15 #include <arpa/inet.h> /* for inet_ntoa */
16
17 #endif
18
19 /* TODO: 
20    o fix misspelling of receive 
21    o double-check mutex states on error returns 
22    o look for memory leaks.. there's going to be shitloads, i'm sure. 
23    o change listing FILE to listing filesend callback 
24    o change send_file and send_chunk over to buffers.
25 */
26
27 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr);
28  
29 /**
30  * aim_handlerendconnect - call this to accept OFT connections and set up the requisite structures
31  * @sess: the session
32  * @cur: the conn the incoming connection is on
33  *
34  * call this when you get an outstanding read on a conn with subtype
35  * AIM_CONN_SUBTYPE_RENDEZVOUS_OUT, it will close the current fd and
36  * call a callback with the new, accept'd fd to the other person. then we
37  * get to start the fun that is OFT!
38  */
39 faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_conn_t *cur)
40
41   int acceptfd = 0;
42   rxcallback_t userfunc;
43   struct sockaddr cliaddr;
44   socklen_t clilen = sizeof(cliaddr);
45   int ret = 0;
46   struct aim_conn_t *newconn;
47
48   if( (acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1)
49     return -1;
50   if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */
51     close(acceptfd);
52     aim_conn_close(cur);
53     return -1;
54   } 
55
56   /* clone it and then close the original */
57   /* XXX safe? maybe cur->priv should be NULLed after this */
58   if (!(newconn = aim_cloneconn(sess, cur))) {
59     close(acceptfd);
60     aim_conn_close(cur);
61     return -1;
62   }
63   aim_conn_close(cur);
64
65   newconn->type = AIM_CONN_TYPE_RENDEZVOUS;
66   newconn->fd = acceptfd;
67
68   switch(newconn->subtype) { 
69   case AIM_CONN_SUBTYPE_OFT_DIRECTIM: { 
70     struct aim_directim_priv *priv;
71
72     if(!newconn->priv)
73       newconn->priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
74     priv = (struct aim_directim_priv *)newconn->priv;
75
76     snprintf(priv->ip, sizeof(priv->ip), "%s:%u", 
77              inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), 
78              ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
79
80     /* should we really do this? seems like the client should decide. maybe clone the connection and keep the listener open. -- mid */
81     if ( (userfunc = aim_callhandler(newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE)))
82       ret = userfunc(sess, NULL, newconn);
83
84     break;
85   } 
86   case AIM_CONN_SUBTYPE_OFT_GETFILE: { 
87     struct aim_filetransfer_priv *priv;
88
89     if(!newconn->priv)
90       newconn->priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
91     priv = (struct aim_filetransfer_priv *)newconn->priv;
92
93     snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
94
95     if ( (userfunc = aim_callhandler(newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE)))
96       ret = userfunc(sess, NULL, newconn);
97
98     break;
99   } 
100   default: { 
101     faimdprintf(1,"Got a Connection on a listener that's not Rendezvous(??!) Killing conn.\n");
102     aim_conn_close(newconn);
103     break;
104   }
105   }
106
107   return ret;
108 }
109  
110 /*
111  * aim_send_im_direct - send IM client-to-client over established connection
112  * @sess: session to conn
113  * @conn: directim connection
114  * @msg: null-terminated string to send; if this is NULL, it will send a "typing" notice. 
115  *
116  */
117 faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg)
118
119
120   struct command_tx_struct *newpacket;
121   struct aim_directim_priv *priv = NULL;
122   int i;
123   if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !conn->priv) { 
124     faimdprintf(2,"faim: directim: invalid arguments\n");
125     return -1;
126   }
127
128   priv = (struct aim_directim_priv *)conn->priv;
129
130   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0001, conn, strlen(msg)))) { 
131     faimdprintf(2,"faim: directim: tx_new failed\n");
132     return -1;
133   } 
134
135   newpacket->lock = 1;
136
137   /* if msg is non-null, we'resending an IM, else a "typing" notice */
138   if(msg) { 
139     if (strlen(msg) >= MAXMSGLEN)
140       return -1;
141     newpacket->hdr.oft.hdr2len = 0x54;
142     if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { 
143       newpacket->lock = 0;
144       aim_tx_destroy(newpacket);
145       return -1;
146     } 
147   } else { 
148     newpacket->hdr.oft.hdr2len = 0x44;
149     if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { 
150       newpacket->lock = 0;
151       aim_tx_destroy(newpacket);
152       return -1;
153     } 
154   } 
155
156   memcpy(newpacket->hdr.oft.magic, "ODC2", 4);
157   newpacket->data = NULL;
158
159   i = 0;
160   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0006);
161   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
162   i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, (char *)priv->cookie, 8);
163   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
164   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
165   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
166   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
167   i += aimutil_put32(newpacket->hdr.oft.hdr2+i, 0x00000000);
168   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
169   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
170   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
171
172   /* flags -- 0x000e for "typing", 0x0000 for message */
173   if(msg)
174     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
175   else 
176     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000e);
177
178   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
179   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
180   i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->sn, strlen(sess->sn));
181   i = 52;
182
183   i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00);
184   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
185   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
186   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
187   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
188   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
189   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
190   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
191
192   /* end of hdr2 */
193
194   if(msg) { 
195     /* values grabbed from a dump */
196     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);
197     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);
198     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
199     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);
200     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);
201     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
202     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
203     i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
204     memcpy(newpacket->data, msg, strlen(msg));
205   } 
206   newpacket->lock = 0;
207   aim_tx_enqueue(sess, newpacket);
208   return 0;
209
210
211 /*
212  * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves.
213  * @sess: your session,
214  * @conn: the BOS conn,
215  * @priv: a dummy priv value (we'll let it get filled in later) (if you pass a NULL, we alloc one)
216  * @destsn: the SN to connect to.
217  *
218  */
219 faim_export struct aim_conn_t *aim_directim_initiate(struct aim_session_t *sess, 
220                                                      struct aim_conn_t *conn, 
221                                                      struct aim_directim_priv *priv, 
222                                                      char *destsn)
223
224
225   struct command_tx_struct *newpacket;
226   struct aim_conn_t *newconn;
227   struct aim_msgcookie_t *cookie;
228   int curbyte, i, listenfd;
229   short port = 4443;
230   struct hostent *hptr;
231   char localhost[129];
232   unsigned char cap[16];
233   char d[4]; /* IPv6 is a bit bigger... */
234
235   /* XXX: TLVlist-ize this */
236  
237   /* Open our socket */
238
239   if( (listenfd = aim_listenestablish(port)) == -1)
240     return NULL;
241
242   /* get our local IP */
243   /* XXX if available, use getaddrinfo() */
244   /* XXX allow client to specify which IP to use for multihomed boxes */
245   if(gethostname(localhost, 128) < 0)
246     return NULL;
247   if( (hptr = gethostbyname(localhost)) == NULL)
248     return NULL;
249   memcpy(&d, hptr->h_addr_list[0], 4);
250
251   /* XXX: this probably isn't quite kosher, but it works */
252   aim_putcap(cap, 16, AIM_CAPS_IMIMAGE);
253
254   /* create the OSCAR packet */
255
256   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(destsn)+4+4+0x32)))
257     return NULL;
258   newpacket->lock = 1;
259
260   curbyte = 0;
261   curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
262
263   /* Generate a random message cookie */
264   /* This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
265   for (i=0; i<7; i++) 
266     curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) rand() % 20));
267
268   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
269
270   /* grab all the data for cookie caching */
271   cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t));
272   memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
273   cookie->type = AIM_COOKIETYPE_OFTIM;
274   priv = cookie->data;
275
276   if(!priv)
277     priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
278  
279   memcpy(priv->cookie, cookie, 8);
280   memcpy(priv->sn, destsn, sizeof(priv->sn));
281   cookie->data = priv;
282   aim_cachecookie(sess, cookie);
283
284   /* Channel ID */
285   curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
286
287   /* Destination SN (prepended with byte length)*/
288   curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
289   curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
290   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
291   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
292
293   /* enTLV start */
294   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
295   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0032);
296
297   /* Flag data / ICBM Parameters  */
298   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
299   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
300
301   /* Cookie  */
302   curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
303
304   /*Capability String  */
305   curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
306
307   /* 000a/0002 : 0001  */
308   curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
309   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
310   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
311
312   /* 0003/0004: IP address  */
313   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
314   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
315   for(i = 0;i < 4; i++) 
316     curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
317  
318   /* 0005/0002: Port */
319   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
320   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
321   curbyte += aimutil_put16(newpacket->data+curbyte, port);
322
323   /* 000f/0000: ?? */
324   curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
325   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
326   newpacket->commandlen = curbyte;
327   newpacket->lock = 0;
328   aim_tx_enqueue(sess, newpacket);
329
330
331   /* XXX switch to aim_cloneconn()? */
332   if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL)))
333     return NULL;
334
335   newconn->fd = listenfd;
336   newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
337   newconn->priv = priv;
338   newconn->lastactivity = time(NULL);
339
340   faimdprintf(2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
341
342   return newconn;
343
344
345 /*
346  * unsigned long aim_oft_listener_clean - close up old listeners
347  * @sess: session to clean up in
348  * @age: maximum age in seconds 
349  *
350  * returns number closed, -1 on error.
351  */
352 faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time_t age) 
353
354   struct aim_conn_t *cur;
355   time_t now;
356   unsigned int hit = 0;
357   
358   if(!sess)
359     return -1;
360   now = time(NULL);
361   faim_mutex_lock(&sess->connlistlock);
362   for(cur = sess->connlist;cur; cur = cur->next)
363     if(cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 
364       faim_mutex_lock(&cur->active);
365       if (cur->lastactivity < (now - age) ) { 
366         faim_mutex_unlock(&cur->active);
367         aim_conn_close(cur);
368         hit++;
369       } else 
370         faim_mutex_unlock(&cur->active);
371     } 
372   faim_mutex_unlock(&sess->connlistlock);
373   return hit;
374
375
376 /*
377  * aim_directim_connect - connect to buddy for directim
378  * @sess: the session to append the conn to,
379  * @conn: the BOS connection,
380  * @priv: the filled-in priv data structure for the connection 
381  *
382  * returns conn if connected, %NULL on error
383  */
384 faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_directim_priv *priv)
385
386   struct aim_conn_t *newconn = NULL;
387
388   if(!sess || !conn || !priv)
389     return NULL;
390   
391   /* XXX verify that non-blocking connects actually work */
392   newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, priv->ip);
393   if (!newconn || (newconn->fd == -1)) { 
394     faimdprintf(2, "could not connect to %s\n", priv->ip);
395     perror("aim_newconn");
396     /* Its safe to call conn_kill here since we created the connection */
397     if (newconn)
398       aim_conn_kill(sess, &newconn);
399     return NULL;
400   }
401
402   newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
403   newconn->priv = priv;
404   faimdprintf(2, "faim: connected to peer (fd = %d)\n", newconn->fd);
405
406   return newconn;
407
408
409 /*
410  * aim_directim_getconn - find a directim conn for buddy name
411  * @sess: your session,
412  * @name: the name to get,  
413  *
414  * returns conn for directim with name, %NULL if none found. 
415  *
416  */
417 faim_export struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, const char *name)
418 {
419   struct aim_conn_t *cur;
420   struct aim_directim_priv *priv;
421
422   if(!sess || !name)
423     return NULL;
424
425   faim_mutex_lock(&sess->connlistlock);
426
427   for (cur = sess->connlist; cur; cur = cur->next) {
428     if (cur->type != AIM_CONN_TYPE_RENDEZVOUS || cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)
429       continue;
430     priv = cur->priv;
431     if (aim_sncmp(priv->sn, name) == 0)
432       break;
433   } faim_mutex_unlock(&sess->connlistlock);
434   return cur;
435
436
437 /*
438  * aim_accepttransfer - accept a file transfer request
439  * @sess: the session,
440  * @conn: the BOS conn for the CAP reply
441  * @sn: the screenname to send it to,
442  * @cookie: the cookie used
443  * @ip: the ip to connect to
444  * @listingfiles: number of files to share
445  * @listingtotsize: total size of shared files
446  * @listingsize: length of the listing file(buffer)
447  * @listingchecksum: checksum of the listing
448  * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)  
449  *
450  * returns connection or %NULL on error.
451  */
452 faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, 
453                                                   struct aim_conn_t *conn, 
454                                                   char *sn, char *cookie, 
455                                                   char *ip, 
456                                                   unsigned short listingfiles, 
457                                                   unsigned short listingtotsize, 
458                                                   unsigned short listingsize, 
459                                                   unsigned int listingchecksum, 
460                                                   unsigned short rendid)
461
462   struct command_tx_struct *newpacket, *newoft;
463   struct aim_conn_t *newconn;
464   struct aim_fileheader_t *fh;
465   struct aim_filetransfer_priv *priv;
466   struct aim_msgcookie_t *cachedcook;
467   int curbyte, i;
468
469   if(!sess || !conn || !sn || !cookie || !ip)
470     return NULL;
471
472   if(rendid == AIM_CAPS_GETFILE)  {
473     newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip);
474     newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
475
476     if (!newconn || (newconn->fd == -1)) {
477       perror("aim_newconn");
478       faimdprintf(2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
479       /* Its safe to call conn_kill here since we created the connection */
480       if (newconn)
481         aim_conn_kill(sess, &newconn);
482       return NULL;
483     } else {
484       priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
485
486       memcpy(priv->cookie, cookie, 8);
487       priv->state = 0;
488       strncpy(priv->sn, sn, MAXSNLEN);
489       strncpy(priv->ip, ip, sizeof(priv->ip));
490       newconn->priv = (void *)priv;
491
492       faimdprintf(2, "faim: connected to peer (fd = %d)\n", newconn->fd);
493     }
494
495     if(rendid == AIM_CAPS_GETFILE) { 
496       faimdprintf(2, "faim: getfile request accept\n");
497
498       if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x1108, newconn, 0))) { 
499         faimdprintf(2, "faim: aim_accepttransfer: tx_new OFT failed\n");
500         /* Its safe to call conn_kill here since we created the connection */
501         aim_conn_kill(sess, &newconn);
502         return NULL;
503       } 
504
505       newoft->lock = 1;
506       memcpy(newoft->hdr.oft.magic, "OFT2", 4);
507       newoft->hdr.oft.hdr2len = 0x100 - 8;
508
509       if(!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
510         return NULL;
511
512       fh->encrypt = 0x0000;
513       fh->compress = 0x0000;
514       fh->totfiles = listingfiles;
515       fh->filesleft = listingfiles;      /* is this right -- total parts and parts left?*/
516       fh->totparts = 0x0001;
517       fh->partsleft = 0x0001;
518       fh->totsize = listingtotsize;
519       fh->size = listingsize;      /* ls -l listing.txt */
520       fh->modtime = (int)time(NULL); /* we'll go with current time for now */
521       fh->checksum = listingchecksum;
522       fh->rfcsum = 0x00000000;
523       fh->rfsize = 0x00000000;
524       fh->cretime = 0x00000000;
525       fh->rfcsum = 0x00000000;
526       fh->nrecvd = 0x00000000;
527       fh->recvcsum = 0x00000000;
528       memset(fh->idstring, 0, sizeof(fh->idstring));
529       memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
530       fh->flags = 0x02;
531       fh->lnameoffset = 0x1a;
532       fh->lsizeoffset = 0x10;
533       memset(fh->dummy, 0, sizeof(fh->dummy));
534       memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
535
536       /* we need to figure out these encodings for filenames */
537       fh->nencode = 0x0000;
538       fh->nlanguage = 0x0000;
539       memset(fh->name, 0, sizeof(fh->name));
540       memcpy(fh->name, "listing.txt", sizeof(fh->name));
541
542       if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 
543         newoft->lock = 0;
544         aim_tx_destroy(newoft);
545         return NULL;
546       } 
547
548       memcpy(fh->bcookie, cookie, 8);
549
550       if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
551         printf("eek, bh fail!\n");
552
553       newoft->lock = 0;
554       aim_tx_enqueue(sess, newoft);
555    
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         /* more cleanup */
559         return NULL;
560       }
561
562       memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
563       memcpy(cachedcook->cookie, cookie, 8);
564
565       cachedcook->type = AIM_COOKIETYPE_OFTGET;
566       cachedcook->data = (void *)priv;
567
568       if (aim_cachecookie(sess, cachedcook) != 0)
569         faimdprintf(1, "faim: ERROR caching message cookie\n");
570
571       free(fh);
572     } 
573  
574     /* OSCAR CAP accept packet */
575     
576     if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sn)+4+2+8+16)))
577       return NULL;
578
579     newpacket->lock = 1;
580     curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
581
582     for (i = 0;  i < 8;  i++)
583       curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
584
585     curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
586     curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn));
587     curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn));
588     curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
589     curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a);
590     curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept*/);
591
592     for (i = 0;i < 8; i++) 
593       curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
594
595     curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid);
596     newpacket->lock = 0;
597     aim_tx_enqueue(sess, newpacket);
598
599     return newconn;
600   } return NULL;
601 }
602
603 /*
604  * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
605  *  @file is an opened listing file
606  * 
607  * returns a pointer to the filled-in fileheader_t
608  *
609  * currently omits checksum. we'll fix this when AOL breaks us, i
610  * guess.
611  *
612  */
613
614 faim_export struct aim_fileheader_t *aim_getlisting(FILE *file) 
615 {
616   struct aim_fileheader_t *fh;
617   u_long totsize = 0, size = 0, checksum = 0xffff0000;
618   short totfiles = 0;
619   char *linebuf, sizebuf[9];
620   
621   int linelength = 1024;
622
623   /* XXX: if we have a line longer than 1024chars, God help us. */
624   if( (linebuf = (char *)calloc(1, linelength)) == NULL ) {
625     faimdprintf(2, "linebuf calloc failed\n");
626     return NULL;
627   }  
628
629   if(fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
630     perror("getlisting END1 fseek:");
631     faimdprintf(2, "getlising fseek END1 error\n");
632   }
633
634   if(fgetpos(file, &size) == -1) {
635     perror("getlisting END1 getpos:");
636     faimdprintf(2, "getlising getpos END1 error\n");
637   }
638
639   if(fseek(file, 0, SEEK_SET) != 0) {
640     perror("getlesting fseek(SET):");
641     faimdprintf(2, "faim: getlisting: couldn't seek to beginning of listing file\n");
642   }
643
644   memset(linebuf, 0, linelength);
645
646   size = 0;
647
648   while(fgets(linebuf,  linelength, file)) {
649     totfiles++;
650     memset(sizebuf, 0, 9);
651
652     size += strlen(linebuf);
653     
654     if(strlen(linebuf) < 23) {
655       faimdprintf(2, "line \"%s\" too short. skipping\n", linebuf);
656       continue;
657     }
658     if(linebuf[strlen(linebuf)-1] != '\n') {
659       faimdprintf(2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
660     }
661
662     memcpy(sizebuf, linebuf+17, 8);
663
664     totsize += strtol(sizebuf, NULL, 10);
665     memset(linebuf, 0, linelength);
666   }   
667
668   if(fseek(file, 0, SEEK_SET) == -1) {
669     perror("getlisting END2 fseek:");
670     faimdprintf(2, "getlising fseek END2 error\n");
671   }  
672
673   free(linebuf);
674
675   /* we're going to ignore checksumming the data for now -- that
676    * requires walking the whole listing.txt. it should probably be
677    * done at register time and cached, but, eh. */  
678
679   if(!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
680     return NULL;
681
682   printf( "faim: OFT: getlisting: totfiles: %u, totsize: %lu, size: %lu\n", totfiles, totsize, size);
683
684   fh->encrypt     = 0x0000;
685   fh->compress    = 0x0000; 
686   fh->totfiles    = totfiles;
687   fh->filesleft   = totfiles; /* is this right ?*/
688   fh->totparts    = 0x0001;
689   fh->partsleft   = 0x0001;
690   fh->totsize     = totsize;
691   fh->size        = size; /* ls -l listing.txt */
692   fh->modtime     = (int)time(NULL); /* we'll go with current time for now */
693   fh->checksum    = checksum; /* XXX: checksum ! */
694   fh->rfcsum      = 0x00000000;
695   fh->rfsize      = 0x00000000;
696   fh->cretime     = 0x00000000;
697   fh->rfcsum      = 0x00000000;
698   fh->nrecvd      = 0x00000000;
699   fh->recvcsum    = 0x00000000;
700
701   /*  memset(fh->idstring, 0, sizeof(fh->idstring)); */
702   memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
703   memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
704
705   fh->flags       = 0x02;
706   fh->lnameoffset = 0x1a;
707   fh->lsizeoffset = 0x10;
708
709   /*  memset(fh->dummy, 0, sizeof(fh->dummy)); */
710   memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
711
712   fh->nencode     = 0x0000; /* we need to figure out these encodings for filenames */
713   fh->nlanguage   = 0x0000;
714
715   /*  memset(fh->name, 0, sizeof(fh->name)); */
716   memcpy(fh->name, "listing.txt", sizeof(fh->name));
717   memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
718
719   faimdprintf(2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
720   return fh;
721 }
722
723 /*
724  * aim_listenestablish - create a listening socket on a port.
725  * @portnum: the port number to bind to.  
726  *
727  * you need to call accept() when it's connected. returns your fd 
728  *
729  */
730 faim_internal int aim_listenestablish(u_short portnum)
731 {
732 #if defined(__linux__)
733   /* XXX what other OS's support getaddrinfo? */
734   int listenfd;
735   const int on = 1;
736   struct addrinfo hints, *res, *ressave;
737   char serv[5];
738   sprintf(serv, "%d", portnum);
739   memset(&hints, 0, sizeof(struct addrinfo));
740   hints.ai_flags = AI_PASSIVE;
741   hints.ai_family = AF_UNSPEC;
742   hints.ai_socktype = SOCK_STREAM;
743   if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) {
744     perror("getaddrinfo");
745     return -1;
746   } 
747   ressave = res;
748   do { 
749     listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);    
750     if (listenfd < 0)
751       continue;
752     setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
753     if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
754       break;
755     /* success */
756     close(listenfd);
757   } while ( (res = res->ai_next) );
758
759   if (!res)
760     return -1;
761   
762   if (listen(listenfd, 1024)!=0) { 
763     perror("listen");
764     return -1;
765   } 
766
767   freeaddrinfo(ressave);
768   return listenfd;
769 #else
770   int listenfd;
771   const int on = 1;
772   struct sockaddr_in sockin;
773   if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
774     perror("socket(listenfd)");
775     return -1;
776   }
777
778   if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) != 0)) {
779     perror("setsockopt(listenfd)");
780     close(listenfd);
781     return -1;
782   } 
783   
784   memset(&sockin, 0, sizeof(struct sockaddr_in));
785   sockin.sin_family = AF_INET;
786   sockin.sin_port = htons(portnum);
787
788   if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
789     perror("bind(listenfd)");
790     close(listenfd);
791     return -1;
792   }
793   if (listen(listenfd, 4) != 0) {
794     perror("listen(listenfd)");
795     close(listenfd);
796     return -1;
797   }
798   return listenfd;
799 #endif
800
801 /*
802  * aim_get_command_rendezvous - OFT equivalent of aim_get_command
803  * @sess: session to work on
804  * @conn: conn to pull data from 
805  *
806  * this reads and handles data from conn->fd. currently a little rough
807  * around the edges
808  */
809 faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
810 {
811   unsigned char hdrbuf1[6];
812   unsigned char *hdr = NULL;
813   int hdrlen, hdrtype;
814   int flags = 0;
815   rxcallback_t userfunc = NULL;
816   
817   memset(hdrbuf1, 0, sizeof(hdrbuf1));
818   faim_mutex_lock(&conn->active);
819   
820  /* gets locked down for the entirety */
821
822   if(conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE ) { 
823     struct aim_filetransfer_priv *ft;
824     ft = conn->priv;
825     if(ft->state == 2) { 
826       /* waiting on listing data */
827       int ret = 0;
828       char *listing;
829       struct command_tx_struct *newoft;
830       if(!(listing = malloc(ft->fh.size))) {
831         faim_mutex_unlock(&conn->active);
832         return -1;
833       }
834
835      ft->state = 0;
836      if(aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size)        
837        faimdprintf(2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size);
838
839      if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x120b, conn, 0))) {
840        faimdprintf(2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n");
841        faim_mutex_unlock(&conn->active);
842        free(listing);
843        aim_conn_close(conn);
844        return -1;
845      }
846
847      newoft->lock = 1;
848
849      memcpy(newoft->hdr.oft.magic, "OFT2", 4);
850      newoft->hdr.oft.hdr2len = 0x100 - 8;
851      
852      /* this is icky. */
853      ft->fh.nrecvd = ft->fh.size;
854      ft->fh.recvcsum = ft->fh.checksum;
855      ft->fh.flags = 0;
856      
857      if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
858        newoft->lock = 0;
859        aim_tx_destroy(newoft);
860        free(listing);
861        faim_mutex_unlock(&conn->active);
862        return -1;
863      }
864      
865      if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh))))
866        printf("eek! bh fail listing\n");
867
868      /* send the 120b   */
869      newoft->lock = 0;
870      aim_tx_enqueue(sess, newoft);
871      if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) )
872        ret = userfunc(sess, NULL, conn, ft, listing);
873      
874      faim_mutex_unlock(&conn->active);
875      free(listing);
876      return ret;
877    }
878    if(ft->state == 3) { 
879      /* waiting on file data */
880      if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECIEVE)) )  {
881        faim_mutex_unlock(&conn->active);
882        return userfunc(sess, NULL, conn, ft);
883      }
884      faim_mutex_unlock(&conn->active);
885      return 0;
886    }
887  }
888  
889  if ( (hdrlen = aim_recv(conn->fd, hdrbuf1, 6)) < 6) {
890    faimdprintf(2, "faim: rend: read error (fd: %i) %02x%02x%02x%02x%02x%02x (%i)\n", 
891                conn->fd, hdrbuf1[0],hdrbuf1[1],hdrbuf1[2],hdrbuf1[3],hdrbuf1[4],hdrbuf1[5],hdrlen);
892    faim_mutex_unlock(&conn->active);
893    if(hdrlen < 0)
894      perror("read");
895    else { /* disconnected */
896      switch(conn->subtype) { 
897      case AIM_CONN_SUBTYPE_OFT_DIRECTIM: { 
898        /* XXX: clean up cookies here ? */
899        struct aim_directim_priv *priv = NULL;
900        if(!(priv = (struct aim_directim_priv *)conn->priv) )
901          return -1;
902        
903        aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTIM);
904        if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT)) ) {
905          aim_conn_close(conn);
906          return userfunc(sess, NULL, conn, priv->sn);
907        }
908        break;
909      } 
910      case AIM_CONN_SUBTYPE_OFT_GETFILE: {
911        struct aim_filetransfer_priv *priv;
912        if(!(priv = (struct aim_filetransfer_priv *)conn->priv))
913          return -1;
914        aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET);
915        if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT)) ) {
916          aim_conn_close(conn);
917          return userfunc(sess, NULL, conn, priv->sn);
918        }
919        break;
920      }
921      case AIM_CONN_SUBTYPE_OFT_SENDFILE: {
922        struct aim_filetransfer_priv *priv;
923        if(!(priv = (struct aim_filetransfer_priv *)conn->priv))
924          return -1;
925        aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND);
926        if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEDISCONNECT)) ) { 
927          aim_conn_close(conn);
928          return userfunc(sess, NULL, conn, priv->sn);
929        }
930        break;
931      } 
932      }
933
934      aim_conn_close(conn);
935      return -1;
936    }
937  }
938
939  hdrlen = aimutil_get16(hdrbuf1+4);
940  hdrlen -= 6;
941
942  if (!(hdr = malloc(hdrlen))) { 
943    faim_mutex_unlock(&conn->active);
944    return -1;
945  }
946
947  if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) {
948    perror("read");
949    faimdprintf(2,"faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen);
950    free(hdr);
951    faim_mutex_unlock(&conn->active);
952    aim_conn_close(conn);
953    return -1;
954    }
955  hdrtype = aimutil_get16(hdr);
956  printf("\tgot 0x%04x", hdrtype);
957  switch (hdrtype) {
958  case 0x0001: {    /* directim */
959    int payloadlength = 0;
960    char *snptr = NULL;
961    struct aim_directim_priv *priv;
962    int i;
963
964    if(!(priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)))) {
965      faim_mutex_unlock(&conn->active);
966      return -1;
967    }
968    
969    payloadlength = aimutil_get32(hdr+22);
970    flags = aimutil_get16(hdr+32);
971    snptr = (char *)hdr+38;
972    strncpy(priv->sn, snptr, MAXSNLEN);
973
974    faimdprintf(2, "faim: OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
975
976    if (flags == 0x000e) { 
977      faim_mutex_unlock(&conn->active);
978      if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)) )
979        return userfunc(sess, NULL, snptr);
980    } else
981      if ((flags == 0x0000) && payloadlength) { 
982        unsigned char *msg;
983        if(! (msg = calloc(1, payloadlength+1)) ) {
984          faim_mutex_unlock(&conn->active);
985          return -1;
986        }
987        if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) {
988          perror("read");
989          printf("faim: rend: read3 error\n");
990          free(msg);
991          faim_mutex_unlock(&conn->active);
992          aim_conn_close(conn);
993          return -1;
994        }
995        faim_mutex_unlock(&conn->active);
996        msg[payloadlength] = 0x00;
997        faimdprintf(2, "faim: directim: %s/%04x/%04x/%s\n", snptr, payloadlength, flags, msg);
998        if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
999          i = userfunc(sess, NULL, conn, snptr, msg);
1000        free(msg);
1001        return i;
1002      }
1003    break;
1004  }
1005  case 0x1108: { /* getfile listing.txt incoming tx->rx */
1006    struct aim_filetransfer_priv *ft;
1007    struct aim_fileheader_t *fh;
1008    struct aim_msgcookie_t *cook;
1009    struct command_tx_struct *newoft;
1010    faimdprintf(2,"faim: rend: fileget 0x1108\n");
1011    fh = aim_oft_getfh(hdr);
1012    faim_mutex_unlock(&conn->active);
1013    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1014      faim_mutex_unlock(&conn->active);
1015      free(fh);
1016      return -1;
1017    }
1018    ft = cook->data;
1019    ft->state = 2;
1020
1021    /* we're waaaaiiiting.. for listing.txt */
1022
1023    memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1024    aim_cachecookie(sess, cook);
1025    free(fh);
1026
1027    if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x1209, conn, 0))) {
1028      aim_conn_close(conn);
1029      return -1;
1030    }
1031
1032    memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1033    newoft->hdr.oft.hdr2len = 0x100 - 8;
1034
1035    if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1036      newoft->lock = 0;
1037      aim_tx_destroy(newoft);
1038      return -1;
1039    }
1040
1041    if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1042      newoft->lock = 0;
1043      aim_tx_destroy(newoft);
1044      return -1;
1045    }
1046
1047    newoft->lock = 0;
1048    aim_tx_enqueue(sess, newoft);
1049    break;
1050    
1051  } 
1052  case 0x1209: { /* get file listing ack rx->tx */
1053    struct aim_filetransfer_priv *ft;
1054    struct aim_fileheader_t *fh;
1055    struct aim_msgcookie_t *cook;
1056    int ret;
1057
1058    fh = aim_oft_getfh(hdr);
1059    faim_mutex_unlock(&conn->active);
1060
1061    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
1062      faimdprintf(2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", 
1063                  AIM_COOKIETYPE_OFTGET, fh->bcookie);
1064
1065    ft = cook->data;   
1066
1067    if(ft->fh.size != fh->size)
1068      faimdprintf(2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", 
1069                  ft->fh.size, fh->size);
1070
1071    
1072    if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ)))
1073      ret = userfunc(sess, NULL, conn, fh);   
1074
1075    faimdprintf(2, "faim: get_command_rendezvous: hit end of 1209\n");
1076
1077    free(fh);
1078
1079    return ret;
1080
1081    break;
1082  }
1083  case 0x120b: {    /* getfile listing.txt rx confirm */
1084    struct aim_filetransfer_priv *ft;
1085    struct aim_msgcookie_t *cook;
1086    struct aim_fileheader_t *fh;
1087
1088    fh = aim_oft_getfh(hdr);
1089    faim_mutex_unlock(&conn->active);
1090
1091    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))     {
1092      free(fh);
1093      return -1;
1094    }
1095
1096    ft = cook->data;
1097    aim_cachecookie(sess, cook);
1098    free(fh);
1099
1100    /* XXX: call listing.txt rx confirm */
1101    break;
1102  }
1103  case 0x120c: { /* getfile file request */
1104    struct aim_filetransfer_priv *ft;
1105    struct aim_msgcookie_t *cook;
1106    struct aim_fileheader_t *fh;
1107    struct command_tx_struct *newoft;
1108    int i;
1109
1110    fh = aim_oft_getfh(hdr);
1111    faim_mutex_unlock(&conn->active);
1112
1113    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
1114      return -1;
1115
1116    ft = cook->data;
1117    memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1118    free(fh);
1119
1120    aim_cachecookie(sess, cook);
1121
1122    faimdprintf(2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name);
1123
1124    if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) )
1125      i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie);
1126
1127    if(i < 0)
1128      return -1;
1129
1130    if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0101, conn, 0))) {
1131      faimdprintf(2, "faim: send_final_transfer: tx_new OFT failed\n");
1132      return -1;
1133    }
1134
1135    newoft->lock = 1;
1136    memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1137    newoft->hdr.oft.hdr2len = 0x100 - 8;
1138
1139    if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1140      newoft->lock = 0;
1141      aim_tx_destroy(newoft);
1142      return -1;
1143    } 
1144
1145    /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */
1146    ft->fh.nrecvd = 0;
1147    ft->fh.recvcsum = 0;
1148    ft->fh.flags = 0x20;
1149
1150    aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1151
1152    newoft->lock = 0;
1153    aim_tx_enqueue(sess, newoft);
1154
1155    faimdprintf(2, "faim: OFT: OFT file header enqueued.\n");
1156
1157    return i;
1158
1159    break;
1160  }
1161  case 0x0101: {    /* getfile: sending data  */
1162    struct aim_fileheader_t *fh;
1163    struct aim_filetransfer_priv *ft;
1164    struct aim_msgcookie_t *cook;
1165    struct command_tx_struct *newoft;
1166
1167    fh = aim_oft_getfh(hdr);
1168    faim_mutex_unlock(&conn->active);
1169
1170    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1171      printf("fucking no cookie\n");
1172      free(fh);
1173      return -1;
1174    }
1175    free(fh);
1176
1177    ft = cook->data;
1178
1179    ft->state = 3;
1180    aim_cachecookie(sess, cook);
1181
1182    faimdprintf(2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name);
1183
1184    if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0202, conn, 0))) {
1185      aim_conn_close(conn);
1186      faimdprintf(2, "faim: send_final_transfer: tx_new OFT failed\n");
1187      return -1;
1188    }
1189
1190    newoft->lock = 1;
1191    memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1192
1193    newoft->hdr.oft.hdr2len = 0x100 - 8;
1194
1195    if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1196      newoft->lock = 0;
1197      aim_tx_destroy(newoft);
1198      return -1;
1199    }
1200
1201    aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1202
1203    newoft->lock = 0;
1204    aim_tx_enqueue(sess, newoft);
1205
1206    faimdprintf(2, "faim: OFT: OFT 0x0202 enqueued.\n");
1207
1208    if( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL)
1209      return 1;
1210
1211    break;
1212  }
1213  case 0x0202: {    /* get file: ready to recieve data */
1214    struct aim_fileheader_t *fh;
1215    struct aim_filetransfer_priv *ft;
1216    struct aim_msgcookie_t *cook;
1217    int ret = 1;
1218
1219    fh = aim_oft_getfh(hdr);
1220    faim_mutex_unlock(&conn->active);
1221
1222    if(!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1223      free(fh);
1224      return -1;
1225    }
1226    
1227    ft = cook->data;
1228
1229    faimdprintf(2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n");
1230
1231    if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) )
1232      ret = userfunc(sess, NULL, conn, fh);
1233
1234    free(fh);
1235
1236    return ret;
1237    break;
1238  }
1239  case 0x0204: {    /* get file: finished. close it up */
1240    int i;
1241    struct aim_fileheader_t *fh;
1242
1243    fh = aim_oft_getfh(hdr);
1244    faim_mutex_unlock(&conn->active);
1245
1246    faimdprintf(2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n");
1247
1248    if ( (userfunc = aim_callhandler(conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) )
1249      i = userfunc(sess, NULL, conn, fh);
1250    else 
1251      i = 1;
1252
1253    if(conn)
1254      aim_conn_close(conn);
1255
1256    free(fh);
1257
1258    return i;
1259    break;
1260  }
1261  default: { 
1262         faimdprintf(2,"faim: OFT frame: uknown type %04x\n", hdrtype);
1263         faim_mutex_unlock(&conn->active);
1264         break;
1265  } 
1266  } /* switch */
1267  free(hdr);
1268  return 0;
1269 }
1270  
1271 /*
1272  * aim_oft_getfh - extracts a aim_fileheader_t from buffer hdr.
1273  * @hdr: buffer to extract header from  
1274  *
1275  * returns pointer to struct on success; %NULL on error.  
1276  *
1277  */
1278 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) 
1279 {
1280   struct aim_fileheader_t *fh;
1281   int i, j;
1282   if(!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
1283     return NULL;
1284   
1285   /* [0] and [1] are the type. we can ignore those here. */
1286   i = 2;
1287   for(j = 0; j < 8; j++, i++)
1288     fh->bcookie[j] = hdr[i];
1289   fh->encrypt = aimutil_get16(hdr+i);
1290   i += 2;
1291   fh->compress = aimutil_get16(hdr+i);
1292   i += 2;
1293   fh->totfiles = aimutil_get16(hdr+i);
1294   i += 2;
1295   fh->filesleft = aimutil_get16(hdr+i);
1296   i += 2;
1297   fh->totparts = aimutil_get16(hdr+i);
1298   i += 2;
1299   fh->partsleft = aimutil_get16(hdr+i);
1300   i += 2;
1301   fh->totsize = aimutil_get32(hdr+i);
1302   i += 4;
1303   fh->size = aimutil_get32(hdr+i);
1304   i += 4;
1305   fh->modtime = aimutil_get32(hdr+i);
1306   i += 4;
1307   fh->checksum = aimutil_get32(hdr+i);
1308   i += 4;
1309   fh->rfrcsum = aimutil_get32(hdr+i);
1310   i += 4;
1311   fh->rfsize = aimutil_get32(hdr+i);
1312   i += 4;
1313   fh->cretime = aimutil_get32(hdr+i);
1314   i += 4;
1315   fh->rfcsum = aimutil_get32(hdr+i);
1316   i += 4;
1317   fh->nrecvd = aimutil_get32(hdr+i);
1318   i += 4;
1319   fh->recvcsum = aimutil_get32(hdr+i);
1320   i += 4;
1321   memcpy(fh->idstring, hdr+i, 32);
1322   i += 32;
1323   fh->flags = aimutil_get8(hdr+i);
1324   i += 1;
1325   fh->lnameoffset = aimutil_get8(hdr+i);
1326   i += 1;
1327   fh->lsizeoffset = aimutil_get8(hdr+i);
1328   i += 1;
1329   memcpy(fh->dummy, hdr+i, 69);
1330   i += 69;
1331   memcpy(fh->macfileinfo, hdr+i, 16);
1332   i += 16;
1333   fh->nencode = aimutil_get16(hdr+i);
1334   i += 2;
1335   fh->nlanguage = aimutil_get16(hdr+i);
1336   i += 2;
1337   memcpy(fh->name, hdr+i, 64);
1338   i += 64;
1339   return fh;
1340
1341
1342 /*
1343  * aim_oft_checksum - calculate oft checksum of buffer
1344  * @buffer: buffer of data to checksum
1345  * @bufsize: size of buffer
1346  * @checksum: pointer to integer to place result in (pointer!) 
1347  
1348  *
1349  * note that checksum is a pointer. checksum should be filled with
1350  * 0xFFFF0000 for each new file; you can have this checksum chunks of
1351  * files in series if you just call it repeatedly in a for(; ; ) loop
1352  * and don't reset the checksum between each call. and you thought we
1353  * didn't care about you and your pathetic client's meomry footprint
1354  * ;^) 
1355  *
1356  */
1357 faim_export int aim_oft_checksum(char *buffer, int bufsize, int *checksum){ short check0, check1;
1358  int i;
1359  check0 = ((*checksum & 0xFF000000) >> 16);
1360  check1 = ((*checksum & 0x00ff0000) >> 16);
1361  for(i = 0; i < bufsize; i++) {
1362    if(i % 2) { /* use check1 -- second byte */
1363      if ( (short)buffer[i] > check1 ) { /* wrapping */
1364        check1 += 0x100;  /* this is a cheap way to wrap */
1365
1366        /* if we're wrapping, decrement the other one */
1367        /* XXX: check this corner case */
1368        if(check0 == 0) 
1369          check0 = 0x00ff;
1370        else 
1371          check0--;
1372      } 
1373      check1 -= buffer[i];
1374    } else { /* use check0 -- first byte  */
1375      if ( (short)buffer[i] > check0 ) { /* wrapping */
1376        check0 += 0x100;       /* this is a cheap way to wrap */
1377   
1378        /* if we're wrapping, decrement the other one */
1379          /* XXX: check this corner case */
1380        if(check1 == 0) 
1381          check1 = 0x00ff;
1382        else 
1383          check1--;
1384      } 
1385      check0 -= buffer[i];
1386      } 
1387  }
1388
1389  if(check0 > 0xff || check1 > 0xff)  { 
1390      /* they shouldn't be able to do this. error! */
1391    faimdprintf(2, "check0 or check1 is too high: 0x%04x, 0x%04x\n", check0, check1);
1392      return -1;
1393  } 
1394
1395  /* grab just the lowest byte; this should be clean, but just in
1396     case */
1397  check0 &= 0xff;
1398  check1 &= 0xff;
1399
1400  *checksum = ((check0 * 0x1000000) + (check1 * 0x10000));
1401  return *checksum;
1402
1403
1404 /*
1405  * aim_oft_buildheader - fills a buffer with network-order fh data
1406  * @dest: buffer to fill -- pre-alloced
1407  * @fh: fh to get data from  
1408  *
1409  * returns length written; -1 on error.
1410  * DOES NOT DO BOUNDS CHECKING!
1411  *
1412  */
1413 faim_internal int aim_oft_buildheader(unsigned char *dest,struct aim_fileheader_t *fh) 
1414
1415   int i, curbyte;
1416   if(!dest || !fh)
1417     return -1;
1418   curbyte = 0;
1419   for(i = 0; i < 8; i++) 
1420     curbyte += aimutil_put8(dest+curbyte, fh->bcookie[i]);
1421   curbyte += aimutil_put16(dest+curbyte, fh->encrypt);
1422   curbyte += aimutil_put16(dest+curbyte, fh->compress);
1423   curbyte += aimutil_put16(dest+curbyte, fh->totfiles);
1424   curbyte += aimutil_put16(dest+curbyte, fh->filesleft);
1425   curbyte += aimutil_put16(dest+curbyte, fh->totparts);
1426   curbyte += aimutil_put16(dest+curbyte, fh->partsleft);
1427   curbyte += aimutil_put32(dest+curbyte, fh->totsize);
1428   curbyte += aimutil_put32(dest+curbyte, fh->size);
1429   curbyte += aimutil_put32(dest+curbyte, fh->modtime);
1430   curbyte += aimutil_put32(dest+curbyte, fh->checksum);
1431   curbyte += aimutil_put32(dest+curbyte, fh->rfrcsum);
1432   curbyte += aimutil_put32(dest+curbyte, fh->rfsize);
1433   curbyte += aimutil_put32(dest+curbyte, fh->cretime);
1434   curbyte += aimutil_put32(dest+curbyte, fh->rfcsum);
1435   curbyte += aimutil_put32(dest+curbyte, fh->nrecvd);
1436   curbyte += aimutil_put32(dest+curbyte, fh->recvcsum);
1437   memcpy(dest+curbyte, fh->idstring, 32);
1438   curbyte += 32;
1439   curbyte += aimutil_put8(dest+curbyte, fh->flags);
1440   curbyte += aimutil_put8(dest+curbyte, fh->lnameoffset);
1441   curbyte += aimutil_put8(dest+curbyte, fh->lsizeoffset);
1442   memcpy(dest+curbyte, fh->dummy, 69);
1443   curbyte += 69;
1444   memcpy(dest+curbyte, fh->macfileinfo, 16);
1445   curbyte += 16;
1446   curbyte += aimutil_put16(dest+curbyte, fh->nencode);
1447   curbyte += aimutil_put16(dest+curbyte, fh->nlanguage);
1448   memset(dest+curbyte, 0x00, 64);
1449   memcpy(dest+curbyte, fh->name, 64);
1450
1451   /* XXX: Filenames longer than 64B  */
1452   curbyte += 64;
1453   return curbyte;
1454 }
1455 #if 0 
1456 /*
1457 * aim_getfile_send - send a FULL file down (ie: blocking; that is: DON'T USE IT, use send_chunk below.)
1458 * @conn: the OFT connection to shove the data down,
1459 * @tosend: is the FILE
1460 * for the file to send
1461 * @fh: the filled-in fh value 
1462
1463 *
1464 * returns -1 on error, 1 on success. This sends the whold file and
1465 * blocks, so it will totally mess you up if you use it. use the
1466 * send_chunk below and work out a schduling setup or some such. 
1467
1468 *
1469 */
1470 faim_export int aim_getfile_send(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh)
1471
1472   int pos, bufpos, i;
1473   const int bufsize = 4096;
1474   char *buf;
1475   
1476  /* sanity checks
1477   */
1478
1479  if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->subtype != AIM_CONN_SUBTYPE_OFT_GETFILE)
1480    { faimdprintf(1, "getfile_send: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
1481    return -1;
1482    }
1483  if(!tosend)
1484    { faimdprintf(1, "getfile_send: file pointer isn't valid\n");
1485    return -1;
1486    }
1487  if(!fh)
1488    { faimdprintf(1, "getfile_send: fh isn't valid\n");
1489    return -1;
1490    } 
1491  /* real code
1492   */
1493
1494  if(!(buf = (char *)calloc(1, bufsize)))
1495    { perror("faim: getfile_send: calloc:");
1496    faimdprintf(2, "getfile_send calloc error\n");
1497    return -1;
1498    } pos = 0;
1499  if( fseek(tosend, 0, SEEK_SET) == -1)
1500    { perror("faim: getfile_send: fseek:");
1501    faimdprintf(2, "getfile_send fseek error\n");
1502    } faimdprintf(2, "faim: getfile_send: using %i byte blocks\n", bufsize);
1503  for(pos = 0;
1504      pos < fh->size;
1505      pos++) { bufpos = pos % bufsize;
1506      if(bufpos == 0 && pos > 0)
1507        { 
1508          /* filled our buffer. spit it across the wire
1509           */
1510
1511          if ( (i = send(conn->fd, buf, bufsize, 0)) != bufsize )
1512            { perror("faim: getfile_send: write1: ");
1513            faimdprintf(1, "faim: getfile_send: whoopsy, didn't write it all...\n");
1514            free(buf);
1515            return -1;
1516            } }
1517      if( (buf[bufpos] = fgetc(tosend)) == EOF)
1518        {
1519          if(pos != fh->size)
1520            { printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1521            faimdprintf(1, "faim: getfile_send: hrm... apparent early EOF at pos 0x%lx of 0x%lx\n", pos, fh->size);
1522            free(buf);
1523            return -1;
1524            } } }
1525  if( (i = send(conn->fd, buf, bufpos+1, 0)) != (bufpos+1))
1526    { perror("faim: getfile_send: write2: ");
1527    faimdprintf(1, "faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1528    free(buf);
1529    return -1;
1530    } free(buf);
1531  fclose(tosend);
1532  return 1;
1533 }
1534  
1535 /*
1536 * aim_getfile_send_chunk - send a chunk of a file down a conn
1537 * @conn: the OFT connection to shove the data down,
1538 * @tosend: the buffer to send
1539 * @fh: the filled-in fh value
1540 * @pos: the position to start at (see below)
1541 * @bufsize: the size of the chunk to send 
1542
1543 *
1544 * returns -1 on error, new pos on success.
1545 * Notes on usage:
1546 * You don't really have to keep track of pos if you don't want
1547 * to. just always call with -1 for pos, and it'll use the one
1548 * contained within the FILE
1549 *. 
1550
1551 *
1552 * if (pos + chunksize > fh->size), we only send as much data as we
1553 * can get (ie: up to fh->size. 
1554
1555 *
1556 * the value of pos: at beginning should be 0, after 5 bytes are sent
1557 * should be 5); -1 for "don't seek" 
1558
1559 *
1560 * GOING TO BE CHANGED TO USE unsigned char
1561 * BUFFERS!!!
1562 */
1563 faim_export int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
1564 {
1565  int bufpos;
1566  char *buf;
1567
1568  /* sanity checks
1569   */
1570
1571  if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->type != AIM_CONN_SUBTYPE_OFT_GETFILE)
1572    { faimdprintf(1, "faim: getfile_send_chunk: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
1573    return -1;
1574    }
1575  if(!tosend)
1576    { faimdprintf(1, "faim: getfile_send_chunk: file pointer isn't valid\n");
1577    return -1;
1578    }
1579  if(!fh)
1580    { faimdprintf(1, "faim: getfile_send_chunk: fh isn't valid\n");
1581    return -1;
1582    } 
1583  /* real code
1584   */
1585
1586  if(!(buf = (char *)calloc(1, bufsize)))
1587    { perror("faim: getfile_send_chunk: calloc:");
1588    faimdprintf(2, "faim: getfile_send_chunk calloc error\n");
1589    return -1;
1590    }
1591  if(pos != -1)
1592    {
1593      if( fseek(tosend, pos, SEEK_SET) == -1)
1594        { perror("faim: getfile_send_chunk: fseek:");
1595        faimdprintf(2, "faim: getfile_send_chunk fseek error\n");
1596        } } faimdprintf(2, "faim: getfile_send_chunk: using %i byte blocks\n", bufsize);
1597  for(bufpos = 0;
1598      pos < fh->size;
1599      bufpos++, pos++) {
1600    if( (buf[bufpos] = fgetc(tosend)) == EOF)
1601      {
1602        if(pos != fh->size)
1603          { faimdprintf(1, "faim: getfile_send_chunk: hrm... apparent early EOF at pos 0x%x of 0x%x\n", pos, fh->size);
1604          free(buf);
1605          return -1;
1606          } } }
1607  if( send(conn->fd, buf, bufpos+1, 0) != (bufpos+1))
1608    { faimdprintf(1, "faim: getfile_send_chunk cleanup: whoopsy, didn't write it all...\n");
1609    free(buf);
1610    return -1;
1611    } free(buf);
1612  return (pos + bufpos);
1613 }
1614 #endif 
1615 /*
1616 * aim_tx_destroy - free's tx_command_t's
1617 * @command: the command to free 
1618
1619 *
1620 * if command is locked, doesn't free.
1621 * returns -1 on error (locked struct); 0 on success. 
1622
1623 *
1624 */
1625 faim_internal int aim_tx_destroy(struct command_tx_struct *command){
1626   if(command->lock)
1627     return -1;
1628   if(command->data)
1629     free(command->data);
1630   if (command->hdrtype == AIM_FRAMETYPE_OFT && command->hdr.oft.hdr2)
1631     free(command->hdr.oft.hdr2);
1632   free(command);
1633   return 0;
1634
1635
1636 /*
1637  * aim_getfile_intitiate - For those times when we want to open up the getfile dialog ourselves.
1638  * @sess: your session,
1639  * @conn: the BOS conn,
1640  * @destsn is the SN to connect to.
1641  */
1642 faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, struct aim_conn_t *conn, char *destsn)
1643
1644   struct command_tx_struct *newpacket;
1645  struct aim_conn_t *newconn;
1646  struct aim_filetransfer_priv *priv;
1647  struct aim_msgcookie_t *cookie;
1648  int curbyte, i, listenfd;
1649  short port = 4443;
1650  struct hostent *hptr;
1651  struct utsname myname;
1652  char cap[16];
1653  char d[4];
1654  
1655  /* Open our socket */
1656
1657  if( (listenfd = aim_listenestablish(port)) == -1)
1658    return NULL;
1659
1660  /* get our local IP */
1661
1662  if(uname(&myname) < 0)
1663    return NULL;
1664  if( (hptr = gethostbyname(myname.nodename)) == NULL)
1665    return NULL;
1666  memcpy(&d, hptr->h_addr_list[0], 4);
1667
1668  /* XXX: this probably isn't quite kosher, but it works */
1669  aim_putcap(cap, 16, AIM_CAPS_GETFILE);
1670
1671  /* create the OSCAR packet */
1672
1673  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(destsn)+4+4+0x42)))
1674    return NULL;
1675  newpacket->lock = 1;
1676
1677  /* lock struct */
1678  curbyte = 0;
1679  curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
1680
1681  /* XXX: check the cookie before commiting to using it */
1682
1683  /* Generate a random message cookie
1684   * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
1685  for (i=0; i<7; i++) 
1686    curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
1687
1688  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1689
1690  /* grab all the data for cookie caching. */
1691
1692  cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t));
1693  memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
1694  cookie->type = AIM_COOKIETYPE_OFTGET;
1695
1696  priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
1697  memcpy(priv->cookie, cookie, 8);
1698  memcpy(priv->sn, destsn, sizeof(priv->sn));
1699  memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
1700  priv->state = 1;
1701  cookie->data = priv;
1702  conn->priv = priv;
1703  aim_cachecookie(sess, cookie);
1704
1705  /* cache da cookie */
1706  
1707  /* Channel ID */
1708  curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
1709
1710  /* Destination SN (prepended with byte length) */
1711  curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
1712  curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
1713  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1714  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1715
1716  /* enTLV start */
1717  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1718  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
1719
1720  /* Flag data / ICBM Parameters? */
1721  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1722  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1723
1724  /* Cookie */
1725  curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
1726
1727  /* Capability String */
1728  curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
1729
1730  /* 000a/0002 : 0001 */
1731  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
1732  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1733  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
1734
1735  /* 0003/0004: IP address */
1736  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1737  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
1738  for(i = 0; i < 4; i++)
1739    curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
1740
1741  /* already in network byte order  */
1742  
1743  /* 0005/0002: Port */
1744  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1745  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1746  curbyte += aimutil_put16(newpacket->data+curbyte, port);
1747
1748  /* 000f/0000: ?? */
1749  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
1750  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1751
1752  /* 2711/000c: ?? */
1753  curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
1754  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
1755  curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
1756
1757  for(i = 0; i < 0x000c - 4; i++)
1758    curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1759
1760  newpacket->commandlen = curbyte;
1761  newpacket->lock = 0;
1762  aim_tx_enqueue(sess, newpacket);
1763
1764  /* allocate and set up our connection */
1765
1766  i = fcntl(listenfd, F_GETFL, 0);
1767  fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
1768  newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
1769
1770  if (!newconn){ 
1771    perror("aim_newconn");
1772    return NULL;
1773  }
1774
1775  newconn->fd = listenfd;
1776  newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
1777  newconn->priv = priv;
1778  faimdprintf(2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
1779
1780  return newconn;
1781 }
1782  
1783 /*
1784  * aim_oft_getfile_request - request a particular file over an established getfile connection
1785  * @sess: your session
1786  * @conn: the established OFT getfile connection
1787  * @name: filename to request
1788  * @size: size of the file 
1789  *
1790  */
1791 faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_conn_t *conn, const unsigned char *name, const int size)
1792 {
1793   struct command_tx_struct *newoft;
1794   struct aim_filetransfer_priv *ft;
1795   if(!sess || !conn || !conn->priv || !name)
1796     return 0;
1797
1798  if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x120c, conn, 0))) {
1799    faimdprintf(2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1800    return -1;
1801  }
1802
1803  newoft->lock = 1;
1804
1805  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1806  newoft->hdr.oft.hdr2len = 0x100 - 8;
1807
1808  ft = (struct aim_filetransfer_priv *)conn->priv;
1809  ft->fh.filesleft = 1;
1810  ft->fh.totfiles = 1;
1811  ft->fh.totparts = 1;
1812  ft->fh.partsleft = 1;
1813  ft->fh.totsize = size;
1814  ft->fh.size = size;
1815  ft->fh.checksum = 0;
1816  memcpy(ft->fh.name, name, strlen(name));
1817  memset(ft->fh.name+strlen(name), 0, 1);
1818
1819  if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1820    newoft->lock = 0;
1821    aim_tx_destroy(newoft);
1822    return -1;
1823  }
1824
1825  if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1826    newoft->lock = 0;
1827    aim_tx_destroy(newoft);
1828    return -1;
1829  }
1830
1831  newoft->lock = 0;
1832
1833  aim_tx_enqueue(sess, newoft);
1834  return 0;
1835 }
1836  
1837 /*
1838  * aim_oft_getfile_ack - acknowledge a getfile download as complete
1839  * @sess: your session
1840  * @conn: the getfile conn to send the ack over 
1841  *
1842  * call this function after you have read all the data in a particular
1843  * filetransfer 
1844  *
1845  */
1846 faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_t *conn) {
1847   struct command_tx_struct *newoft;
1848   struct aim_filetransfer_priv *ft;
1849
1850   if(!sess || !conn || !conn->priv)
1851     return -1;
1852
1853   if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0202, conn, 0))) {
1854     faimdprintf(2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1855     return -1;
1856   } 
1857
1858   newoft->lock = 1;
1859
1860   memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1861   newoft->hdr.oft.hdr2len = 0x100-8;
1862
1863  if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 
1864    newoft->lock = 0;
1865    aim_tx_destroy(newoft);
1866    return -1;
1867  }
1868
1869  ft = (struct aim_filetransfer_priv *)conn->priv;
1870
1871  if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1872    newoft->lock = 0;
1873    aim_tx_destroy(newoft);
1874    return -1;
1875  }
1876
1877  newoft->lock = 0;
1878  aim_tx_enqueue(sess, newoft);
1879  return 0;
1880 }
1881  
1882 /*
1883  * aim_oft_getfile_end - end a getfile.
1884  * @sess: your session
1885  * @conn: the getfile connection 
1886  *
1887  * call this before you close the getfile connection if you're on the
1888  * receiving/requesting end.
1889  */
1890 faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_t *conn)
1891 {
1892   struct command_tx_struct *newoft;
1893   struct aim_filetransfer_priv *ft;
1894   
1895   if(!sess || !conn || !conn->priv)
1896     return -1;
1897
1898   if(!(newoft = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0204, conn, 0))) {
1899     faimdprintf(2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1900     return -1;
1901   }
1902   
1903   newoft->lock = 1;
1904   
1905   memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1906   newoft->hdr.oft.hdr2len = 0x100 - 8;
1907   
1908   if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1909     newoft->lock = 0;
1910     aim_tx_destroy(newoft);
1911     return -1;
1912   }
1913   
1914   ft = (struct aim_filetransfer_priv *)conn->priv;
1915   ft->state = 4; /* no longer wanting data */
1916   ft->fh.nrecvd = ft->fh.size;
1917   ft->fh.recvcsum = ft->fh.checksum;
1918   ft->fh.flags = 0x21;
1919   
1920   if(!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1921     newoft->lock = 0;
1922     aim_tx_destroy(newoft);
1923     return -1;
1924   }
1925   
1926   newoft->lock = 0;
1927   aim_tx_enqueue(sess, newoft);
1928   
1929   return 0;
1930 }
This page took 2.656765 seconds and 5 git commands to generate.