source: libfaim/ft.c @ 5d9c664

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 5d9c664 was 862371b, checked in by James M. Kretchmar <kretch@mit.edu>, 21 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 59.9 KB
Line 
1/*
2 * File transfer (OFT) and DirectIM (ODC).
3 * (OSCAR File Transfer, Oscar Direct Connect(ion?)
4 */
5
6#define FAIM_INTERNAL
7
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif
11#include <aim.h>
12
13#ifndef _WIN32
14#include <netdb.h>
15#include <sys/socket.h>
16#include <netinet/in.h>
17#include <sys/utsname.h> /* for aim_directim_initiate */
18#include <arpa/inet.h> /* for inet_ntoa */
19#define G_DIR_SEPARATOR '/'
20#endif
21
22#ifdef _WIN32
23#include "win32dep.h"
24#endif
25
26#define AIM_OFT_PROTO_OFFER          0x0101
27#define AIM_OFT_PROTO_ACCEPT         0x0202
28#define AIM_OFT_PROTO_RESUME         0x0205
29#define AIM_OFT_PROTO_RESUMEACCEPT   0x0207
30#define AIM_OFT_PROTO_ACK            0x0204
31
32struct aim_filetransfer_priv {
33        char sn[MAXSNLEN+1];
34        char cookie[8];
35        char ip[30];
36        int state;
37        struct aim_fileheader_t fh;
38};
39
40struct aim_directim_intdata {
41        fu8_t cookie[8];
42        char sn[MAXSNLEN+1];
43        char ip[22];
44};
45
46static int listenestablish(fu16_t portnum);
47static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs);
48static void oft_dirconvert(char *name);
49static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh);
50 
51/**
52 * aim_handlerendconnect - call this to accept OFT connections and set up the required structures
53 * @sess: the session
54 * @cur: the conn the incoming connection is on
55 *
56 * call this when you get an outstanding read on a conn with subtype
57 * AIM_CONN_SUBTYPE_RENDEZVOUS_OUT, it will clone the current
58 * &aim_conn_t and tweak things as appropriate. the new conn and the
59 * listener conn are both returned to the client in the
60 * %AIM_CB_FAM_OFT, %AIM_CB_OFT_<CLASS>INITIATE callback.
61 */
62faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur)
63{ 
64        int acceptfd = 0;
65        struct sockaddr cliaddr;
66        int clilen = sizeof(cliaddr);
67        int ret = 0;
68        aim_conn_t *newconn;
69
70        if ((acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1)
71                return 0; /* not an error */
72
73        if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */
74                close(acceptfd);
75                aim_conn_close(cur);
76                return -1;
77        } 
78
79        if (!(newconn = aim_cloneconn(sess, cur))) {
80                close(acceptfd);
81                aim_conn_close(cur);
82                return -1;
83        }
84
85        newconn->type = AIM_CONN_TYPE_RENDEZVOUS;
86        newconn->fd = acceptfd;
87
88        if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 
89                struct aim_directim_intdata *priv;
90                aim_rxcallback_t userfunc;
91
92                priv = (struct aim_directim_intdata *)(newconn->internal = cur->internal);
93                cur->internal = NULL;
94
95                snprintf(priv->ip, sizeof(priv->ip), "%s:%u", 
96                                inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), 
97                                ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
98
99                if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE)))
100                        ret = userfunc(sess, NULL, newconn, cur);
101
102        } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
103#if 0
104                struct aim_filetransfer_priv *priv;
105                aim_rxcallback_t userfunc;
106
107                newconn->priv = cur->priv;
108                cur->priv = NULL;
109                priv = (struct aim_filetransfer_priv *)newconn->priv;
110
111                snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
112
113                if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE)))
114                        ret = userfunc(sess, NULL, newconn, cur);
115#endif
116        } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
117                struct aim_filetransfer_priv *ft;
118                aim_rxcallback_t userfunc;
119
120                /* The new conn automatically inherits the internal value
121                 * of cur. */
122                cur->internal = NULL;
123                ft = (struct aim_filetransfer_priv *)newconn->internal;
124
125                snprintf(ft->ip, sizeof(ft->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
126
127                if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEINITIATE)))
128                        ret = userfunc(sess, NULL, newconn, cur);
129        } else { 
130                faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n");
131                aim_conn_close(newconn);
132                ret = -1;
133        }
134
135        return ret;
136}
137
138/**
139 * aim_send_typing - send client-to-client typing notification over established connection
140 * @sess: session to conn
141 * @conn: directim connection
142 * @typing: If true, notify user has started typing; if false, notify user has stopped.
143 *
144 * The connection must have been previously established.
145 */
146faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
147{
148        struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
149        aim_frame_t *fr;
150        aim_bstream_t *hdrbs;
151        fu8_t *hdr;
152        int hdrlen = 0x44;
153
154        if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
155                return -EINVAL;
156
157        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
158                return -ENOMEM;
159        memcpy(fr->hdr.rend.magic, "ODC2", 4);
160        fr->hdr.rend.hdrlen = hdrlen;
161
162        if (!(hdr = calloc(1, hdrlen))) {
163                aim_frame_destroy(fr);
164                return -ENOMEM;
165        }
166
167        hdrbs = &(fr->data);
168        aim_bstream_init(hdrbs, hdr, hdrlen);
169
170        aimbs_put16(hdrbs, 0x0006);
171        aimbs_put16(hdrbs, 0x0000);
172        aimbs_putraw(hdrbs, intdata->cookie, 8);
173        aimbs_put16(hdrbs, 0x0000);
174        aimbs_put16(hdrbs, 0x0000);
175        aimbs_put16(hdrbs, 0x0000);
176        aimbs_put16(hdrbs, 0x0000);
177        aimbs_put32(hdrbs, 0x00000000);
178        aimbs_put16(hdrbs, 0x0000);
179        aimbs_put16(hdrbs, 0x0000);
180        aimbs_put16(hdrbs, 0x0000);
181
182        /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
183        aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
184
185        aimbs_put16(hdrbs, 0x0000);
186        aimbs_put16(hdrbs, 0x0000);
187        aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
188       
189        aim_bstream_setpos(hdrbs, 52); /* bleeehh */
190
191        aimbs_put8(hdrbs, 0x00);
192        aimbs_put16(hdrbs, 0x0000);
193        aimbs_put16(hdrbs, 0x0000);
194        aimbs_put16(hdrbs, 0x0000);
195        aimbs_put16(hdrbs, 0x0000);
196        aimbs_put16(hdrbs, 0x0000);
197        aimbs_put16(hdrbs, 0x0000);
198        aimbs_put16(hdrbs, 0x0000);
199        aimbs_put8(hdrbs, 0x00);
200
201        /* end of hdr */
202
203        aim_tx_enqueue(sess, fr);
204
205        return 0;
206} 
207
208/**
209 * aim_send_im_direct - send IM client-to-client over established connection
210 * @sess: session to conn
211 * @conn: directim connection
212 * @msg: null-terminated string to send.
213 * @len: The length of the message to send, including binary data.
214 * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1
215 *
216 * Call this just like you would aim_send_im, to send a directim. You
217 * _must_ have previously established the directim connection.
218 */
219faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
220{
221        struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
222        aim_frame_t *fr;
223        aim_bstream_t *hdrbs;
224        int hdrlen = 0x44;
225        fu8_t *hdr;
226
227        if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 
228                return -EINVAL; 
229
230        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len)))
231                return -ENOMEM; 
232
233        memcpy(fr->hdr.rend.magic, "ODC2", 4);
234        fr->hdr.rend.hdrlen = hdrlen;
235       
236        if (!(hdr = calloc(1, hdrlen + len))) {
237                aim_frame_destroy(fr);
238                return -ENOMEM;
239        }
240
241        hdrbs = &(fr->data);
242        aim_bstream_init(hdrbs, hdr, hdrlen + len);
243
244        aimbs_put16(hdrbs, 0x0006);
245        aimbs_put16(hdrbs, 0x0000);
246        aimbs_putraw(hdrbs, intdata->cookie, 8);
247        aimbs_put16(hdrbs, 0x0000);
248        aimbs_put16(hdrbs, 0x0000);
249        aimbs_put16(hdrbs, 0x0000);
250        aimbs_put16(hdrbs, 0x0000);
251        aimbs_put32(hdrbs, len);
252        aimbs_put16(hdrbs, encoding);
253        aimbs_put16(hdrbs, 0x0000);
254        aimbs_put16(hdrbs, 0x0000);
255       
256        /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */
257        aimbs_put16(hdrbs, 0x0000);
258
259        aimbs_put16(hdrbs, 0x0000);
260        aimbs_put16(hdrbs, 0x0000);
261        aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
262
263        aim_bstream_setpos(hdrbs, 52); /* bleeehh */
264
265        aimbs_put8(hdrbs, 0x00);
266        aimbs_put16(hdrbs, 0x0000);
267        aimbs_put16(hdrbs, 0x0000);
268        aimbs_put16(hdrbs, 0x0000);
269        aimbs_put16(hdrbs, 0x0000);
270        aimbs_put16(hdrbs, 0x0000);
271        aimbs_put16(hdrbs, 0x0000);
272        aimbs_put16(hdrbs, 0x0000);
273        aimbs_put8(hdrbs, 0x00);
274       
275        /* end of hdr2 */
276       
277#if 0 /* XXX this is how you send buddy icon info... */
278        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);
279        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);
280        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
281        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);
282        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);
283        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
284        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
285        i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
286#endif
287        aimbs_putraw(hdrbs, msg, len);
288       
289        aim_tx_enqueue(sess, fr);
290       
291        return 0;
292} 
293
294static int getlocalip(fu8_t *ip)
295{
296        struct hostent *hptr;
297        char localhost[129];
298
299        /* XXX if available, use getaddrinfo() */
300        /* XXX allow client to specify which IP to use for multihomed boxes */
301
302        if (gethostname(localhost, 128) < 0)
303                return -1;
304
305        if (!(hptr = gethostbyname(localhost)))
306                return -1;
307
308        memcpy(ip, hptr->h_addr_list[0], 4);
309
310        return 0;
311}
312
313/**
314 * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves.
315 * @sess: your session,
316 * @conn: the BOS conn,
317 * @priv: a dummy priv value (we'll let it get filled in later) (if you pass a %NULL, we alloc one)
318 * @destsn: the SN to connect to.
319 *
320 */
321faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, const char *destsn)
322{ 
323        aim_conn_t *newconn;
324        aim_msgcookie_t *cookie;
325        struct aim_directim_intdata *priv;
326        int listenfd;
327        fu16_t port = 4443;
328        fu8_t localip[4];
329        fu8_t ck[8];
330
331        if (getlocalip(localip) == -1)
332                return NULL;
333
334        if ((listenfd = listenestablish(port)) == -1)
335                return NULL;
336
337        aim_request_directim(sess, destsn, localip, port, ck);
338
339        cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
340        memcpy(cookie->cookie, ck, 8);
341        cookie->type = AIM_COOKIETYPE_OFTIM;
342
343        /* this one is for the cookie */
344        priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
345
346        memcpy(priv->cookie, ck, 8);
347        strncpy(priv->sn, destsn, sizeof(priv->sn));
348        cookie->data = priv;
349        aim_cachecookie(sess, cookie);
350
351        /* XXX switch to aim_cloneconn()? */
352        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) {
353                close(listenfd);
354                return NULL;
355        }
356
357        /* this one is for the conn */
358        priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
359
360        memcpy(priv->cookie, ck, 8);
361        strncpy(priv->sn, destsn, sizeof(priv->sn));
362
363        newconn->fd = listenfd;
364        newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
365        newconn->internal = priv;
366        newconn->lastactivity = time(NULL);
367
368        faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
369
370        return newconn;
371}
372
373/**
374 * aim_sendfile_intitiate - For those times when we want to send the file ourselves.
375 * @sess: your session,
376 * @conn: the BOS conn,
377 * @destsn: the SN to connect to.
378 * @filename: the name of the files you want to send
379 *
380 */
381faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret)
382{ 
383        aim_conn_t *newconn;
384        aim_msgcookie_t *cookie;
385        struct aim_filetransfer_priv *ft;
386        int listenfd;
387
388        /* XXX allow different ports */
389        fu16_t port = 4443;
390        fu8_t localip[4];
391        fu8_t ck[8];
392
393        if (getlocalip(localip) == -1)
394                return NULL;
395
396        if ((listenfd = listenestablish(port)) == -1)
397                return NULL;
398
399        aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck);
400
401        cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
402        memcpy(cookie->cookie, ck, 8);
403        cookie->type = AIM_COOKIETYPE_OFTSEND;
404        memcpy(cookret, ck, 8);
405
406        /* this one is for the cookie */
407        ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
408
409        memcpy(ft->cookie, ck, 8);
410        strncpy(ft->sn, destsn, sizeof(ft->sn));
411        cookie->data = ft;
412        aim_cachecookie(sess, cookie);
413
414        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) {
415                close(listenfd);
416                return NULL;
417        }
418
419        /* this one is for the conn */
420        ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
421
422        memcpy(ft->cookie, ck, 8);
423        strncpy(ft->sn, destsn, sizeof(ft->sn));
424
425        newconn->fd = listenfd;
426        newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
427        newconn->internal = ft;
428        newconn->lastactivity = time(NULL);
429
430        faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
431
432        return newconn;
433}
434
435#if 0
436/**
437 * unsigned int aim_oft_listener_clean - close up old listeners
438 * @sess: session to clean up in
439 * @age: maximum age in seconds
440 *
441 * returns number closed, -1 on error.
442 */
443faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age)
444{
445        aim_conn_t *cur;
446        time_t now;
447        unsigned int hit = 0;
448
449        if (!sess)
450                return -1;
451        now = time(NULL);
452
453        for(cur = sess->connlist;cur; cur = cur->next)
454                if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
455                        if (cur->lastactivity < (now - age) ) {
456                                aim_conn_close(cur);
457                                hit++;
458                        }
459                }
460        return hit;
461}
462#endif
463
464faim_export const char *aim_directim_getsn(aim_conn_t *conn)
465{
466        struct aim_directim_intdata *intdata;
467
468        if (!conn)
469                return NULL;
470
471        if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 
472                        (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
473                return NULL;
474
475        if (!conn->internal)
476                return NULL;
477
478        intdata = (struct aim_directim_intdata *)conn->internal;
479
480        return intdata->sn;
481}
482
483/**
484 * aim_directim_connect - connect to buddy for directim
485 * @sess: the session to append the conn to,
486 * @sn: the SN we're connecting to
487 * @addr: address to connect to
488 *
489 * This is a wrapper for aim_newconn.
490 *
491 * If addr is NULL, the socket is not created, but the connection is
492 * allocated and setup to connect.
493 *
494 */
495faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie)
496{ 
497        aim_conn_t *newconn;
498        struct aim_directim_intdata *intdata;
499
500        if (!sess || !sn)
501                return NULL;
502
503        if (!(intdata = malloc(sizeof(struct aim_directim_intdata))))
504                return NULL;
505        memset(intdata, 0, sizeof(struct aim_directim_intdata));
506
507        memcpy(intdata->cookie, cookie, 8);
508        strncpy(intdata->sn, sn, sizeof(intdata->sn));
509        if (addr)
510                strncpy(intdata->ip, addr, sizeof(intdata->ip));
511
512        /* XXX verify that non-blocking connects actually work */
513        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) {
514                free(intdata);
515                return NULL;
516        }
517
518        if (!newconn) {
519                free(intdata);
520                return newconn;
521        }
522
523        newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
524        newconn->internal = intdata;
525
526        return newconn;
527} 
528
529/**
530 * aim_directim_getconn - find a directim conn for buddy name
531 * @sess: your session,
532 * @name: the name to get,
533 *
534 * returns conn for directim with name, %NULL if none found.
535 *
536 */
537faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name)
538{
539        aim_conn_t *cur;
540
541        if (!sess || !name || !strlen(name))
542                return NULL;
543
544        for (cur = sess->connlist; cur; cur = cur->next) {
545                struct aim_directim_intdata *intdata;
546               
547                if ((cur->type != AIM_CONN_TYPE_RENDEZVOUS) || (cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
548                        continue;
549
550                intdata = cur->internal;
551
552                if (aim_sncmp(intdata->sn, name) == 0)
553                        break;
554        }
555
556        return cur;
557} 
558
559/**
560 * aim_accepttransfer - accept a file transfer request
561 * @sess: the session,
562 * @conn: the BOS conn for the CAP reply
563 * @sn: the screenname to send it to,
564 * @cookie: the cookie used
565 * @ip: the ip to connect to
566 * @port: the port to use
567 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)
568 *
569 * @listingfiles: number of files to share
570 * @listingtotsize: total size of shared files
571 * @listingsize: length of the listing file(buffer)
572 * @listingchecksum: checksum of the listing
573 *
574 * Returns new connection or %NULL on error.
575 *
576 * XXX this should take a struct.
577 */
578faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn,
579                                                const fu8_t *cookie, const fu8_t *ip, 
580                                                fu16_t port, fu16_t rendid, ...)
581{
582        aim_frame_t *newpacket;
583        aim_conn_t *newconn;
584        struct aim_filetransfer_priv *priv;
585        int i;
586        char addr[21];
587
588        if (!sess || !conn || !sn || !cookie || !ip) {
589                return NULL;
590        }
591
592        /* OSCAR CAP accept packet */
593
594        if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
595                return NULL;
596        }
597
598        aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
599
600        for (i = 0; i < 8; i++)
601                aimbs_put8(&newpacket->data, cookie[i]);
602
603        aimbs_put16(&newpacket->data, 0x0002);
604        aimbs_put8(&newpacket->data, strlen(sn));
605        aimbs_putraw(&newpacket->data, sn, strlen(sn));
606        aimbs_put16(&newpacket->data, 0x0005);
607        aimbs_put16(&newpacket->data, 0x001a);
608        aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT);
609
610        for (i = 0; i < 8; i++) /* yes, again... */
611                aimbs_put8(&newpacket->data, cookie[i]);
612
613        aim_putcap(&newpacket->data, rendid);
614        aim_tx_enqueue(sess, newpacket);
615
616        snprintf(addr, sizeof(addr), "%s:%d", ip, port);
617        newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
618
619        if (newconn->status & AIM_CONN_STATUS_CONNERR) {
620                return NULL;
621        }
622
623        if (!newconn || (newconn->fd == -1)) {
624                perror("aim_newconn");
625        faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
626                return newconn;
627        }
628
629        priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
630
631        memcpy(priv->cookie, cookie, 8);
632        priv->state = 0;
633        strncpy(priv->sn, sn, MAXSNLEN);
634        strncpy(priv->ip, ip, sizeof(priv->ip));
635        newconn->internal = (void *)priv;
636
637        faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
638
639        if (rendid == AIM_CAPS_GETFILE) {
640                return NULL; /* This should never happen for now. -- wtm */
641
642#if 0
643        struct aim_fileheader_t *fh;
644        aim_frame_t *newoft;
645        aim_msgcookie_t *cachedcook;
646        /* XXX take the following parameters    fu16_t listingfiles,
647                                                fu16_t listingtotsize,
648                                                fu16_t listingsize,
649                                                fu32_t listingchecksum, */
650
651        newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
652
653        faimdprintf(sess, 2, "faim: getfile request accept\n");
654
655        if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) {
656                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
657                /* XXX: conn leak here */
658                return NULL;
659        }
660
661        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
662        newoft->hdr.oft.hdr2len = 0x100 - 8;
663
664        if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
665                /* XXX: conn leak here */
666                perror("calloc");
667                return NULL;
668        }
669
670        fh->encrypt = 0x0000;
671        fh->compress = 0x0000;
672        fh->totfiles = listingfiles;
673        fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/
674        fh->totparts = 0x0001;
675        fh->partsleft = 0x0001;
676        fh->totsize = listingtotsize;
677        fh->size = listingsize; /* ls -l listing.txt */
678        fh->modtime = (int)time(NULL); /* we'll go with current time for now */
679        fh->checksum = listingchecksum;
680        fh->rfcsum = 0x00000000;
681        fh->rfsize = 0x00000000;
682        fh->cretime = 0x00000000;
683        fh->rfcsum = 0x00000000;
684        fh->nrecvd = 0x00000000;
685        fh->recvcsum = 0x00000000;
686        memset(fh->idstring, 0, sizeof(fh->idstring));
687        strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
688        fh->flags = 0x02;
689        fh->lnameoffset = 0x1a;
690        fh->lsizeoffset = 0x10;
691        memset(fh->dummy, 0, sizeof(fh->dummy));
692        memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
693
694        /* we need to figure out these encodings for filenames */
695        fh->nencode = 0x0000;
696        fh->nlanguage = 0x0000;
697        memset(fh->name, 0, sizeof(fh->name));
698        strncpy(fh->name, "listing.txt", sizeof(fh->name));
699
700        if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
701                aim_frame_destroy(newoft);
702                /* XXX: conn leak */
703                perror("calloc (1)");
704                return NULL;
705        }
706
707        memcpy(fh->bcookie, cookie, 8);
708
709        if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
710                faimdprintf(sess, 1, "eek, bh fail!\n");
711
712        aim_tx_enqueue(sess, newoft);
713
714        if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) {
715                faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
716                /* XXX: more cleanup, conn leak */
717                perror("calloc (2)");
718                return NULL;
719        }
720
721        memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
722        memcpy(cachedcook->cookie, cookie, 8);
723
724        cachedcook->type = AIM_COOKIETYPE_OFTGET;
725        /* XXX doesn't priv need to be copied so we don't
726         * double free? -- wtm
727         */
728        cachedcook->data = (void *)priv;
729
730        if (aim_cachecookie(sess, cachedcook) == -1)
731                faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
732
733        free(fh);
734#endif
735
736        } else if (rendid == AIM_CAPS_SENDFILE) {
737                newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
738                priv->fh.recvcsum = 0xffff0000;
739        } else {
740                return NULL;
741        }
742
743        return newconn;
744}
745
746/* conn is a BOS connection over which to send the cancel msg */
747faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
748                const char *cookie, const char *sn, int rendid)
749{
750        aim_frame_t *newpacket;
751        int i;
752
753        if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
754                return 1;
755        }
756
757        aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
758
759        for (i = 0; i < 8; i++)
760                aimbs_put8(&newpacket->data, cookie[i]);
761
762        aimbs_put16(&newpacket->data, 0x0002);
763        aimbs_put8(&newpacket->data, strlen(sn));
764        aimbs_putraw(&newpacket->data, sn, strlen(sn));
765        aimbs_put16(&newpacket->data, 0x0005);
766        aimbs_put16(&newpacket->data, 0x001a);
767        aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
768
769        for (i = 0; i < 8; i++)
770                aimbs_put8(&newpacket->data, cookie[i]);
771
772        aim_putcap(&newpacket->data, rendid);
773        aim_tx_enqueue(sess, newpacket);
774
775        return 0;
776}
777
778/**
779 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
780 * @file is an opened listing file
781 *
782 * returns a pointer to the filled-in fileheader_t
783 *
784 * Currently omits checksum. we'll fix this when AOL breaks us, i
785 * guess.
786 *
787 */
788faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file) 
789{
790        return NULL;
791#if 0
792        struct aim_fileheader_t *fh;
793        u_long totsize = 0, size = 0, checksum = 0xffff0000;
794        short totfiles = 0;
795        char *linebuf, sizebuf[9];
796        int linelength = 1024;
797
798        /* XXX: if we have a line longer than 1024chars, God help us. */
799        if ((linebuf = (char *)calloc(1, linelength)) == NULL ) {
800                faimdprintf(sess, 2, "linebuf calloc failed\n");
801                return NULL;
802        }
803
804        if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
805                perror("getlisting END1 fseek:");
806                faimdprintf(sess, 2, "getlising fseek END1 error\n");
807        }
808
809        if ((size = ftell(file)) == -1) {
810                perror("getlisting END1 getpos:");
811                faimdprintf(sess, 2, "getlising getpos END1 error\n");
812        }
813
814        if (fseek(file, 0, SEEK_SET) != 0) {
815                perror("getlesting fseek(SET):");
816                faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
817        }
818
819        memset(linebuf, 0, linelength);
820
821        size = 0;
822
823        while(fgets(linebuf, linelength, file)) {
824                totfiles++;
825                memset(sizebuf, 0, 9);
826
827                size += strlen(linebuf);
828
829                if (strlen(linebuf) < 23) {
830                        faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
831                        continue;
832                }
833
834                if (linebuf[strlen(linebuf)-1] != '\n') {
835                        faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
836                }
837
838                memcpy(sizebuf, linebuf+17, 8);
839
840                totsize += strtol(sizebuf, NULL, 10);
841                memset(linebuf, 0, linelength);
842        }
843
844        if (fseek(file, 0, SEEK_SET) == -1) {
845                perror("getlisting END2 fseek:");
846                faimdprintf(sess, 2, "getlising fseek END2 error\n");
847        }
848
849        free(linebuf);
850
851        /* we're going to ignore checksumming the data for now -- that
852         * requires walking the whole listing.txt. it should probably be
853         * done at register time and cached, but, eh. */
854
855        if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
856                return NULL;
857
858        fh->encrypt = 0x0000;
859        fh->compress = 0x0000;
860        fh->totfiles = totfiles;
861        fh->filesleft = totfiles; /* is this right? */
862        fh->totparts = 0x0001;
863        fh->partsleft = 0x0001;
864        fh->totsize = totsize;
865        fh->size = size; /* ls -l listing.txt */
866        fh->modtime = (int)time(NULL); /* we'll go with current time for now */
867        fh->checksum = checksum; /* XXX: checksum ! */
868        fh->rfcsum = 0x00000000;
869        fh->rfsize = 0x00000000;
870        fh->cretime = 0x00000000;
871        fh->rfcsum = 0x00000000;
872        fh->nrecvd = 0x00000000;
873        fh->recvcsum = 0x00000000;
874
875        /* memset(fh->idstring, 0, sizeof(fh->idstring)); */
876        memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
877        memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
878
879        fh->flags = 0x02;
880        fh->lnameoffset = 0x1a;
881        fh->lsizeoffset = 0x10;
882
883        /* memset(fh->dummy, 0, sizeof(fh->dummy)); */
884        memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
885
886        fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */
887        fh->nlanguage = 0x0000;
888
889        /* memset(fh->name, 0, sizeof(fh->name)); */
890        strncpy(fh->name, "listing.txt", sizeof(fh->name));
891        memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
892
893        faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
894        return fh;
895#endif
896}
897
898/**
899 * aim_listenestablish - create a listening socket on a port.
900 * @portnum: the port number to bind to.
901 *
902 * you need to call accept() when it's connected. returns your fd
903 *
904 * XXX: give the client author the responsibility of setting up a
905 * listener, then we no longer have a libfaim problem with broken
906 * solaris *innocent smile* -jbm
907 */
908static int listenestablish(fu16_t portnum)
909{
910#if HAVE_GETADDRINFO
911        int listenfd;
912        const int on = 1;
913        struct addrinfo hints, *res, *ressave;
914        char serv[5];
915
916        snprintf(serv, sizeof(serv), "%d", portnum);
917        memset(&hints, 0, sizeof(struct addrinfo));
918        hints.ai_flags = AI_PASSIVE;
919        hints.ai_family = AF_UNSPEC;
920        hints.ai_socktype = SOCK_STREAM;
921        if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) {
922                perror("getaddrinfo");
923                return -1;
924        } 
925        ressave = res;
926        do { 
927                listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
928                if (listenfd < 0)
929                        continue;
930                setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
931                if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
932                        break;
933                /* success */
934                close(listenfd);
935        } while ( (res = res->ai_next) );
936
937        if (!res)
938                return -1;
939
940        if (listen(listenfd, 1024)!=0) { 
941                perror("listen");
942                return -1;
943        } 
944
945        fcntl(listenfd, F_SETFL, O_NONBLOCK);
946
947        freeaddrinfo(ressave);
948        return listenfd;
949#else
950        int listenfd;
951        const int on = 1;
952        struct sockaddr_in sockin;
953
954        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
955                perror("socket(listenfd)");
956                return -1;
957        }
958
959        if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
960                perror("setsockopt(listenfd)");
961                close(listenfd);
962                return -1;
963        } 
964
965        memset(&sockin, 0, sizeof(struct sockaddr_in));
966        sockin.sin_family = AF_INET;
967        sockin.sin_port = htons(portnum);
968
969        if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
970                perror("bind(listenfd)");
971                close(listenfd);
972                return -1;
973        }
974        if (listen(listenfd, 4) != 0) {
975                perror("listen(listenfd)");
976                close(listenfd);
977                return -1;
978        }
979        fcntl(listenfd, F_SETFL, O_NONBLOCK);
980        return listenfd;
981#endif
982} 
983
984static int getcommand_getfile(aim_session_t *sess, aim_conn_t *conn)
985{
986#if 0
987        struct aim_filetransfer_priv *ft;
988        aim_rxcallback_t userfunc;
989
990        ft = conn->priv;
991        if (ft->state == 2) {
992                /* waiting on listing data */
993                int ret = 0;
994                char *listing;
995                aim_frame_t *newoft;
996
997                if (!(listing = malloc(ft->fh.size)))
998                        return -1;
999
1000                ft->state = 0;
1001                if (aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size)   
1002                        faimdprintf(sess, 2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size);
1003
1004                if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) {
1005                        faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n");
1006                        free(listing);
1007                        aim_conn_close(conn);
1008                        return -1;
1009                }
1010
1011                memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1012                newoft->hdr.oft.hdr2len = 0x100 - 8;
1013
1014                /* Protocol BS - set nrecvd to size of listing, recvcsum to listing checksum, flags to 0 */
1015
1016                ft->fh.nrecvd = ft->fh.size;
1017                ft->fh.recvcsum = ft->fh.checksum;
1018                ft->fh.flags = 0;
1019
1020                if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1021                        aim_frame_destroy(newoft);
1022                        free(listing);
1023                        return -1;
1024                }
1025
1026                if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh))))
1027                        faimdprintf(sess, 2, "eek! bh fail listing\n");
1028
1029                /* send the 120b */
1030                aim_tx_enqueue(sess, newoft);
1031                if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) )
1032                        ret = userfunc(sess, NULL, conn, ft, listing);
1033
1034                free(listing);
1035                return ret;
1036        }
1037
1038        if (ft->state == 3) {
1039                /* waiting on file data */
1040                if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) )
1041                        return userfunc(sess, NULL, conn, ft->fh.name,
1042                                        ft->fh.size);
1043                return 0;
1044        }
1045
1046        if (ft->state == 4) {
1047                if( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4)) )
1048                        return userfunc(sess, NULL, conn);
1049                aim_conn_close(conn);
1050                return 0;
1051        }       
1052
1053        return 0;
1054#else
1055        return -1;
1056#endif
1057}
1058
1059static void connclose_sendfile(aim_session_t *sess, aim_conn_t *conn)
1060{
1061        aim_msgcookie_t *cook;
1062        struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->internal;
1063
1064        cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND);
1065        aim_cookie_free(sess, cook);
1066
1067        return;
1068}
1069
1070static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn)
1071{
1072        free(conn->internal);
1073
1074        return;
1075}
1076
1077static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn)
1078{
1079#if 0
1080        aim_msgcookie_t *cook;
1081        struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv;
1082
1083        cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET);
1084        aim_cookie_free(sess, cook);
1085#endif
1086        return;
1087}
1088
1089static void connkill_getfile(aim_session_t *sess, aim_conn_t *conn)
1090{
1091       
1092        free(conn->internal);
1093
1094        return;
1095}
1096
1097static void connclose_directim(aim_session_t *sess, aim_conn_t *conn)
1098{
1099        struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
1100        aim_msgcookie_t *cook;
1101
1102        cook = aim_uncachecookie(sess, intdata->cookie, AIM_COOKIETYPE_OFTIM);
1103        aim_cookie_free(sess, cook);
1104
1105        return;
1106}
1107
1108static void connkill_directim(aim_session_t *sess, aim_conn_t *conn)
1109{
1110       
1111        free(conn->internal);
1112
1113        return;
1114}
1115
1116faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn)
1117{
1118
1119        if (conn->type != AIM_CONN_TYPE_RENDEZVOUS)
1120                return;
1121
1122        if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE)
1123                connclose_sendfile(sess, conn);
1124        else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE)
1125                connclose_getfile(sess, conn);
1126        else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
1127                connclose_directim(sess, conn);
1128
1129        return;
1130}
1131
1132faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn)
1133{
1134
1135        if (conn->type != AIM_CONN_TYPE_RENDEZVOUS)
1136                return;
1137
1138        if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE)
1139                connkill_sendfile(sess, conn);
1140        else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE)
1141                connkill_getfile(sess, conn);
1142        else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
1143                connkill_directim(sess, conn);
1144
1145        return;
1146}
1147
1148static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1149{
1150        aim_frame_t fr;
1151        aim_rxcallback_t userfunc;
1152        fu32_t payloadlength;
1153        fu16_t flags, encoding;
1154        char *snptr = NULL;
1155
1156        fr.conn = conn;
1157
1158        /* XXX ugly */
1159        aim_bstream_setpos(bs, 20);
1160        payloadlength = aimbs_get32(bs);
1161
1162        aim_bstream_setpos(bs, 24);
1163        encoding = aimbs_get16(bs);
1164
1165        aim_bstream_setpos(bs, 30);
1166        flags = aimbs_get16(bs);
1167
1168        aim_bstream_setpos(bs, 36);
1169        /* XXX -create an aimbs_getnullstr function? */
1170        snptr = aimbs_getstr(bs, MAXSNLEN);
1171
1172        faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr);
1173
1174        if (flags & 0x0002) {
1175                int ret = 0;
1176
1177                if (flags == 0x000c) {
1178                        if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1179                                ret = userfunc(sess, &fr, snptr, 1);
1180                        return ret;
1181                }
1182
1183                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1184                        ret = userfunc(sess, &fr, snptr, 0);
1185
1186                return ret;
1187
1188        } else if (((flags & 0x000f) == 0x0000) && payloadlength) {
1189                char *msg, *msg2;
1190                int ret = 0;
1191                int recvd = 0;
1192                int i;
1193
1194                if (!(msg = calloc(1, payloadlength+1)))
1195                        return -1;
1196                msg2 = msg;
1197               
1198                while (payloadlength - recvd) {
1199                        if (payloadlength - recvd >= 1024)
1200                                i = aim_recv(conn->fd, msg2, 1024);
1201                        else 
1202                                i = aim_recv(conn->fd, msg2, payloadlength - recvd);
1203                        if (i <= 0) {
1204                                free(msg);
1205                                return -1;
1206                        }
1207                        recvd = recvd + i;
1208                        msg2 = msg2 + i;
1209                        if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
1210                                userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
1211                }
1212               
1213                if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
1214                        ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
1215
1216                free(msg);
1217
1218                return ret;
1219        }
1220
1221        return 0;
1222}
1223
1224static int handlehdr_getfile_listing(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1225{
1226#if 0
1227        struct aim_filetransfer_priv *ft;
1228        struct aim_fileheader_t *fh;
1229        struct aim_msgcookie_t *cook;
1230        aim_frame_t *newoft;
1231        aim_rxcallback_t userfunc;
1232
1233        faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n");
1234        fh = aim_oft_getfh(hdr);
1235
1236        faim_mutex_unlock(&conn->active);
1237
1238        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1239                free(fh);
1240                return -1;
1241        }
1242
1243        ft = cook->data;
1244
1245        /* we're waaaaiiiting.. for listing.txt */
1246        ft->state = 2;
1247
1248        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1249        free(fh);
1250
1251        if(aim_cachecookie(sess, cook) == -1) {
1252                faimdprintf(sess, 1, "error caching cookie\n");
1253                return -1;
1254        }
1255
1256        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) {
1257                aim_conn_close(conn);
1258                return -1;
1259        }
1260
1261        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1262        newoft->hdr.oft.hdr2len = 0x100 - 8;
1263
1264        if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1265                newoft->lock = 0;
1266                aim_frame_destroy(newoft);
1267                return -1;
1268        }
1269
1270        if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1271                newoft->lock = 0;
1272                aim_frame_destroy(newoft);
1273                return -1;
1274        }
1275
1276        newoft->lock = 0;
1277        aim_tx_enqueue(sess, newoft);
1278#endif
1279        return -1;
1280}
1281
1282static int handlehdr_getfile_listing2(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1283{
1284#if 0
1285        struct aim_filetransfer_priv *ft;
1286        struct aim_fileheader_t *fh;
1287        struct aim_msgcookie_t *cook;
1288        int ret = 0;
1289        aim_rxcallback_t userfunc;
1290       
1291        fh = aim_oft_getfh(hdr);
1292
1293        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
1294                faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);
1295
1296        ft = cook->data;
1297
1298        if (ft->fh.size != fh->size)
1299                faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size);
1300
1301        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ)))
1302                ret = userfunc(sess, NULL, conn, fh);
1303
1304        faimdprintf(sess, 2, "faim: get_command_rendezvous: hit end of 1209\n");
1305
1306        free(fh);
1307
1308        return ret;
1309#else
1310        return -1;
1311#endif
1312}
1313
1314static int handlehdr_getfile_listing3(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1315{
1316#if 0
1317        struct aim_filetransfer_priv *ft;
1318        struct aim_msgcookie_t *cook;
1319        struct aim_fileheader_t *fh;
1320        aim_rxcallback_t userfunc;
1321
1322        fh = aim_oft_getfh(hdr);
1323
1324        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1325                free(fh);
1326                return -1;
1327        }
1328
1329        free(fh);
1330
1331        ft = cook->data;
1332
1333        if (aim_cachecookie(sess, cook) == -1)
1334                return -1;
1335
1336        if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGRXCONFIRM)))
1337                return userfunc(sess, NULL, conn);
1338#endif
1339        return -1;
1340}
1341
1342static int handlehdr_getfile_request(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1343{
1344#if 0
1345        struct aim_filetransfer_priv *ft;
1346        aim_msgcookie_t *cook;
1347        struct aim_fileheader_t *fh;
1348        aim_frame_t *newoft;
1349        int i = 0;
1350        aim_rxcallback_t userfunc;
1351
1352        fh = aim_oft_getfh(hdr);
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        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1361        free(fh);
1362
1363        aim_cachecookie(sess, cook);
1364
1365        faimdprintf(sess, 2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name);
1366
1367        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) )
1368                i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie);
1369
1370        if (i < 0)
1371                return i;
1372
1373        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0101, 0))) {
1374                faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1375                return -1;
1376        }
1377
1378        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1379        newoft->hdr.oft.hdr2len = 0x100 - 8;
1380
1381        if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1382                aim_frame_destroy(newoft);
1383                return -1;
1384        }
1385
1386        /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */
1387        ft->fh.nrecvd = 0;
1388        ft->fh.recvcsum = 0;
1389        ft->fh.flags = 0x20;
1390
1391        aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1392
1393        aim_tx_enqueue(sess, newoft);
1394
1395        faimdprintf(sess, 2, "faim: OFT: OFT file header enqueued.\n");
1396
1397        return i;
1398#else
1399        return -1;
1400#endif
1401}
1402
1403static int handlehdr_getfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1404{
1405#if 0
1406        struct aim_fileheader_t *fh;
1407        struct aim_filetransfer_priv *ft;
1408        struct aim_msgcookie_t *cook;
1409        struct command_tx_struct *newoft;
1410        aim_rxcallback_t userfunc;
1411
1412        fh = aim_oft_getfh(hdr);
1413
1414        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1415                free(fh);
1416                return -1;
1417        }
1418
1419        free(fh);
1420
1421        ft = cook->data;
1422
1423        ft->state = 3;
1424
1425        if (aim_cachecookie(sess, cook) == -1)
1426                return -1;
1427
1428        faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name);
1429
1430        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
1431                faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1432                return -1;
1433        }
1434
1435        newoft->lock = 1;
1436        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1437
1438        newoft->hdr.oft.hdr2len = 0x100 - 8;
1439
1440        if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1441                aim_frame_destroy(newoft);
1442                return -1;
1443        }
1444
1445        aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1446
1447        newoft->lock = 0;
1448        aim_tx_enqueue(sess, newoft);
1449
1450        faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n");
1451
1452        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL)
1453                return 1;
1454#else
1455        return -1;
1456#endif
1457}
1458
1459/* We are receiving a file, and the buddy sent us this header describing
1460 * it.  We send back a similar header to confirm, then we're ready to
1461 * start reading the raw data.
1462 */
1463static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1464{
1465        struct aim_filetransfer_priv *ft;
1466        struct aim_fileheader_t *fh;
1467        aim_frame_t *newoft;
1468        aim_rxcallback_t userfunc;
1469
1470        fh = aim_oft_getfh(bs);
1471
1472        /* We receive a null cookie for the first file; we must fill
1473         * it in to authenticate ourselves. -- wtm
1474         */
1475        ft = conn->internal;
1476        memcpy(&(fh->bcookie), ft->cookie, 8);
1477
1478        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1479        free(fh);
1480
1481        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) {
1482                faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1483                return -1;
1484        }
1485
1486        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1487                return -1;
1488        }
1489        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1490        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1491
1492        aim_tx_enqueue(sess, newoft);
1493
1494        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL)
1495                return 1;
1496
1497        {
1498                char *cur;
1499                /* Convert the directory separator: it is sent
1500                 * as ^A (0x01).
1501                 */
1502                while ((cur = strchr(ft->fh.name, 0x01))) {
1503                        *cur = G_DIR_SEPARATOR;
1504                }
1505        }
1506        return userfunc(sess, NULL, conn, &(ft->fh));
1507}
1508
1509
1510/*
1511 * These were originally described by Josh Myer:
1512 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/
1513 * XXX this doesn't actually work yet
1514 * -- wtm
1515 */
1516static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1517        aim_frame_t *newoft;
1518        aim_msgcookie_t *cook;
1519        struct aim_fileheader_t *fh;
1520        struct aim_filetransfer_priv *ft;
1521
1522        fh = aim_oft_getfh(bs);
1523        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1524                free(fh);
1525                return -1;
1526        }
1527        ft = (struct aim_filetransfer_priv *)cook->data;
1528
1529        ft->fh.nrecvd = fh->nrecvd;
1530        ft->fh.recvcsum = fh->recvcsum;
1531        strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
1532        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
1533                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1534                free(fh);
1535                return -1;
1536        }
1537
1538        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1539                aim_frame_destroy(newoft);
1540                free(fh);
1541                return -1;
1542        }
1543        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1544        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1545
1546        aim_tx_enqueue(sess, newoft);
1547        free(fh);
1548
1549        return 0;
1550}
1551
1552/* We are sending a file, and the buddy sent us this header indicating
1553 * that he or she is ready for the raw data.
1554 */
1555static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1556        struct aim_fileheader_t *fh;
1557        aim_msgcookie_t *cook;
1558        int ret = 1;
1559        struct aim_filetransfer_priv *ft;
1560        aim_rxcallback_t userfunc;
1561       
1562        fh = aim_oft_getfh(bs);
1563        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1564                free(fh);
1565                return -1;
1566        }
1567        ft = (struct aim_filetransfer_priv *)cook->data;
1568
1569        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILESEND)) )
1570                ret = userfunc(sess, NULL, conn, &(ft->fh));
1571
1572        free(fh);
1573
1574        return ret;
1575}
1576
1577static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1578{
1579#if 0
1580        struct aim_fileheader_t *fh;
1581        struct aim_msgcookie_t *cook;
1582        int ret = 1;
1583        aim_rxcallback_t userfunc;
1584        struct aim_filetransfer_priv *ft;
1585
1586        fh = aim_oft_getfh(hdr);
1587
1588        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1589                free(fh);
1590                return -1;
1591        }
1592
1593        ft = cook->data;
1594
1595        faimdprintf(sess, 2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n");
1596
1597        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) )
1598                ret = userfunc(sess, NULL, conn, fh);
1599
1600        free(fh);
1601
1602        return ret;
1603#else
1604        return -1;
1605#endif
1606}
1607
1608/* We just sent the raw data of a file, and the buddy sent us back this
1609 * header indicating that the transfer is complete.
1610 */
1611static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1612{
1613        struct aim_fileheader_t *fh;
1614        aim_msgcookie_t *cook;
1615        aim_rxcallback_t userfunc;
1616
1617        fh = aim_oft_getfh(bs);
1618
1619        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1620                free(fh);
1621                return -1;
1622        }
1623
1624        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILECOMPLETE)) )
1625                userfunc(sess, NULL, conn, fh->bcookie);
1626
1627        free(fh);
1628        return 0;
1629}
1630
1631static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1632{
1633#if 0
1634        struct aim_fileheader_t *fh;
1635        aim_rxcallback_t userfunc;
1636
1637        fh = aim_oft_getfh(hdr);
1638
1639        faimdprintf(sess, 2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n");
1640
1641        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) )
1642                userfunc(sess, NULL, conn, fh);
1643
1644        free(fh);
1645#endif
1646
1647        return -1;
1648}
1649
1650faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
1651{
1652        aim_conn_t *conn = fr->conn;
1653        aim_bstream_t *bs = &fr->data;
1654        int ret = -1;
1655
1656        if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1657                /* This should never happen. -- wtm */
1658                return getcommand_getfile(sess, conn);
1659
1660        } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
1661                switch(fr->hdr.rend.type) {
1662                        case AIM_OFT_PROTO_OFFER:
1663                                ret = handlehdr_sendfile_sending(sess, conn, bs);
1664                                break;
1665                        case AIM_OFT_PROTO_RESUME:
1666                                ret = handlehdr_sendfile_resume(sess, conn, bs);
1667                                break;
1668                        case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */;
1669                        case AIM_OFT_PROTO_ACCEPT:
1670                                ret = handlehdr_sendfile_recv(sess, conn, bs);
1671                                break;
1672                        case AIM_OFT_PROTO_ACK:
1673                                ret = handlehdr_sendfile_finish(sess, conn, bs);
1674                                break;
1675                        default:
1676                                faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type);
1677                                ret = -1;
1678                                break;
1679                }
1680
1681        } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
1682                if (fr->hdr.rend.type == 0x0001)
1683                        ret = handlehdr_directim(sess, conn, bs);
1684                else
1685                        faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type);
1686
1687        } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1688                /* This _really_ shouldn't happen. :) -- wtm */
1689                char *hdr = NULL;
1690                int hdrtype = fr->hdr.rend.type;
1691                if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
1692                        ret = handlehdr_getfile_listing(sess, conn, hdr);
1693                else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
1694                        ret = handlehdr_getfile_listing2(sess, conn, hdr);
1695                else if (hdrtype == 0x120b) /* get file listing rx confirm */
1696                        ret = handlehdr_getfile_listing3(sess, conn, hdr);
1697                else if (hdrtype == 0x120c) /* getfile request */
1698                        ret = handlehdr_getfile_request(sess, conn, hdr);
1699                else if (hdrtype == 0x0101) /* getfile sending data */
1700                        ret = handlehdr_getfile_sending(sess, conn, hdr);
1701                else if (hdrtype == 0x0202) /* getfile recv data */
1702                        ret = handlehdr_getfile_recv(sess, conn, hdr);
1703                else if (hdrtype == 0x0204) /* getfile finished */
1704                        ret = handlehdr_getfile_finish(sess, conn, hdr);
1705                else {
1706                        faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
1707                        ret = -1;
1708                }
1709        }
1710       
1711        if (ret == -1)
1712                aim_conn_close(conn);
1713
1714        return ret;
1715}
1716
1717/**
1718 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr.
1719 * @bs: bstream to extract header from
1720 *
1721 * returns pointer to new struct on success; %NULL on error.
1722 *
1723 */
1724static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
1725{
1726        struct aim_fileheader_t *fh;
1727
1728        if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
1729                return NULL;
1730
1731        /* The bstream should be positioned after the hdrtype. */
1732        aimbs_getrawbuf(bs, fh->bcookie, 8);
1733        fh->encrypt = aimbs_get16(bs);
1734        fh->compress = aimbs_get16(bs);
1735        fh->totfiles = aimbs_get16(bs);
1736        fh->filesleft = aimbs_get16(bs);
1737        fh->totparts = aimbs_get16(bs);
1738        fh->partsleft = aimbs_get16(bs);
1739        fh->totsize = aimbs_get32(bs);
1740        fh->size = aimbs_get32(bs);
1741        fh->modtime = aimbs_get32(bs);
1742        fh->checksum = aimbs_get32(bs);
1743        fh->rfrcsum = aimbs_get32(bs);
1744        fh->rfsize = aimbs_get32(bs);
1745        fh->cretime = aimbs_get32(bs);
1746        fh->rfcsum = aimbs_get32(bs);
1747        fh->nrecvd = aimbs_get32(bs);
1748        fh->recvcsum = aimbs_get32(bs);
1749        aimbs_getrawbuf(bs, fh->idstring, 32);
1750        fh->flags = aimbs_get8(bs);
1751        fh->lnameoffset = aimbs_get8(bs);
1752        fh->lsizeoffset = aimbs_get8(bs);
1753        aimbs_getrawbuf(bs, fh->dummy, 69);
1754        aimbs_getrawbuf(bs, fh->macfileinfo, 16);
1755        fh->nencode = aimbs_get16(bs);
1756        fh->nlanguage = aimbs_get16(bs);
1757        aimbs_getrawbuf(bs, fh->name, 64); /* XXX */
1758
1759        return fh;
1760} 
1761
1762/**
1763 * aim_oft_checksum - calculate oft checksum of buffer
1764 * @buffer: buffer of data to checksum
1765 * @bufsize: size of buffer
1766 * @prevcheck: previous checksum
1767 *
1768 * Prevcheck should be 0xFFFF0000 for each new file; you can have this
1769 * checksum chunks of files in series if you just call it repeatedly in a
1770 * for(; ; ) loop and don't reset the checksum between each call. And you
1771 * thought we didn't care about you and your pathetic client's meomry
1772 * footprint ;^)
1773 *
1774 * Thanks to Graham Booker for providing this improved checksum
1775 * routine, which is simpler and should be more accurate than Josh
1776 * Myer's original code. -- wtm
1777 *
1778 * This algorithim works every time I have tried it.  The other fails
1779 * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
1780 * checksum I have ever seen.
1781 */
1782faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) {
1783        fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
1784        int i;
1785        unsigned short val;
1786
1787        for (i=0; i<bufferlen; i++) {
1788                oldcheck = check;
1789                if (i&1) {
1790                        val = buffer[i];
1791                } else {
1792                        val = buffer[i] << 8;
1793                }
1794                check -= val;
1795                /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */
1796                if (check > oldcheck) {
1797                        check--;
1798                }
1799        }
1800        check = ((check & 0x0000ffff) + (check >> 16));
1801        check = ((check & 0x0000ffff) + (check >> 16));
1802        return check << 16;
1803}
1804
1805faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
1806                const unsigned char *buffer, int len) {
1807        struct aim_filetransfer_priv *ft = conn->internal;
1808
1809        ft->fh.nrecvd += len;
1810        ft->fh.recvcsum = aim_oft_checksum(buffer, len, ft->fh.recvcsum);
1811
1812        return 0;
1813}
1814
1815/**
1816 * aim_oft_buildheader - fills a buffer with network-order fh data
1817 * @bs: bstream to fill -- automatically initialized
1818 * @fh: fh to get data from
1819 *
1820 * returns -1 on error.
1821 *
1822 */
1823static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
1824{ 
1825        fu8_t *hdr;
1826
1827        if (!bs || !fh)
1828                return -1;
1829
1830
1831
1832
1833        if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
1834                return -1;
1835        }
1836        aim_bstream_init(bs, hdr, 0x100 - 8);
1837
1838        aimbs_putraw(bs, fh->bcookie, 8);
1839        aimbs_put16(bs, fh->encrypt);
1840        aimbs_put16(bs, fh->compress);
1841        aimbs_put16(bs, fh->totfiles);
1842        aimbs_put16(bs, fh->filesleft);
1843        aimbs_put16(bs, fh->totparts);
1844        aimbs_put16(bs, fh->partsleft);
1845        aimbs_put32(bs, fh->totsize);
1846        aimbs_put32(bs, fh->size);
1847        aimbs_put32(bs, fh->modtime);
1848        aimbs_put32(bs, fh->checksum);
1849        aimbs_put32(bs, fh->rfrcsum);
1850        aimbs_put32(bs, fh->rfsize);
1851        aimbs_put32(bs, fh->cretime);
1852        aimbs_put32(bs, fh->rfcsum);
1853        aimbs_put32(bs, fh->nrecvd);
1854        aimbs_put32(bs, fh->recvcsum);
1855        aimbs_putraw(bs, fh->idstring, 32);
1856        aimbs_put8(bs, fh->flags);
1857        aimbs_put8(bs, fh->lnameoffset);
1858        aimbs_put8(bs, fh->lsizeoffset);
1859        aimbs_putraw(bs, fh->dummy, 69);
1860        aimbs_putraw(bs, fh->macfileinfo, 16);
1861        aimbs_put16(bs, fh->nencode);
1862        aimbs_put16(bs, fh->nlanguage);
1863        aimbs_putraw(bs, fh->name, 64);
1864
1865        /* XXX: Filenames longer than 64B */
1866        return 0;
1867}
1868
1869/**
1870 * aim_getfile_intitiate - Request an OFT getfile session
1871 * @sess: your session,
1872 * @conn: the BOS conn,
1873 * @destsn is the SN to connect to.
1874 *
1875 * returns a new &aim_conn_t on success, %NULL on error
1876 */
1877faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn)
1878{ 
1879        return NULL;
1880#if 0
1881        struct command_tx_struct *newpacket;
1882        struct aim_conn_t *newconn;
1883        struct aim_filetransfer_priv *priv;
1884        struct aim_msgcookie_t *cookie;
1885        int curbyte, i, listenfd;
1886        short port = 4443;
1887        struct hostent *hptr;
1888        struct utsname myname;
1889        char cap[16];
1890        char d[4];
1891
1892        /* Open our socket */
1893
1894        if ( (listenfd = aim_listenestablish(port)) == -1)
1895                return NULL;
1896
1897        /* get our local IP */
1898
1899        if (uname(&myname) < 0)
1900                return NULL;
1901        if ( (hptr = gethostbyname(myname.nodename)) == NULL)
1902                return NULL;
1903        memcpy(&d, hptr->h_addr_list[0], 4);
1904
1905        aim_putcap(cap, 16, AIM_CAPS_GETFILE);
1906
1907        /* create the OSCAR packet */
1908
1909        if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
1910                return NULL;
1911        newpacket->lock = 1;
1912
1913        /* lock struct */
1914        curbyte = 0;
1915        curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
1916
1917        /* XXX: check the cookie before commiting to using it */
1918
1919        /* Generate a random message cookie
1920         * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
1921        for (i=0; i<7; i++)
1922                curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
1923
1924        curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1925
1926        /* grab all the data for cookie caching. */
1927 
1928        if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
1929                return NULL;
1930        memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
1931        cookie->type = AIM_COOKIETYPE_OFTGET;
1932
1933        if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
1934                return NULL;
1935        memcpy(priv->cookie, cookie, 8);
1936        memcpy(priv->sn, destsn, sizeof(priv->sn));
1937        memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
1938        priv->state = 1;
1939
1940        cookie->data = priv;
1941
1942        aim_cachecookie(sess, cookie);
1943
1944        /* Channel ID */
1945        curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
1946
1947        /* Destination SN (prepended with byte length) */
1948        curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
1949        curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
1950        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1951        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1952
1953        /* enTLV start */
1954        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1955        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
1956
1957        /* Flag data / ICBM Parameters? */
1958        curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1959        curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1960
1961        /* Cookie */
1962        curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
1963
1964        /* Capability String */
1965        curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
1966
1967        /* 000a/0002 : 0001 */
1968        curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
1969        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1970        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
1971
1972        /* 0003/0004: IP address */
1973        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1974        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
1975        for (i = 0; i < 4; i++)
1976        curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
1977
1978        /* already in network byte order */
1979 
1980        /* 0005/0002: Port */
1981        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1982        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1983        curbyte += aimutil_put16(newpacket->data+curbyte, port);
1984
1985        /* 000f/0000: ?? */
1986        curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
1987        curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1988
1989        /* 2711/000c: ?? */
1990        curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
1991        curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
1992        curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
1993
1994        for (i = 0; i < 0x000c - 4; i++)
1995                curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1996
1997        newpacket->commandlen = curbyte;
1998        newpacket->lock = 0;
1999        aim_tx_enqueue(sess, newpacket);
2000
2001        /* allocate and set up our connection */
2002
2003        i = fcntl(listenfd, F_GETFL, 0);
2004        fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
2005        newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
2006
2007        if (!newconn){
2008                perror("aim_newconn");
2009                return NULL;
2010        }
2011
2012        newconn->fd = listenfd;
2013        newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
2014        newconn->internal = priv;
2015        faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
2016
2017        return newconn;
2018#endif
2019}
2020 
2021/**
2022 * aim_oft_getfile_request - request a particular file over an established getfile connection
2023 * @sess: your session
2024 * @conn: the established OFT getfile connection
2025 * @name: filename to request
2026 * @size: size of the file
2027 *
2028 *
2029 * returns -1 on error, 0 on successful enqueuing
2030 */
2031#if 0
2032faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size)
2033{
2034        aim_frame_t *newoft;
2035        struct aim_filetransfer_priv *ft;
2036        if (!sess || !conn || !conn->priv || !name)
2037                return -1;
2038
2039        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
2040                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2041                return -1;
2042        }
2043        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
2044        newoft->hdr.oft.hdr2len = 0x100 - 8;
2045
2046        ft = (struct aim_filetransfer_priv *)conn->priv;
2047        ft->fh.filesleft = 1;
2048        ft->fh.totfiles = 1;
2049        ft->fh.totparts = 1;
2050        ft->fh.partsleft = 1;
2051        ft->fh.totsize = size;
2052        ft->fh.size = size;
2053        ft->fh.checksum = 0;
2054        memcpy(ft->fh.name, name, strlen(name));
2055        memset(ft->fh.name+strlen(name), 0, 1);
2056
2057        if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
2058                aim_frame_destroy(newoft);
2059                return -1;
2060        }
2061
2062        if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
2063                aim_frame_destroy(newoft);
2064                return -1;
2065        }
2066
2067        aim_tx_enqueue(sess, newoft);
2068        return 0;
2069}
2070#endif
2071
2072/* Identify a file that we are about to send by transmitting the
2073 * appropriate header.
2074 */
2075faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize)
2076{
2077        aim_frame_t *newoft;
2078        aim_msgcookie_t *cook;
2079        struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
2080        struct aim_fileheader_t *fh;
2081
2082        if (!sess || !conn || !filename)
2083                return -1;
2084
2085        if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
2086                return -1;
2087
2088#ifdef DUMB_OFT_CHECKSUM
2089        /* Yes, we are supposed to checksum the whole file before sending, and
2090         * yes, it's dumb.  This is the only way to get some clients (such as
2091         * Mac AIM v4.5.163) to successfully complete the transfer.  With
2092         * the WinAIM clients, we seem to be able to get away with just
2093         * setting the checksum to zero.
2094         * -- wtm
2095         */
2096        {
2097                int fd = open(filename, O_RDONLY);
2098                if (fd >= 0) {
2099                        int bytes;
2100                        char buf[1024];
2101                        fh->checksum = 0xffff0000;
2102                        while ((bytes = aim_recv(fd, buf, 1024)) > 0) {
2103                                fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
2104                        }
2105                }
2106                close(fd);
2107        }
2108#else
2109        fh->checksum = 0x00000000;
2110#endif
2111        fh->encrypt = 0x0000;
2112        fh->compress = 0x0000;
2113        fh->totfiles = numfiles;
2114        fh->filesleft = numfiles - filesdone;
2115        fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */
2116        fh->partsleft = 0x0001;
2117        fh->totsize = totsize;
2118        fh->size = size;
2119        fh->modtime = (int)time(NULL); /* we'll go with current time for now */
2120        /* fh->checksum set above */
2121        fh->rfcsum = 0x00000000;
2122        fh->rfsize = 0x00000000;
2123        fh->cretime = 0x00000000;
2124        fh->rfcsum = 0x00000000;
2125        fh->nrecvd = 0x00000000; /* always zero initially */
2126        fh->recvcsum= 0x00000000; /* ditto */
2127
2128        strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
2129        fh->flags = 0x02;
2130        fh->lnameoffset = 0x1a;
2131        fh->lsizeoffset = 0x10;
2132        memset(fh->dummy, 0, sizeof(fh->dummy));
2133        memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
2134
2135        /* apparently 0 is ASCII, 2 is UCS-2 */
2136        /* it is likely that 3 is ISO 8859-1 */
2137        fh->nencode = 0x0000;
2138        fh->nlanguage = 0x0000;
2139
2140        /* Convert the directory separator to ^A for portability. */
2141        strncpy(fh->name, filename, sizeof(fh->name));
2142        oft_dirconvert(fh->name);
2143
2144        /* XXX we should normally send a null cookie here, and make
2145         * the receiver fill it in for authentication -- wtm
2146         */
2147        memcpy(fh->bcookie, ft->cookie, 8);
2148
2149        if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
2150                return -1;
2151        }
2152
2153        /* Update both headers to be safe. */
2154        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
2155        memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t));
2156
2157        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
2158                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2159                free(fh);
2160                return -1;
2161        }
2162
2163        if (aim_oft_buildheader(&newoft->data, fh) == -1) {
2164                aim_frame_destroy(newoft);
2165                free(fh);
2166                return -1;
2167        }
2168
2169        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
2170        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
2171
2172        aim_tx_enqueue(sess, newoft);
2173        free(fh);
2174        return 0;
2175}
2176 
2177/**
2178 * aim_oft_getfile_ack - acknowledge a getfile download as complete
2179 * @sess: your session
2180 * @conn: the getfile conn to send the ack over
2181 *
2182 * Call this function after you have read all the data in a particular
2183 * filetransfer. Returns -1 on error, 0 on apparent success
2184 *
2185 */
2186faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) 
2187{
2188        return -EINVAL;
2189#if 0
2190        struct command_tx_struct *newoft;
2191        struct aim_filetransfer_priv *ft;
2192
2193        if (!sess || !conn || !conn->priv)
2194                return -1;
2195
2196        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
2197                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2198        return -1;
2199        }
2200
2201        newoft->lock = 1;
2202
2203        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
2204        newoft->hdr.oft.hdr2len = 0x100-8;
2205
2206        if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
2207                newoft->lock = 0;
2208                aim_frame_destroy(newoft);
2209                return -1;
2210        }
2211
2212        ft = (struct aim_filetransfer_priv *)conn->priv;
2213
2214        if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
2215                newoft->lock = 0;
2216                aim_frame_destroy(newoft);
2217                return -1;
2218        }
2219
2220        newoft->lock = 0;
2221        aim_tx_enqueue(sess, newoft);
2222        return 0;
2223#endif
2224}
2225 
2226/**
2227 * aim_oft_end - end a getfile/sendfile.
2228 * @sess: your session
2229 * @conn: the getfile connection
2230 *
2231 * call this before you close the getfile connection if you're on the
2232 * receiving/requesting end.
2233 */
2234faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn)
2235{
2236        aim_frame_t *newoft;
2237        struct aim_filetransfer_priv *ft;
2238
2239        if (!sess || !conn || !conn->internal)
2240                return -1;
2241
2242        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) {
2243                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2244                return -1;
2245        }
2246
2247        ft = (struct aim_filetransfer_priv *)conn->internal;
2248        ft->state = 4; /* no longer wanting data */
2249        ft->fh.flags = 0x21;
2250
2251        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
2252                aim_frame_destroy(newoft);
2253                return -1;
2254        }
2255        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
2256        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
2257
2258        aim_tx_enqueue(sess, newoft);
2259
2260        return 0;
2261}
2262
2263/*
2264 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability.
2265 */
2266static void oft_dirconvert(char *name) {
2267        char *c = name;
2268        while ((c = strchr(c, G_DIR_SEPARATOR)))
2269                *c = 0x01;
2270}
Note: See TracBrowser for help on using the repository browser.