Changeset e374dee for libfaim/ft.c


Ignore:
Timestamp:
Oct 10, 2003, 5:12:30 PM (18 years ago)
Author:
James M. Kretchmar <kretch@mit.edu>
Branches:
master, barnowl_perlaim, debian, owl, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
fe6f1d3
Parents:
f4d0975
Message:
*** empty log message ***
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libfaim/ft.c

    r862371b re374dee  
    11/*
    2  * File transfer (OFT) and DirectIM (ODC).
    3  * (OSCAR File Transfer, Oscar Direct Connect(ion?)
     2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC).
     3 * (ODC is also referred to as DirectIM and IM Image.)
     4 *
     5 * There are a few static helper functions at the top, then
     6 * ODC stuff, then ft stuff.
     7 *
     8 * I feel like this is a good place to explain OFT, so I'm going to
     9 * do just that.  Each OFT packet has a header type.  I guess this
     10 * is pretty similar to the subtype of a SNAC packet.  The type
     11 * basically tells the other client the meaning of the OFT packet. 
     12 * There are two distinct types of file transfer, which I usually
     13 * call "sendfile" and "getfile."  Sendfile is when you send a file
     14 * to another AIM user.  Getfile is when you share a group of files,
     15 * and other users request that you send them the files.
     16 *
     17 * A typical sendfile file transfer goes like this:
     18 *   1) Sender sends a channel 2 ICBM telling the other user that
     19 *      we want to send them a file.  At the same time, we open a
     20 *      listener socket (this should be done before sending the
     21 *      ICBM) on some port, and wait for them to connect to us. 
     22 *      The ICBM we sent should contain our IP address and the port
     23 *      number that we're listening on.
     24 *   2) The receiver connects to the sender on the given IP address
     25 *      and port.  After the connection is established, the receiver
     26 *      sends an ICBM signifying that we are ready and waiting.
     27 *   3) The sender sends an OFT PROMPT message over the OFT
     28 *      connection.
     29 *   4) The receiver of the file sends back an exact copy of this
     30 *      OFT packet, except the cookie is filled in with the cookie
     31 *      from the ICBM.  I think this might be an attempt to verify
     32 *      that the user that is connected is actually the guy that
     33 *      we sent the ICBM to.  Oh, I've been calling this the ACK.
     34 *   5) The sender starts sending raw data across the connection
     35 *      until the entire file has been sent.
     36 *   6) The receiver knows the file is finished because the sender
     37 *      sent the file size in an earlier OFT packet.  So then the
     38 *      receiver sends the DONE thingy (after filling in the
     39 *      "received" checksum and size) and closes the connection.
    440 */
    541
    642#define FAIM_INTERNAL
    7 
    843#ifdef HAVE_CONFIG_H
    9 #include <config.h>
     44#include  <config.h>
    1045#endif
     46
    1147#include <aim.h>
    1248
    1349#ifndef _WIN32
     50#include <stdio.h>
    1451#include <netdb.h>
    1552#include <sys/socket.h>
    1653#include <netinet/in.h>
    17 #include <sys/utsname.h> /* for aim_directim_initiate */
     54#include <sys/utsname.h> /* for aim_odc_initiate */
    1855#include <arpa/inet.h> /* for inet_ntoa */
    1956#define G_DIR_SEPARATOR '/'
     
    2461#endif
    2562
    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 
    32 struct 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 
    40 struct aim_directim_intdata {
     63struct aim_odc_intdata {
    4164        fu8_t cookie[8];
    4265        char sn[MAXSNLEN+1];
     
    4467};
    4568
    46 static int listenestablish(fu16_t portnum);
    47 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs);
    48 static void oft_dirconvert(char *name);
    49 static 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  */
    62 faim_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  */
    146 faim_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  */
    219 faim_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 
    294 static 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  */
    321 faim_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  */
    381 faim_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  */
    443 faim_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 
    464 faim_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  */
    495 faim_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  */
    537 faim_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  */
    578 faim_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;
     69/**
     70 * Convert the directory separator from / (0x2f) to ^A (0x01)
     71 *
     72 * @param name The filename to convert.
     73 */
     74static void aim_oft_dirconvert_tostupid(char *name)
     75{
     76        while (name[0]) {
     77                if (name[0] == 0x01)
     78                        name[0] = G_DIR_SEPARATOR;
     79                name++;
     80        }
     81}
     82
     83/**
     84 * Convert the directory separator from ^A (0x01) to / (0x2f)
     85 *
     86 * @param name The filename to convert.
     87 */
     88static void aim_oft_dirconvert_fromstupid(char *name)
     89{
     90        while (name[0]) {
     91                if (name[0] == G_DIR_SEPARATOR)
     92                        name[0] = 0x01;
     93                name++;
     94        }
     95}
     96
     97/**
     98 * Calculate oft checksum of buffer
     99 *
     100 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file.  The
     101 * checksum is kind of a rolling checksum thing, so each time you get bytes
     102 * of a file you just call this puppy and it updates the checksum.  You can
     103 * calculate the checksum of an entire file by calling this in a while or a
     104 * for loop, or something.
     105 *
     106 * Thanks to Graham Booker for providing this improved checksum routine,
     107 * which is simpler and should be more accurate than Josh Myer's original
     108 * code. -- wtm
     109 *
     110 * This algorithim works every time I have tried it.  The other fails
     111 * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
     112 * checksum I have ever seen.
     113 *
     114 * @param buffer Buffer of data to checksum.  Man I'd like to buff her...
     115 * @param bufsize Size of buffer.
     116 * @param prevcheck Previous checksum.
     117 */
     118faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck)
     119{
     120        fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
    585121        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 */
    747 faim_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  */
    788 faim_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
     122        unsigned short val;
     123
     124        for (i=0; i<bufferlen; i++) {
     125                oldcheck = check;
     126                if (i&1)
     127                        val = buffer[i];
     128                else
     129                        val = buffer[i] << 8;
     130                check -= val;
     131                /*
     132                 * The following appears to be necessary.... It happens
     133                 * every once in a while and the checksum doesn't fail.
     134                 */
     135                if (check > oldcheck)
     136                        check--;
     137        }
     138        check = ((check & 0x0000ffff) + (check >> 16));
     139        check = ((check & 0x0000ffff) + (check >> 16));
     140        return check << 16;
     141}
     142
     143faim_export fu32_t aim_oft_checksum_file(char *filename) {
     144        FILE *fd;
     145        fu32_t checksum = 0xffff0000;
     146
     147        if ((fd = fopen(filename, "rb"))) {
     148                int bytes;
     149                fu8_t buffer[1024];
     150
     151                while ((bytes = fread(buffer, 1, 1024, fd)))
     152                        checksum = aim_oft_checksum_chunk(buffer, bytes, checksum);
     153                fclose(fd);
     154        }
     155
     156        return checksum;
     157}
     158
     159/**
     160 * Create a listening socket on a given port.
     161 *
     162 * XXX - Give the client author the responsibility of setting up a
     163 *       listener, then we no longer have a libfaim problem with broken
     164 *       solaris *innocent smile* -- jbm
     165 *
     166 * @param portnum The port number to bind to.
     167 * @return The file descriptor of the listening socket.
    907168 */
    908169static int listenestablish(fu16_t portnum)
     
    919180        hints.ai_family = AF_UNSPEC;
    920181        hints.ai_socktype = SOCK_STREAM;
    921         if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) {
     182        if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) {
    922183                perror("getaddrinfo");
    923184                return -1;
     
    930191                setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    931192                if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
    932                         break;
    933                 /* success */
     193                        break; /* success */
    934194                close(listenfd);
    935195        } while ( (res = res->ai_next) );
     
    938198                return -1;
    939199
    940         if (listen(listenfd, 1024)!=0) {
    941                 perror("listen");
    942                 return -1;
    943         }
    944 
    945         fcntl(listenfd, F_SETFL, O_NONBLOCK);
    946 
    947200        freeaddrinfo(ressave);
    948         return listenfd;
    949201#else
    950202        int listenfd;
     
    953205
    954206        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    955                 perror("socket(listenfd)");
     207                perror("socket");
    956208                return -1;
    957209        }
    958210
    959211        if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
    960                 perror("setsockopt(listenfd)");
     212                perror("setsockopt");
    961213                close(listenfd);
    962214                return -1;
    963         } 
     215        }
    964216
    965217        memset(&sockin, 0, sizeof(struct sockaddr_in));
     
    968220
    969221        if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
    970                 perror("bind(listenfd)");
     222                perror("bind");
    971223                close(listenfd);
    972224                return -1;
    973225        }
     226#endif
     227
    974228        if (listen(listenfd, 4) != 0) {
    975                 perror("listen(listenfd)");
     229                perror("listen");
    976230                close(listenfd);
    977231                return -1;
    978232        }
    979233        fcntl(listenfd, F_SETFL, O_NONBLOCK);
     234
    980235        return listenfd;
     236}
     237
     238/**
     239 * After establishing a listening socket, this is called to accept a connection.  It
     240 * clones the conn used by the listener, and passes both of these to a signal handler.
     241 * The signal handler should close the listener conn and keep track of the new conn,
     242 * since this is what is used for file transfers and what not.
     243 *
     244 * @param sess The session.
     245 * @param cur The conn the incoming connection is on.
     246 * @return Return 0 if no errors, otherwise return the error number.
     247 */
     248faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur)
     249{
     250        int acceptfd = 0;
     251        struct sockaddr addr;
     252        socklen_t addrlen = sizeof(addr);
     253        int ret = 0;
     254        aim_conn_t *newconn;
     255        char ip[20];
     256        int port;
     257
     258        if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1)
     259                return 0; /* not an error */
     260
     261        if (addr.sa_family != AF_INET) { /* just in case IPv6 really is happening */
     262                close(acceptfd);
     263                aim_conn_close(cur);
     264                return -1;
     265        }
     266
     267        strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip));
     268        port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
     269
     270        if (!(newconn = aim_cloneconn(sess, cur))) {
     271                close(acceptfd);
     272                aim_conn_close(cur);
     273                return -ENOMEM;
     274        }
     275
     276        newconn->type = AIM_CONN_TYPE_RENDEZVOUS;
     277        newconn->fd = acceptfd;
     278
     279        if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
     280                aim_rxcallback_t userfunc;
     281                struct aim_odc_intdata *priv;
     282
     283                priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal);
     284                cur->internal = NULL;
     285                snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port);
     286
     287                if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED)))
     288                        ret = userfunc(sess, NULL, newconn, cur);
     289
     290        } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
     291        } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
     292                aim_rxcallback_t userfunc;
     293
     294                if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED)))
     295                        ret = userfunc(sess, NULL, newconn, cur);
     296
     297        } else {
     298                faimdprintf(sess, 1,"Got a connection on a listener that's not rendezvous.  Closing connection.\n");
     299                aim_conn_close(newconn);
     300                ret = -1;
     301        }
     302
     303        return ret;
     304}
     305
     306/**
     307 * Send client-to-client typing notification over an established direct connection.
     308 *
     309 * @param sess The session.
     310 * @param conn The already-connected ODC connection.
     311 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and
     312 *        0x0000 sends "stopped."
     313 * @return Return 0 if no errors, otherwise return the error number.
     314 */
     315faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
     316{
     317        struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
     318        aim_frame_t *fr;
     319        aim_bstream_t *hdrbs;
     320        fu8_t *hdr;
     321        int hdrlen = 0x44;
     322
     323        if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
     324                return -EINVAL;
     325
     326        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, 0)))
     327                return -ENOMEM;
     328        memcpy(fr->hdr.rend.magic, "ODC2", 4);
     329        fr->hdr.rend.hdrlen = hdrlen;
     330
     331        if (!(hdr = calloc(1, hdrlen))) {
     332                aim_frame_destroy(fr);
     333                return -ENOMEM;
     334        }
     335
     336        hdrbs = &(fr->data);
     337        aim_bstream_init(hdrbs, hdr, hdrlen);
     338
     339        aimbs_put16(hdrbs, 0x0006);
     340        aimbs_put16(hdrbs, 0x0000);
     341        aimbs_putraw(hdrbs, intdata->cookie, 8);
     342        aimbs_put16(hdrbs, 0x0000);
     343        aimbs_put16(hdrbs, 0x0000);
     344        aimbs_put16(hdrbs, 0x0000);
     345        aimbs_put16(hdrbs, 0x0000);
     346        aimbs_put32(hdrbs, 0x00000000);
     347        aimbs_put16(hdrbs, 0x0000);
     348        aimbs_put16(hdrbs, 0x0000);
     349        aimbs_put16(hdrbs, 0x0000);
     350
     351        if (typing == 0x0002)
     352                aimbs_put16(hdrbs, 0x0002 | 0x0008);
     353        else if (typing == 0x0001)
     354                aimbs_put16(hdrbs, 0x0002 | 0x0004);
     355        else
     356                aimbs_put16(hdrbs, 0x0002);
     357
     358        aimbs_put16(hdrbs, 0x0000);
     359        aimbs_put16(hdrbs, 0x0000);
     360        aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
     361
     362        aim_bstream_setpos(hdrbs, 52); /* bleeehh */
     363
     364        aimbs_put8(hdrbs, 0x00);
     365        aimbs_put16(hdrbs, 0x0000);
     366        aimbs_put16(hdrbs, 0x0000);
     367        aimbs_put16(hdrbs, 0x0000);
     368        aimbs_put16(hdrbs, 0x0000);
     369        aimbs_put16(hdrbs, 0x0000);
     370        aimbs_put16(hdrbs, 0x0000);
     371        aimbs_put16(hdrbs, 0x0000);
     372        aimbs_put8(hdrbs, 0x00);
     373
     374        /* end of hdr */
     375
     376        aim_tx_enqueue(sess, fr);
     377
     378        return 0;
     379}
     380
     381/**
     382 * Send client-to-client IM over an established direct connection.
     383 * Call this just like you would aim_send_im, to send a directim.
     384 *
     385 * @param sess The session.
     386 * @param conn The already-connected ODC connection.
     387 * @param msg Null-terminated string to send.
     388 * @param len The length of the message to send, including binary data.
     389 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1.
     390 * @param isawaymsg 0 if this is not an auto-response, 1 if it is.
     391 * @return Return 0 if no errors, otherwise return the error number.
     392 */
     393faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg)
     394{
     395        aim_frame_t *fr;
     396        aim_bstream_t *hdrbs;
     397        struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
     398        int hdrlen = 0x44;
     399        fu8_t *hdr;
     400
     401        if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg)
     402                return -EINVAL;
     403
     404        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
     405                return -ENOMEM;
     406
     407        memcpy(fr->hdr.rend.magic, "ODC2", 4);
     408        fr->hdr.rend.hdrlen = hdrlen;
     409
     410        if (!(hdr = calloc(1, hdrlen + len))) {
     411                aim_frame_destroy(fr);
     412                return -ENOMEM;
     413        }
     414
     415        hdrbs = &(fr->data);
     416        aim_bstream_init(hdrbs, hdr, hdrlen + len);
     417
     418        aimbs_put16(hdrbs, 0x0006);
     419        aimbs_put16(hdrbs, 0x0000);
     420        aimbs_putraw(hdrbs, intdata->cookie, 8);
     421        aimbs_put16(hdrbs, 0x0000);
     422        aimbs_put16(hdrbs, 0x0000);
     423        aimbs_put16(hdrbs, 0x0000);
     424        aimbs_put16(hdrbs, 0x0000);
     425        aimbs_put32(hdrbs, len);
     426        aimbs_put16(hdrbs, encoding);
     427        aimbs_put16(hdrbs, 0x0000);
     428        aimbs_put16(hdrbs, 0x0000);
     429
     430        /* flags - used for typing notification and to mark if this is an away message */
     431        aimbs_put16(hdrbs, 0x0000 | isawaymsg);
     432
     433        aimbs_put16(hdrbs, 0x0000);
     434        aimbs_put16(hdrbs, 0x0000);
     435        aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
     436
     437        aim_bstream_setpos(hdrbs, 52); /* bleeehh */
     438
     439        aimbs_put8(hdrbs, 0x00);
     440        aimbs_put16(hdrbs, 0x0000);
     441        aimbs_put16(hdrbs, 0x0000);
     442        aimbs_put16(hdrbs, 0x0000);
     443        aimbs_put16(hdrbs, 0x0000);
     444        aimbs_put16(hdrbs, 0x0000);
     445        aimbs_put16(hdrbs, 0x0000);
     446        aimbs_put16(hdrbs, 0x0000);
     447        aimbs_put8(hdrbs, 0x00);
     448
     449        /* end of hdr2 */
     450
     451#if 0 /* XXX - this is how you send buddy icon info... */       
     452        aimbs_put16(hdrbs, 0x0008);
     453        aimbs_put16(hdrbs, 0x000c);
     454        aimbs_put16(hdrbs, 0x0000);
     455        aimbs_put16(hdrbs, 0x1466);
     456        aimbs_put16(hdrbs, 0x0001);
     457        aimbs_put16(hdrbs, 0x2e0f);
     458        aimbs_put16(hdrbs, 0x393e);
     459        aimbs_put16(hdrbs, 0xcac8);
    981460#endif
    982 }
    983 
    984 static 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;
     461        aimbs_putraw(hdrbs, msg, len);
     462
     463        aim_tx_enqueue(sess, fr);
     464
     465        return 0;
     466}
     467
     468/**
     469 * Get the screen name of the peer of a direct connection.
     470 *
     471 * @param conn The ODC connection.
     472 * @return The screen name of the dude, or NULL if there was an anomaly.
     473 */
     474faim_export const char *aim_odc_getsn(aim_conn_t *conn)
     475{
     476        struct aim_odc_intdata *intdata;
     477
     478        if (!conn || !conn->internal)
     479                return NULL;
     480
     481        if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
     482                        (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
     483                return NULL;
     484
     485        intdata = (struct aim_odc_intdata *)conn->internal;
     486
     487        return intdata->sn;
     488}
     489
     490/**
     491 * Find the conn of a direct connection with the given buddy.
     492 *
     493 * @param sess The session.
     494 * @param sn The screen name of the buddy whose direct connection you want to find.
     495 * @return The conn for the direct connection with the given buddy, or NULL if no
     496 *         connection was found.
     497 */
     498faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn)
     499{
     500        aim_conn_t *cur;
     501        struct aim_odc_intdata *intdata;
     502
     503        if (!sess || !sn || !strlen(sn))
     504                return NULL;
     505
     506        for (cur = sess->connlist; cur; cur = cur->next) {
     507                if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
     508                        intdata = cur->internal;
     509                        if (!aim_sncmp(intdata->sn, sn))
     510                                return cur;
    1009511                }
    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 
    1059 static 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 
    1070 static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn)
    1071 {
    1072         free(conn->internal);
    1073 
    1074         return;
    1075 }
    1076 
    1077 static 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 
    1089 static void connkill_getfile(aim_session_t *sess, aim_conn_t *conn)
    1090 {
    1091        
    1092         free(conn->internal);
    1093 
    1094         return;
    1095 }
    1096 
    1097 static 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 
    1108 static void connkill_directim(aim_session_t *sess, aim_conn_t *conn)
    1109 {
    1110        
    1111         free(conn->internal);
    1112 
    1113         return;
    1114 }
    1115 
    1116 faim_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 
    1132 faim_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 
    1148 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
     512        }
     513
     514        return NULL;
     515}
     516
     517/**
     518 * For those times when we want to open up the direct connection channel ourselves.
     519 *
     520 * You'll want to set up some kind of watcher on this socket. 
     521 * When the state changes, call aim_handlerendconnection with
     522 * the connection returned by this.  aim_handlerendconnection
     523 * will accept the pending connection and stop listening.
     524 *
     525 * @param sess The session
     526 * @param sn The screen name to connect to.
     527 * @return The new connection.
     528 */
     529faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn)
     530{
     531        aim_conn_t *newconn;
     532        aim_msgcookie_t *cookie;
     533        struct aim_odc_intdata *priv;
     534        int listenfd;
     535        fu16_t port = 4443;
     536        fu8_t localip[4];
     537        fu8_t ck[8];
     538
     539        if (aim_util_getlocalip(localip) == -1)
     540                return NULL;
     541
     542        if ((listenfd = listenestablish(port)) == -1)
     543                return NULL;
     544
     545        aim_im_sendch2_odcrequest(sess, ck, sn, localip, port);
     546
     547        cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
     548        memcpy(cookie->cookie, ck, 8);
     549        cookie->type = AIM_COOKIETYPE_OFTIM;
     550
     551        /* this one is for the cookie */
     552        priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
     553
     554        memcpy(priv->cookie, ck, 8);
     555        strncpy(priv->sn, sn, sizeof(priv->sn));
     556        cookie->data = priv;
     557        aim_cachecookie(sess, cookie);
     558
     559        /* XXX - switch to aim_cloneconn()? */
     560        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
     561                close(listenfd);
     562                return NULL;
     563        }
     564
     565        /* this one is for the conn */
     566        priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
     567
     568        memcpy(priv->cookie, ck, 8);
     569        strncpy(priv->sn, sn, sizeof(priv->sn));
     570
     571        newconn->fd = listenfd;
     572        newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
     573        newconn->internal = priv;
     574        newconn->lastactivity = time(NULL);
     575
     576        return newconn;
     577}
     578
     579/**
     580 * Connect directly to the given buddy for directim.
     581 *
     582 * This is a wrapper for aim_newconn.
     583 *
     584 * If addr is NULL, the socket is not created, but the connection is
     585 * allocated and setup to connect.
     586 *
     587 * @param sess The Godly session.
     588 * @param sn The screen name we're connecting to.  I hope it's a girl...
     589 * @param addr Address to connect to.
     590 * @return The new connection.
     591 */
     592faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie)
     593{
     594        aim_conn_t *newconn;
     595        struct aim_odc_intdata *intdata;
     596
     597        if (!sess || !sn)
     598                return NULL;
     599
     600        if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata))))
     601                return NULL;
     602        memcpy(intdata->cookie, cookie, 8);
     603        strncpy(intdata->sn, sn, sizeof(intdata->sn));
     604        if (addr)
     605                strncpy(intdata->ip, addr, sizeof(intdata->ip));
     606
     607        /* XXX - verify that non-blocking connects actually work */
     608        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) {
     609                free(intdata);
     610                return NULL;
     611        }
     612
     613        newconn->internal = intdata;
     614        newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
     615
     616        return newconn;
     617}
     618
     619/**
     620 * Sometimes you just don't know with these kinds of people.
     621 *
     622 * @param sess The session.
     623 * @param conn The ODC connection of the incoming data.
     624 * @param frr The frame allocated for the incoming data.
     625 * @param bs It stands for "bologna sandwich."
     626 * @return Return 0 if no errors, otherwise return the error number.
     627 */
     628static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs)
    1149629{
    1150630        aim_frame_t fr;
     631        int ret = 0;
    1151632        aim_rxcallback_t userfunc;
    1152633        fu32_t payloadlength;
     
    1156637        fr.conn = conn;
    1157638
    1158         /* XXX ugly */
     639        /* AAA - ugly */
    1159640        aim_bstream_setpos(bs, 20);
    1160641        payloadlength = aimbs_get32(bs);
     
    1167648
    1168649        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 
     650        /* XXX - create an aimbs_getnullstr function? */
     651        snptr = aimbs_getstr(bs, 32); /* Next 32 bytes contain the sn, padded with null chars */
     652
     653        faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr);
     654
     655        if (flags & 0x0008) {
     656                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
     657                        ret = userfunc(sess, &fr, snptr, 2);
     658        } else if (flags & 0x0004) {
     659                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
     660                        ret = userfunc(sess, &fr, snptr, 1);
     661        } else {
    1183662                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
    1184663                        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;
     664        }
     665
     666        if (payloadlength) {
     667                char *msg;
    1191668                int recvd = 0;
    1192                 int i;
    1193 
    1194                 if (!(msg = calloc(1, payloadlength+1)))
    1195                         return -1;
    1196                 msg2 = msg;
    1197                
     669                int i, isawaymsg;
     670
     671                isawaymsg = flags & 0x0001;
     672
     673                if (!(msg = calloc(1, payloadlength+1))) {
     674                        free(snptr);
     675                        return -ENOMEM;
     676                }
     677
    1198678                while (payloadlength - recvd) {
    1199679                        if (payloadlength - recvd >= 1024)
    1200                                 i = aim_recv(conn->fd, msg2, 1024);
     680                                i = aim_recv(conn->fd, &msg[recvd], 1024);
    1201681                        else
    1202                                 i = aim_recv(conn->fd, msg2, payloadlength - recvd);
     682                                i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd);
    1203683                        if (i <= 0) {
    1204684                                free(msg);
     685                                free(snptr);
    1205686                                return -1;
    1206687                        }
    1207688                        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);
     689                        if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
     690                                ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
    1211691                }
    1212692               
    1213                 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
    1214                         ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
     693                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)))
     694                        ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg);
    1215695
    1216696                free(msg);
    1217 
    1218                 return ret;
    1219         }
     697        }
     698
     699        free(snptr);
     700
     701        return ret;
     702}
     703
     704faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename)
     705{
     706        struct aim_oft_info *new;
     707
     708        if (!sess)
     709                return NULL;
     710
     711        if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info))))
     712                return NULL;
     713
     714        new->sess = sess;
     715        if (cookie)
     716                memcpy(new->cookie, cookie, 8);
     717        if (ip)
     718                new->clientip = strdup(ip);
     719        if (sn)
     720                new->sn = strdup(sn);
     721        new->port = port;
     722        new->fh.totfiles = 1;
     723        new->fh.filesleft = 1;
     724        new->fh.totparts = 1;
     725        new->fh.partsleft = 1;
     726        new->fh.totsize = size;
     727        new->fh.size = size;
     728        new->fh.modtime = modtime;
     729        new->fh.checksum = 0xffff0000;
     730        new->fh.rfrcsum = 0xffff0000;
     731        new->fh.rfcsum = 0xffff0000;
     732        new->fh.recvcsum = 0xffff0000;
     733        strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31);
     734        if (filename)
     735                strncpy(new->fh.name, filename, 63);
     736
     737        new->next = sess->oft_info;
     738        sess->oft_info = new;
     739
     740        return new;
     741}
     742
     743/**
     744 * Remove the given oft_info struct from the oft_info linked list, and
     745 * then free its memory.
     746 *
     747 * @param sess The session.
     748 * @param oft_info The aim_oft_info struct that we're destroying.
     749 * @return Return 0 if no errors, otherwise return the error number.
     750 */
     751faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info)
     752{
     753        aim_session_t *sess;
     754
     755        if (!oft_info || !(sess = oft_info->sess))
     756                return -EINVAL;
     757
     758        if (sess->oft_info && (sess->oft_info == oft_info)) {
     759                sess->oft_info = sess->oft_info->next;
     760        } else {
     761                struct aim_oft_info *cur;
     762                for (cur=sess->oft_info; (cur->next && (cur->next!=oft_info)); cur=cur->next);
     763                if (cur->next)
     764                        cur->next = cur->next->next;
     765        }
     766
     767        free(oft_info->sn);
     768        free(oft_info->proxyip);
     769        free(oft_info->clientip);
     770        free(oft_info->verifiedip);
     771        free(oft_info);
    1220772
    1221773        return 0;
    1222774}
    1223775
    1224 static 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 
    1282 static 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 
    1314 static 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 
    1342 static 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 
    1403 static 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)
     776/**
     777 * Creates a listener socket so the other dude can connect to us.
     778 *
     779 * You'll want to set up some kind of watcher on this socket. 
     780 * When the state changes, call aim_handlerendconnection with
     781 * the connection returned by this.  aim_handlerendconnection
     782 * will accept the pending connection and stop listening.
     783 *
     784 * @param sess The session.
     785 * @param oft_info File transfer information associated with this
     786 *        connection.
     787 * @return Return 0 if no errors, otherwise return the error number.
     788 */
     789faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info)
     790{
     791        int listenfd;
     792
     793        if (!oft_info)
     794                return -EINVAL;
     795
     796        if ((listenfd = listenestablish(oft_info->port)) == -1)
    1453797                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  */
    1463 static 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  */
    1516 static 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);
     798
     799        if (!(oft_info->conn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
     800                close(listenfd);
     801                return -ENOMEM;
     802        }
     803
     804        oft_info->conn->fd = listenfd;
     805        oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
     806        oft_info->conn->lastactivity = time(NULL);
    1548807
    1549808        return 0;
    1550809}
    1551810
    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  */
    1555 static 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 
    1577 static 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  */
    1611 static 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 
    1631 static 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 
    1650 faim_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  */
    1724 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
     811/**
     812 * Extract an &aim_fileheader_t from the given buffer.
     813 *
     814 * @param bs The should be from an incoming rendezvous packet.
     815 * @return A pointer to new struct on success, or NULL on error.
     816 */
     817static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs)
    1725818{
    1726819        struct aim_fileheader_t *fh;
     
    1755848        fh->nencode = aimbs_get16(bs);
    1756849        fh->nlanguage = aimbs_get16(bs);
    1757         aimbs_getrawbuf(bs, fh->name, 64); /* XXX */
     850        aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */
    1758851
    1759852        return fh;
     
    1761854
    1762855/**
    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  */
    1782 faim_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 
    1805 faim_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  *
     856 * Fills a buffer with network-order fh data
     857 *
     858 * @param bs A bstream to fill -- automatically initialized
     859 * @param fh A struct aim_fileheader_t to get data from.
     860 * @return Return non-zero on error.
    1822861 */
    1823862static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
     
    1826865
    1827866        if (!bs || !fh)
    1828                 return -1;
    1829 
    1830 
    1831 
    1832 
    1833         if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
    1834                 return -1;
    1835         }
     867                return -EINVAL;
     868
     869        if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8)))
     870                return -ENOMEM;
     871
    1836872        aim_bstream_init(bs, hdr, 0x100 - 8);
    1837 
    1838873        aimbs_putraw(bs, fh->bcookie, 8);
    1839874        aimbs_put16(bs, fh->encrypt);
     
    1861896        aimbs_put16(bs, fh->nencode);
    1862897        aimbs_put16(bs, fh->nlanguage);
    1863         aimbs_putraw(bs, fh->name, 64);
    1864 
    1865         /* XXX: Filenames longer than 64B */
     898        aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */
     899
    1866900        return 0;
    1867901}
    1868902
    1869903/**
    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  */
    1877 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn)
    1878 {
    1879         return NULL;
     904 * Create an OFT packet based on the given information, and send it on its merry way.
     905 *
     906 * @param sess The session.
     907 * @param type The subtype of the OFT packet we're sending.
     908 * @param oft_info The aim_oft_info struct with the connection and OFT
     909 *        info we're sending.
     910 * @return Return 0 if no errors, otherwise return the error number.
     911 */
     912faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info)
     913{
     914        aim_frame_t *fr;
     915
     916        if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS))
     917                return -EINVAL;
     918
    1880919#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
    2032 faim_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  */
    2075 faim_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
     920        /*
     921         * If you are receiving a file, the cookie should be null, if you are sending a
     922         * file, the cookie should be the same as the one used in the ICBM negotiation
     923         * SNACs.
    2095924         */
    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;
    2130925        fh->lnameoffset = 0x1a;
    2131926        fh->lsizeoffset = 0x10;
    2132         memset(fh->dummy, 0, sizeof(fh->dummy));
    2133         memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
    2134927
    2135928        /* apparently 0 is ASCII, 2 is UCS-2 */
    2136929        /* it is likely that 3 is ISO 8859-1 */
     930        /* I think "nlanguage" might be the same thing as "subenc" in im.c */
    2137931        fh->nencode = 0x0000;
    2138932        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);
     933#endif
     934
     935        aim_oft_dirconvert_tostupid(oft_info->fh.name);
     936
     937        if (!(fr = aim_tx_new(sess, oft_info->conn, AIM_FRAMETYPE_OFT, type, 0)))
     938                return -ENOMEM;
     939
     940        if (aim_oft_buildheader(&fr->data, &oft_info->fh) == -1) {
     941                aim_frame_destroy(fr);
     942                return -ENOMEM;
     943        }
     944
     945        memcpy(fr->hdr.rend.magic, "OFT2", 4);
     946        fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data);
     947
     948        aim_tx_enqueue(sess, fr);
     949
    2174950        return 0;
    2175951}
    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  */
    2186 faim_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  */
    2234 faim_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  */
    2266 static void oft_dirconvert(char *name) {
    2267         char *c = name;
    2268         while ((c = strchr(c, G_DIR_SEPARATOR)))
    2269                 *c = 0x01;
    2270 }
     952
     953/**
     954 * Handle incoming data on a rendezvous connection.  This is analogous to the
     955 * consumesnac function in rxhandlers.c, and I really think this should probably
     956 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet.
     957 *
     958 * @param sess The session.
     959 * @param fr The frame allocated for the incoming data.
     960 * @return Return 0 if the packet was handled correctly, otherwise return the
     961 *         error number.
     962 */
     963faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
     964{
     965        aim_conn_t *conn = fr->conn;
     966        int ret = 1;
     967
     968        if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
     969                if (fr->hdr.rend.type == 0x0001)
     970                        ret = handlehdr_odc(sess, conn, fr, &fr->data);
     971                else
     972                        faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type);
     973
     974        } else {
     975                aim_rxcallback_t userfunc;
     976                struct aim_fileheader_t *header = aim_oft_getheader(&fr->data);
     977                aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */
     978
     979                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type)))
     980                        ret = userfunc(sess, fr, conn, header->bcookie, header);
     981
     982                free(header);
     983        }
     984
     985        if (ret == -1)
     986                aim_conn_close(conn);
     987
     988        return ret;
     989}
Note: See TracChangeset for help on using the changeset viewer.