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