Changeset 862371b


Ignore:
Timestamp:
Jun 29, 2003, 1:47:04 PM (17 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:
e016fc2
Parents:
03ad7b2
Message:
*** empty log message ***
Location:
libfaim
Files:
3 added
32 edited

Legend:

Unmodified
Added
Removed
  • libfaim/Makefile.in

    r5e53c4a r862371b  
    33LDFLAGS=@LDFLAGS@
    44RANLIB=@RANLIB@
    5 OBJS=admin.o adverts.o auth.o bos.o buddylist.o \
    6      chat.o chatnav.o conn.o ft.o icq.o im.o \
    7      info.o invite.o md5.o meta.o misc.o msgcookie.o \
     5OBJS=admin.o adverts.o auth.o bos.o buddylist.o bstream.o \
     6     chat.o chatnav.o conn.o email.o ft.o icq.o im.o \
     7     info.o invite.o md5.o meta.o misc.o msgcookie.o newsearch.o \
    88     popups.o rxhandlers.o rxqueue.o search.o service.o \
    99     snac.o ssi.o stats.o tlv.o translate.o txqueue.o \
  • libfaim/admin.c

    r5e53c4a r862371b  
     1/*
     2 * Family 0x0007 - Account Administration.
     3 *
     4 * Used for stuff like changing the formating of your screen name, changing your
     5 * email address, requesting an account confirmation email, getting account info,
     6 *
     7 */
    18
    29#define FAIM_INTERNAL
    310#include <aim.h>
    411
    5 /* called for both reply and change-reply */
     12/*
     13 * Subtype 0x0002 - Request a bit of account info.
     14 *
     15 * Info should be one of the following:
     16 * 0x0001 - Screen name formatting
     17 * 0x0011 - Email address
     18 * 0x0013 - Unknown
     19 *
     20 */
     21faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info)
     22{
     23        aim_frame_t *fr;
     24        aim_snacid_t snacid;
     25
     26        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14)))
     27                return -ENOMEM;
     28
     29        snacid = aim_cachesnac(sess, 0x0007, 0x0002, 0x0000, NULL, 0);
     30        aim_putsnac(&fr->data, 0x0007, 0x0002, 0x0000, snacid);
     31
     32        aimbs_put16(&fr->data, info);
     33        aimbs_put16(&fr->data, 0x0000);
     34
     35        aim_tx_enqueue(sess, fr);
     36
     37        return 0;
     38}
     39
     40/*
     41 * Subtypes 0x0003 and 0x0005 - Parse account info.
     42 *
     43 * Called in reply to both an information request (subtype 0x0002) and
     44 * an information change (subtype 0x0004).
     45 *
     46 */
    647static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    748{
    8 
    9         /*
    10          * struct {
    11          *    unsigned short perms;
    12          *    unsigned short tlvcount;
    13          *    aim_tlv_t tlvs[tlvcount];
    14          *  } admin_info[n];
    15          */
    16         while (aim_bstream_empty(bs)) {
    17                 fu16_t perms, tlvcount;
    18 
    19                 perms = aimbs_get16(bs);
    20                 tlvcount = aimbs_get16(bs);
    21 
    22                 while (tlvcount && aim_bstream_empty(bs)) {
    23                         aim_rxcallback_t userfunc;
    24                         fu16_t type, len;
    25                         fu8_t *val;
    26                         int str = 0;
    27 
    28                         type = aimbs_get16(bs);
    29                         len = aimbs_get16(bs);
    30 
    31                         if ((type == 0x0011) || (type == 0x0004))
    32                                 str = 1;
    33 
    34                         if (str)
    35                                 val = aimbs_getstr(bs, len);
    36                         else
    37                                 val = aimbs_getraw(bs, len);
    38 
    39                         /* XXX fix so its only called once for the entire packet */
    40                         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    41                                 userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str);
    42 
    43                         free(val);
    44 
    45                         tlvcount--;
     49        aim_rxcallback_t userfunc;
     50        char *url=NULL, *sn=NULL, *email=NULL;
     51        fu16_t perms, tlvcount, err=0;
     52
     53        perms = aimbs_get16(bs);
     54        tlvcount = aimbs_get16(bs);
     55
     56        while (tlvcount && aim_bstream_empty(bs)) {
     57                fu16_t type, length;
     58
     59                type = aimbs_get16(bs);
     60                length = aimbs_get16(bs);
     61
     62                switch (type) {
     63                        case 0x0001: {
     64                                sn = aimbs_getstr(bs, length);
     65                        } break;
     66
     67                        case 0x0004: {
     68                                url = aimbs_getstr(bs, length);
     69                        } break;
     70
     71                        case 0x0008: {
     72                                err = aimbs_get16(bs);
     73                        } break;
     74
     75                        case 0x0011: {
     76                                if (length == 0) {
     77                                        email = (char*)malloc(13*sizeof(char));
     78                                        strcpy(email, "*suppressed*");
     79                                } else
     80                                        email = aimbs_getstr(bs, length);
     81                        } break;
    4682                }
     83
     84                tlvcount--;
    4785        }
    4886
     87        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     88                userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, err, url, sn, email);
     89
     90        if (sn) free(sn);
     91        if (url) free(url);
     92        if (email) free(email);
     93
    4994        return 1;
    5095}
    5196
     97/*
     98 * Subtype 0x0004 - Set screenname formatting.
     99 *
     100 */
     101faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick)
     102{
     103        aim_frame_t *fr;
     104        aim_snacid_t snacid;
     105        aim_tlvlist_t *tl = NULL;
     106
     107        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newnick))))
     108                return -ENOMEM;
     109
     110        snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
     111        aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
     112
     113        aim_addtlvtochain_raw(&tl, 0x0001, strlen(newnick), newnick);
     114       
     115        aim_writetlvchain(&fr->data, &tl);
     116        aim_freetlvchain(&tl);
     117       
     118        aim_tx_enqueue(sess, fr);
     119
     120
     121        return 0;
     122}
     123
     124/*
     125 * Subtype 0x0004 - Change password.
     126 *
     127 */
     128faim_export int aim_admin_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw)
     129{
     130        aim_frame_t *fr;
     131        aim_tlvlist_t *tl = NULL;
     132        aim_snacid_t snacid;
     133
     134        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw))))
     135                return -ENOMEM;
     136
     137        snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
     138        aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
     139
     140        /* new password TLV t(0002) */
     141        aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw);
     142
     143        /* current password TLV t(0012) */
     144        aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw);
     145
     146        aim_writetlvchain(&fr->data, &tl);
     147        aim_freetlvchain(&tl);
     148
     149        aim_tx_enqueue(sess, fr);
     150
     151        return 0;
     152}
     153
     154/*
     155 * Subtype 0x0004 - Change email address.
     156 *
     157 */
     158faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail)
     159{
     160        aim_frame_t *fr;
     161        aim_snacid_t snacid;
     162        aim_tlvlist_t *tl = NULL;
     163
     164        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail))))
     165                return -ENOMEM;
     166
     167        snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
     168        aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
     169
     170        aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail);
     171       
     172        aim_writetlvchain(&fr->data, &tl);
     173        aim_freetlvchain(&tl);
     174       
     175        aim_tx_enqueue(sess, fr);
     176
     177        return 0;
     178}
     179
     180/*
     181 * Subtype 0x0006 - Request account confirmation.
     182 *
     183 * This will cause an email to be sent to the address associated with
     184 * the account.  By following the instructions in the mail, you can
     185 * get the TRIAL flag removed from your account.
     186 *
     187 */
     188faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn)
     189{
     190        return aim_genericreq_n(sess, conn, 0x0007, 0x0006);
     191}
     192
     193/*
     194 * Subtype 0x0007 - Account confirmation request acknowledgement.
     195 *
     196 */
    52197static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    53198{
    54199        aim_rxcallback_t userfunc;
    55200        fu16_t status;
     201        aim_tlvlist_t *tl;
    56202
    57203        status = aimbs_get16(bs);
     204        /* This is 0x0013 if unable to confirm at this time */
     205
     206        tl = aim_readtlvchain(bs);
    58207
    59208        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     
    87236        return 0;
    88237}
    89 
    90 faim_export int aim_admin_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw)
    91 {
    92         aim_frame_t *tx;
    93         aim_tlvlist_t *tl = NULL;
    94         aim_snacid_t snacid;
    95 
    96         if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw))))
    97                 return -ENOMEM;
    98 
    99         snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
    100         aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
    101 
    102         /* new password TLV t(0002) */
    103         aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw);
    104 
    105         /* current password TLV t(0012) */
    106         aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw);
    107 
    108         aim_writetlvchain(&tx->data, &tl);
    109         aim_freetlvchain(&tl);
    110 
    111         aim_tx_enqueue(sess, tx);
    112 
    113         return 0;
    114 }
    115 
    116 /*
    117  * Request account confirmation.
    118  *
    119  * This will cause an email to be sent to the address associated with
    120  * the account.  By following the instructions in the mail, you can
    121  * get the TRIAL flag removed from your account.
    122  *
    123  */
    124 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn)
    125 {
    126         return aim_genericreq_n(sess, conn, 0x0007, 0x0006);
    127 }
    128 
    129 /*
    130  * Request a bit of account info.
    131  *
    132  * The only known valid tag is 0x0011 (email address).
    133  *
    134  */
    135 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info)
    136 {
    137         aim_frame_t *tx;
    138         aim_snacid_t snacid;
    139 
    140         if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14)))
    141                 return -ENOMEM;
    142 
    143         snacid = aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0);
    144         aim_putsnac(&tx->data, 0x0007, 0x0002, 0x0000, snacid);
    145 
    146         aimbs_put16(&tx->data, info);
    147         aimbs_put16(&tx->data, 0x0000);
    148 
    149         aim_tx_enqueue(sess, tx);
    150 
    151         return 0;
    152 }
    153 
    154 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail)
    155 {
    156         aim_frame_t *tx;
    157         aim_snacid_t snacid;
    158         aim_tlvlist_t *tl = NULL;
    159 
    160         if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail))))
    161                 return -ENOMEM;
    162 
    163         snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
    164         aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
    165 
    166         aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail);
    167        
    168         aim_writetlvchain(&tx->data, &tl);
    169         aim_freetlvchain(&tl);
    170        
    171         aim_tx_enqueue(sess, tx);
    172 
    173         return 0;
    174 }
    175 
    176 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick)
    177 {
    178         aim_frame_t *tx;
    179         aim_snacid_t snacid;
    180         aim_tlvlist_t *tl = NULL;
    181 
    182         if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newnick))))
    183                 return -ENOMEM;
    184 
    185         snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
    186         aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
    187 
    188         aim_addtlvtochain_raw(&tl, 0x0001, strlen(newnick), newnick);
    189        
    190         aim_writetlvchain(&tx->data, &tl);
    191         aim_freetlvchain(&tl);
    192        
    193         aim_tx_enqueue(sess, tx);
    194 
    195         return 0;
    196 }
    197 
  • libfaim/adverts.c

    r5e53c4a r862371b  
    11/*
    2  *
     2 * Family 0x0005 - Advertisements.
    33 *
    44 */
     
    3030        return 0;
    3131}
    32 
    33 
  • libfaim/aim.h

    r5e53c4a r862371b  
    1212#define FAIM_VERSION_MAJOR 0
    1313#define FAIM_VERSION_MINOR 99
    14 #define FAIM_VERSION_MINORMINOR 4
     14#define FAIM_VERSION_MINORMINOR 1
    1515
    1616#include <faimconfig.h>
     
    2626#include <time.h>
    2727
    28 #ifdef _WIN32
    29 #include <windows.h>
    30 #include <io.h>
    31 #else
     28#ifndef _WIN32
    3229#include <sys/time.h>
    3330#include <unistd.h>
    3431#include <netinet/in.h>
    3532#include <sys/socket.h>
     33#else
     34#include <winsock.h>
    3635#endif
    3736
     
    4241typedef fu32_t aim_snacid_t;
    4342typedef fu16_t flap_seqnum_t;
    44 
    45 /* Portability stuff (DMP) */
    46 
    47 #ifdef _WIN32
    48 #define sleep(x) Sleep((x)*1000)
    49 #define snprintf _snprintf /* I'm not sure whats wrong with Microsoft here */
    50 #define close(x) closesocket(x) /* no comment */
    51 #endif
    5243
    5344#if defined(mach) && defined(__APPLE__)
     
    147138};
    148139
    149 #define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \
     140#define CLIENTINFO_AIM_3_5_1670 { \
    150141        "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
    151142        0x0004, \
     
    158149}
    159150
    160 #define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \
     151#define CLIENTINFO_AIM_4_1_2010 { \
    161152          "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
    162153          0x0004, \
     
    169160}
    170161
     162#define CLIENTINFO_AIM_5_0_2938 { \
     163          "AOL Instant Messenger, version 5.0.2938/WIN32", \
     164          0x0109, \
     165          0x0005, \
     166          0x0000, \
     167          0x0000, \
     168          0x0b7a, \
     169          "us", \
     170          "en", \
     171}
     172
     173#define CLIENTINFO_ICQ_4_65_3281 { \
     174        "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \
     175        0x010a, \
     176        0x0004, \
     177        0x0041, \
     178        0x0001, \
     179        0x0cd1, \
     180        "us", \
     181        "en", \
     182}
     183
     184#define CLIENTINFO_ICQ_5_34_3728 { \
     185        "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \
     186        0x010a, \
     187        0x0005, \
     188        0x0022, \
     189        0x0001, \
     190        0x0e8f, \
     191        "us", \
     192        "en", \
     193}
     194
    171195/*
    172196 * I would make 4.1.2010 the default, but they seem to have found
     
    174198 *
    175199 * 3.5.1670 should work fine, however, you will be subjected to the
    176  * memory test, which may require you to have a WinAIM binary laying
     200 * memory test, which may require you to have a WinAIM binary lying
    177201 * around. (see login.c::memrequest())
    178202 */
    179 #define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670
     203#define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_3_5_1670
     204#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_4_65_3281
    180205
    181206#ifndef TRUE
     
    192217#define AIM_CONN_TYPE_CHAT          0x000e
    193218#define AIM_CONN_TYPE_CHATNAV       0x000d
     219#define AIM_CONN_TYPE_SEARCH        0x000f
     220#define AIM_CONN_TYPE_EMAIL         0x0018
    194221
    195222/* they start getting arbitrary in rendezvous stuff =) */
     
    250277typedef struct aim_bstream_s {
    251278        fu8_t *data;
    252         fu16_t len;
    253         fu16_t offset;
     279        fu32_t len;
     280        fu32_t offset;
    254281} aim_bstream_t;
    255282
     
    262289                } flap;
    263290                struct {
     291                        fu8_t magic[4]; /* ODC2 OFT2 */
     292                        fu16_t hdrlen;
    264293                        fu16_t type;
    265                         fu8_t magic[4]; /* ODC2 OFT2 */
    266                         fu16_t hdr2len;
    267                         fu8_t *hdr2; /* rest of bloated header */
    268                 } oft;
     294                } rend;
    269295        } hdr;
    270296        aim_bstream_t data;     /* payload stream */
     
    305331
    306332        /* ---- Internal Use Only ------------------------ */
     333
     334        /* Server-stored information (ssi) */
     335        struct {
     336                int received_data;
     337                fu16_t revision;
     338                struct aim_ssi_item *items;
     339                time_t timestamp;
     340                int waiting_for_ack;
     341                aim_frame_t *holding_queue;
     342        } ssi;
     343
     344        struct aim_emailinfo *emailinfo;
    307345
    308346        /* Connection information */
     
    381419        fu32_t membersince; /* time_t */
    382420        fu32_t onlinesince; /* time_t */
    383         fu32_t sessionlen; /* in seconds */
     421        fu32_t sessionlen;  /* in seconds */
    384422        fu32_t capabilities;
    385423        struct {
     
    459497/* TLV list handling. */
    460498faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs);
     499faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num);
    461500faim_internal void aim_freetlvchain(aim_tlvlist_t **list);
    462501faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n);
     
    518557        char *bosip;
    519558        fu8_t *cookie;
     559        char *chpassurl;
    520560        struct aim_clientrelease latestrelease;
    521561        struct aim_clientrelease latestbeta;
     
    574614faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd);
    575615
    576 /* aim_misc.c */
     616/* misc.c */
    577617
    578618#define AIM_VISIBILITYCHANGE_PERMITADD    0x05
     
    620660faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn);
    621661
    622 /* aim_im.c */
     662/* im.c */
    623663
    624664struct aim_fileheader_t {
     
    657697};
    658698
    659 struct aim_filetransfer_priv {
    660         char sn[MAXSNLEN];
    661         char cookie[8];
    662         char ip[30];
    663         int state;
    664         struct aim_fileheader_t fh;
    665 };
     699#define AIM_OFT_SUBTYPE_SEND_FILE 0x0001
     700#define AIM_OFT_SUBTYPE_SEND_DIR 0x0002
     701#define AIM_OFT_SUBTYPE_GET_FILE 0x0011
     702#define AIM_OPT_SUBTYPE_GET_LIST 0x0012
    666703
    667704struct aim_chat_roominfo {
     
    683720#define AIM_IMFLAGS_MULTIPART           0x0400 /* ->mpmsg section valid */
    684721#define AIM_IMFLAGS_OFFLINE             0x0800 /* send to offline user */
     722#define AIM_IMFLAGS_TYPINGNOT           0x1000 /* typing notification */
    685723
    686724/*
     
    822860                        const char *rtfmsg;
    823861                } rtfmsg;
     862                struct {
     863                        fu16_t subtype;
     864                        fu16_t totfiles;
     865                        fu32_t totsize;
     866                        char *filename;
     867                } sendfile;
    824868        } info;
    825869        void *destructor; /* used internally only */
     870};
     871
     872/* Valid values for channel 4 args->type */
     873#define AIM_ICQMSG_AUTHREQUEST 0x0006
     874#define AIM_ICQMSG_AUTHDENIED 0x0007
     875#define AIM_ICQMSG_AUTHGRANTED 0x0008
     876
     877struct aim_incomingim_ch4_args {
     878        fu32_t uin; /* Of the sender of the ICBM */
     879        fu16_t type;
     880        char *msg; /* Reason for auth request, deny, or accept */
    826881};
    827882
     
    831886faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum);
    832887faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen);
    833 faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg);
     888faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing);
     889faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg, int len, int encoding);
    834890faim_export const char *aim_directim_getsn(aim_conn_t *conn);
    835891faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, const char *destsn);
    836892faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie);
    837893
    838 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize);
     894faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type);
     895faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret);
     896faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message);
     897
     898faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2);
    839899
    840900faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn);
    841901faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size);
     902faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn,
     903                const char *name, int filesdone, int numfiles, int size,
     904                int totsize);
    842905faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn);
    843 faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn);
    844 
    845 /* aim_info.c */
     906faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn);
     907
     908/* info.c */
    846909#define AIM_CAPS_BUDDYICON      0x00000001
    847910#define AIM_CAPS_VOICE          0x00000002
     
    904967#define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
    905968faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, unsigned short code);
    906 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid);
     969faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t port, fu16_t rendid, ...);
     970faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
     971                                const char *cookie, const char *sn, int rendid);
     972faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
     973                                const unsigned char *buffer, int bufferlen);
    907974
    908975faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short);
     
    9331000
    9341001struct aim_icbmparameters {
    935         unsigned short maxchan;
    936         unsigned long flags; /* AIM_IMPARAM_FLAG_ */
    937         unsigned short maxmsglen; /* message size that you will accept */
    938         unsigned short maxsenderwarn; /* this and below are *10 (999=99.9%) */
    939         unsigned short maxrecverwarn;
    940         unsigned long minmsginterval; /* in milliseconds? */
     1002        fu16_t maxchan;
     1003        fu32_t flags; /* AIM_IMPARAM_FLAG_ */
     1004        fu16_t maxmsglen; /* message size that you will accept */
     1005        fu16_t maxsenderwarn; /* this and below are *10 (999=99.9%) */
     1006        fu16_t maxrecverwarn;
     1007        fu32_t minmsginterval; /* in milliseconds? */
    9411008};
    9421009
     
    9541021faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick);
    9551022
    956 /* aim_buddylist.c */
     1023/* buddylist.c */
    9571024faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *);
    9581025faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *);
    9591026
    960 /* aim_search.c */
     1027/* search.c */
    9611028faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *);
     1029
     1030/* newsearch.c */
     1031struct aim_usersearch {
     1032        char *first;
     1033        char *last;
     1034        char *middle;
     1035        char *maiden;
     1036        char *email;
     1037        char *country;
     1038        char *state;
     1039        char *city;
     1040        char *sn;
     1041        char *interest;
     1042        char *nick;
     1043        char *zip;
     1044        char *region;
     1045        char *address;
     1046        struct aim_usersearch *next;
     1047};
     1048
     1049faim_export int aim_usersearch_email(aim_session_t *, const char *, const char *);
     1050faim_export int aim_usersearch_name(aim_session_t *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
     1051faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *);
     1052
    9621053
    9631054/* These apply to exchanges as well. */
     
    9951086#define AIM_SSI_TYPE_BUDDY         0x0000
    9961087#define AIM_SSI_TYPE_GROUP         0x0001
    997 #define AIM_SSI_TYPE_PERMITLIST    0x0002
    998 #define AIM_SSI_TYPE_DENYLIST      0x0003
     1088#define AIM_SSI_TYPE_PERMIT        0x0002
     1089#define AIM_SSI_TYPE_DENY          0x0003
    9991090#define AIM_SSI_TYPE_PDINFO        0x0004
    10001091#define AIM_SSI_TYPE_PRESENCEPREFS 0x0005
     
    10091100};
    10101101
     1102/* These build the actual SNACs and queue them to be sent */
    10111103faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn);
    10121104faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev);
    10131105faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn);
     1106faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype);
    10141107faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn);
    10151108faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn);
     1109
     1110/* These handle the local variables */
     1111faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid);
     1112faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type);
     1113faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn);
     1114faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list);
     1115faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list);
     1116faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn);
     1117faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num);
     1118faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn);
     1119faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num);
     1120faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type);
     1121faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn);
     1122faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn);
     1123faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num);
     1124faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn);
     1125faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num);
     1126faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn);
     1127faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type);
     1128faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask);
     1129faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence);
    10161130
    10171131struct aim_icq_offlinemsg {
     
    10351149faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin);
    10361150
    1037 /* aim_util.c */
     1151/* email.c */
     1152struct aim_emailinfo {
     1153        fu8_t *cookie16;
     1154        fu8_t *cookie8;
     1155        char *url;
     1156        fu16_t nummsgs;
     1157        fu8_t unread;
     1158        char *domain;
     1159        fu16_t flag;
     1160        struct aim_emailinfo *next;
     1161};
     1162
     1163faim_export int aim_email_sendcookies(aim_session_t *sess, aim_conn_t *conn);
     1164faim_export int aim_email_activate(aim_session_t *sess, aim_conn_t *conn);
     1165
     1166/* util.c */
    10381167/*
    10391168 * These are really ugly.  You'd think this was LISP.  I wish it was.
     
    11001229faim_export char *aim_strsep(char **pp, const char *delim);
    11011230
    1102 /* aim_meta.c */
     1231/* meta.c */
    11031232faim_export char *aim_getbuilddate(void);
    11041233faim_export char *aim_getbuildtime(void);
  • libfaim/aim_cbtypes.h

    r5e53c4a r862371b  
    2424#define AIM_CB_FAM_CTN 0x000d /* ChatNav */
    2525#define AIM_CB_FAM_CHT 0x000e /* Chat */
     26#define AIM_CB_FAM_SCH 0x000f /* "New" search */
     27#define AIM_CB_FAM_SSI 0x0013 /* Server stored information */
    2628#define AIM_CB_FAM_ICQ 0x0015
    2729#define AIM_CB_FAM_ATH 0x0017
     30#define AIM_CB_FAM_EML 0x0018
    2831#define AIM_CB_FAM_OFT 0xfffe /* OFT/Rvous */
    2932#define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */
     
    97100#define AIM_CB_MSG_EVIL 0x0009
    98101#define AIM_CB_MSG_MISSEDCALL 0x000a
    99 #define AIM_CB_MSG_CLIENTERROR 0x000b
     102#define AIM_CB_MSG_CLIENTAUTORESP 0x000b
    100103#define AIM_CB_MSG_ACK 0x000c
     104#define AIM_CB_MSG_MTN 0x0014
    101105#define AIM_CB_MSG_DEFAULT 0xffff
    102106
     
    174178
    175179/*
     180 * SNAC Family: "New" Search
     181 *
     182 * Most of these are actually special.
     183 */
     184#define AIM_CB_SCH_ERROR 0x0001
     185#define AIM_CB_SCH_SEARCH 0x0002
     186#define AIM_CB_SCH_RESULTS 0x0003
     187
     188/*
    176189 * SNAC Family: ICQ
    177190 *
     
    185198
    186199/*
     200 * SNAC Family: Server-Stored Buddy Lists
     201 */
     202#define AIM_CB_SSI_ERROR 0x0001
     203#define AIM_CB_SSI_REQRIGHTS 0x0002
     204#define AIM_CB_SSI_RIGHTSINFO 0x0003
     205#define AIM_CB_SSI_REQLIST 0x0005
     206#define AIM_CB_SSI_LIST 0x0006
     207#define AIM_CB_SSI_ACTIVATE 0x0007
     208#define AIM_CB_SSI_ADD 0x0008
     209#define AIM_CB_SSI_MOD 0x0009
     210#define AIM_CB_SSI_DEL 0x000A
     211#define AIM_CB_SSI_SRVACK 0x000E
     212#define AIM_CB_SSI_NOLIST 0x000F
     213#define AIM_CB_SSI_EDITSTART 0x0011
     214#define AIM_CB_SSI_EDITSTOP 0x0012
     215
     216/*
    187217 * SNAC Family: Authorizer
    188218 *
     
    197227
    198228/*
     229 * SNAC Family: Email
     230 *
     231 * Used for getting information on the email address
     232 * associated with your screen name.
     233 *
     234 */
     235#define AIM_CB_EML_ERROR 0x0001
     236#define AIM_CB_EML_SENDCOOKIES 0x0006
     237#define AIM_CB_EML_MAILSTATUS 0x0007
     238#define AIM_CB_EML_INIT 0x0016
     239
     240/*
    199241 * OFT Services
    200242 *
     
    207249#define AIM_CB_OFT_DIRECTIMINITIATE 0x0005
    208250
     251/* had been removed, put back by kretch */
    209252#define AIM_CB_OFT_GETFILECONNECTREQ 0x0006 /* connect request -- actually an OSCAR CAP*/
    210253#define AIM_CB_OFT_GETFILELISTINGREQ 0x0007 /* OFT listing.txt request */
     
    219262#define AIM_CB_OFT_GETFILESTATE4 0x0010
    220263
    221 #define AIM_CB_OFT_SENDFILEDISCONNECT 0x0020   /* OFT connection disconnected.*/
    222 
     264#define AIM_CB_OFT_SENDFILEFILEREQ 0x0011 /* started receiving file */
     265#define AIM_CB_OFT_SENDFILEFILESEND 0x0012 /* buddy ready to for us to send */
     266#define AIM_CB_OFT_SENDFILECOMPLETE 0x0013 /* send to buddy complete */
     267#define AIM_CB_OFT_SENDFILEINITIATE 0x0014 /* connection to buddy initiated */
    223268
    224269
     
    237282#define AIM_CB_SPECIAL_FLAPVER 0x0005
    238283#define AIM_CB_SPECIAL_CONNINITDONE 0x0006
     284#define AIM_CB_SPECIAL_IMAGETRANSFER 0x007
     285#define AIM_CB_SPECIAL_MSGTIMEOUT 0x008
    239286#define AIM_CB_SPECIAL_UNKNOWN 0xffff
    240287#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN
    241288
     289/* SNAC flags */
     290#define AIM_SNACFLAGS_DESTRUCTOR 0x0001
    242291
    243292#endif/*__AIM_CBTYPES_H__ */
  • libfaim/aim_internal.h

    r5e53c4a r862371b  
    2525        char name[AIM_MODULENAME_MAXLEN+1];
    2626        int (*snachandler)(aim_session_t *sess, struct aim_module_s *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs);
     27        int (*snacdestructor)(aim_session_t *sess, aim_conn_t *conn, aim_modsnac_t *snac, void *data);
     28
    2729        void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod);
    2830        void *priv;
     
    5355faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod);
    5456faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod);
     57faim_internal int email_modfirst(aim_session_t *sess, aim_module_t *mod);
     58faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod);
    5559
    5660faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype);
     
    6165#define AIMBS_CURPOSPAIR(x) ((x)->data + (x)->offset), ((x)->len - (x)->offset)
    6266
    63 faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn);
    64 faim_internal int aim_recv(int fd, void *buf, size_t count);
    65 faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count);
     67/* bstream.c */
    6668faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len);
    6769faim_internal int aim_bstream_empty(aim_bstream_t *bs);
     
    8890faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len);
    8991
    90 faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn);
    91 
    92 faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur);
    93 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *);
    94 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen);
    95 faim_internal void aim_frame_destroy(aim_frame_t *);
    96 faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *);
    97 faim_internal int aim_tx_printqueue(aim_session_t *);
    98 faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *);
    99 
     92/* conn.c */
     93faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src);
     94
     95/* ft.c */
     96faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr);
     97
     98/* rxhandlers.c */
    10099faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type);
    101100faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_frame_t *ptr);
     101faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...);
     102faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src);
     103
     104/* rxqueue.c */
     105faim_internal int aim_recv(int fd, void *buf, size_t count);
     106faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count);
     107faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn);
     108faim_internal void aim_frame_destroy(aim_frame_t *);
     109
     110/* txqueue.c */
     111faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen);
     112faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *);
     113faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *);
     114faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur);
     115faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *);
     116
     117/* XXX - What is this?   faim_internal int aim_tx_printqueue(aim_session_t *); */
    102118
    103119/*
     
    114130} aim_snac_t;
    115131
     132struct aim_snac_destructor {
     133        aim_conn_t *conn;
     134        void *data;
     135};
     136
     137/* snac.c */
    116138faim_internal void aim_initsnachash(aim_session_t *sess);
    117139faim_internal aim_snacid_t aim_newsnac(aim_session_t *, aim_snac_t *newsnac);
     
    120142faim_internal void aim_cleansnacs(aim_session_t *, int maxage);
    121143faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id);
    122 
    123 faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src);
    124 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src);
    125 
    126 faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *);
    127 
    128 faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...);
    129144
    130145/* Stored in ->priv of the service request SNAC for chats. */
  • libfaim/auth.c

    r5e53c4a r862371b  
    11/*
    2  * Deals with the authorizer (group 0x0017=23, and old-style non-SNAC login).
     2 * Family 0x0017 - Authentication.
     3 *
     4 * Deals with the authorizer for SNAC-based login, and also old-style
     5 * non-SNAC login.
    36 *
    47 */
     
    148151
    149152/*
    150  * Part two of the ICQ hack.  Note the ignoring of the key and clientinfo.
    151  */
    152 static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password)
    153 {
    154         static const char clientstr[] = {"ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85"};
    155         static const char lang[] = {"en"};
    156         static const char country[] = {"us"};
     153 * Part two of the ICQ hack.  Note the ignoring of the key.
     154 */
     155static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *ci)
     156{
    157157        aim_frame_t *fr;
    158158        aim_tlvlist_t *tl = NULL;
     
    169169        aim_encode_password(password, password_encoded);
    170170
    171         aimbs_put32(&fr->data, 0x00000001);
     171        aimbs_put32(&fr->data, 0x00000001); /* FLAP Version */
    172172        aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
    173173        aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded);
    174         aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientstr), clientstr);
    175         aim_addtlvtochain16(&tl, 0x0016, 0x010a); /* cliend ID */
    176         aim_addtlvtochain16(&tl, 0x0017, 0x0004); /* major version */
    177         aim_addtlvtochain16(&tl, 0x0018, 0x0041); /* minor version */
    178         aim_addtlvtochain16(&tl, 0x0019, 0x0001); /* point version */
    179         aim_addtlvtochain16(&tl, 0x001a, 0x0cd1); /* build */
     174
     175        if (ci->clientstring)
     176                aim_addtlvtochain_raw(&tl, 0x0003, strlen(ci->clientstring), ci->clientstring);
     177        aim_addtlvtochain16(&tl, 0x0016, (fu16_t)ci->clientid);
     178        aim_addtlvtochain16(&tl, 0x0017, (fu16_t)ci->major);
     179        aim_addtlvtochain16(&tl, 0x0018, (fu16_t)ci->minor);
     180        aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point);
     181        aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build);
    180182        aim_addtlvtochain32(&tl, 0x0014, 0x00000055); /* distribution chan */
    181         aim_addtlvtochain_raw(&tl, 0x000f, strlen(lang), lang);
    182         aim_addtlvtochain_raw(&tl, 0x000e, strlen(country), country);
     183        aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang);
     184        aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country);
    183185
    184186        aim_writetlvchain(&fr->data, &tl);
     
    277279         */
    278280        if (sess->flags & AIM_SESS_FLAGS_XORLOGIN)
    279                 return goddamnicq2(sess, conn, sn, password);
     281                return goddamnicq2(sess, conn, sn, password, ci);
    280282
    281283
     
    290292        aim_encode_password_md5(password, key, digest);
    291293        aim_addtlvtochain_raw(&tl, 0x0025, 16, digest);
     294
     295        /*
     296         * Newer versions of winaim have an empty type x004c TLV here.
     297         */
    292298
    293299        if (ci->clientstring)
     
    305311         * to use SSI.
    306312         */
    307         if (0)
    308                 aim_addtlvtochain8(&tl, 0x004a, 0x01);
     313        aim_addtlvtochain8(&tl, 0x004a, 0x01);
    309314
    310315        aim_writetlvchain(&fr->data, &tl);
     
    473478                ; /* no idea what this is */
    474479
     480        /*
     481         * URL to change password.
     482         */
     483        if (aim_gettlv(tlvlist, 0x0054, 1))
     484                info.chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1);
    475485
    476486        if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003)))
     
    481491        free(info.errorurl);
    482492        free(info.email);
     493        free(info.chpassurl);
    483494        free(info.latestrelease.name);
    484495        free(info.latestrelease.url);
     
    539550        return 0;
    540551}
    541 
  • libfaim/bos.c

    r5e53c4a r862371b  
     1/*
     2 * Family 0x0009 - Basic Oscar Service.
     3 *
     4 */
    15
    26#define FAIM_INTERNAL
    37#include <aim.h>
    48
    5 /* Request BOS rights (group 9, type 2) */
     9/* Subtype 0x0002 - Request BOS rights. */
    610faim_export int aim_bos_reqrights(aim_session_t *sess, aim_conn_t *conn)
    711{
     
    913}
    1014
    11 /* BOS Rights (group 9, type 3) */
     15/* Subtype 0x0003 - BOS Rights. */
    1216static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    1317{
     
    4347
    4448/*
    45  * Set group permisson mask (group 9, type 4)
     49 * Subtype 0x0004 - Set group permisson mask.
    4650 *
    4751 * Normally 0x1f (all classes).
     
    5862
    5963/*
    60  * Modify permit/deny lists (group 9, types 5, 6, 7, and 8)
     64 * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists.
    6165 *
    6266 * Changes your visibility depending on changetype:
     
    159163        return 0;
    160164}
    161 
    162 
  • libfaim/buddylist.c

    r5e53c4a r862371b  
     1/*
     2 * Family 0x0003 - Old-style Buddylist Management (non-SSI).
     3 *
     4 */
    15
    26#define FAIM_INTERNAL
     
    48
    59/*
    6  * Oncoming Buddy notifications contain a subset of the
    7  * user information structure.  Its close enough to run
    8  * through aim_extractuserinfo() however.
    9  *
    10  * Although the offgoing notification contains no information,
    11  * it is still in a format parsable by extractuserinfo.
    12  *
    13  */
    14 static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    15 {
    16         aim_userinfo_t userinfo;
    17         aim_rxcallback_t userfunc;
    18 
    19         aim_extractuserinfo(sess, bs, &userinfo);
    20 
    21         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    22                 return userfunc(sess, rx, &userinfo);
    23 
    24         return 0;
    25 }
    26 
     10 * Subtype 0x0002 - Request rights.
     11 *
     12 * Request Buddy List rights.
     13 *
     14 */
     15faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn)
     16{
     17        return aim_genericreq_n(sess, conn, 0x0003, 0x0002);
     18}
     19
     20/*
     21 * Subtype 0x0003 - Rights.
     22 *
     23 */
    2724static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    2825{
     
    5451                maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1);
    5552
     53        /*
     54         * TLV type 0x0003: Unknown.
     55         *
     56         * ICQ only?
     57         */
     58
    5659        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    5760                ret = userfunc(sess, rx, maxbuddies, maxwatchers);
     
    6063
    6164        return ret; 
     65}
     66
     67/*
     68 * Subtype 0x0004 - Add buddy to list.
     69 *
     70 * Adds a single buddy to your buddy list after login.
     71 * XXX This should just be an extension of setbuddylist()
     72 *
     73 */
     74faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)
     75{
     76        aim_frame_t *fr;
     77        aim_snacid_t snacid;
     78
     79        if (!sn || !strlen(sn))
     80                return -EINVAL;
     81
     82        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
     83                return -ENOMEM;
     84
     85        snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);
     86        aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
     87
     88        aimbs_put8(&fr->data, strlen(sn));
     89        aimbs_putraw(&fr->data, sn, strlen(sn));
     90
     91        aim_tx_enqueue(sess, fr);
     92
     93        return 0;
     94}
     95
     96/*
     97 * Subtype 0x0004 - Add multiple buddies to your buddy list.
     98 *
     99 * This just builds the "set buddy list" command then queues it.
     100 *
     101 * buddy_list = "Screen Name One&ScreenNameTwo&";
     102 *
     103 * XXX Clean this up. 
     104 *
     105 */
     106faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list)
     107{
     108        aim_frame_t *fr;
     109        aim_snacid_t snacid;
     110        int len = 0;
     111        char *localcpy = NULL;
     112        char *tmpptr = NULL;
     113
     114        if (!buddy_list || !(localcpy = strdup(buddy_list)))
     115                return -EINVAL;
     116
     117        for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
     118                faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));
     119                len += 1 + strlen(tmpptr);
     120                tmpptr = strtok(NULL, "&");
     121        }
     122
     123        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len)))
     124                return -ENOMEM;
     125
     126        snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0);
     127        aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
     128
     129        strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
     130
     131        for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
     132
     133                faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));
     134
     135                aimbs_put8(&fr->data, strlen(tmpptr));
     136                aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr));
     137                tmpptr = strtok(NULL, "&");
     138        }
     139
     140        aim_tx_enqueue(sess, fr);
     141
     142        free(localcpy);
     143
     144        return 0;
     145}
     146
     147/*
     148 * Subtype 0x0005 - Remove buddy from list.
     149 *
     150 * XXX generalise to support removing multiple buddies (basically, its
     151 * the same as setbuddylist() but with a different snac subtype).
     152 *
     153 */
     154faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)
     155{
     156        aim_frame_t *fr;
     157        aim_snacid_t snacid;
     158
     159        if (!sn || !strlen(sn))
     160                return -EINVAL;
     161
     162        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
     163                return -ENOMEM;
     164
     165        snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);
     166        aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid);
     167
     168        aimbs_put8(&fr->data, strlen(sn));
     169        aimbs_putraw(&fr->data, sn, strlen(sn));
     170
     171        aim_tx_enqueue(sess, fr);
     172
     173        return 0;
     174}
     175
     176/*
     177 * Subtype 0x000b
     178 *
     179 * XXX Why would we send this?
     180 *
     181 */
     182faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info)
     183{
     184        aim_frame_t *fr;
     185        aim_snacid_t snacid;
     186
     187        if (!sess || !conn || !info)
     188                return -EINVAL;
     189
     190        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
     191                return -ENOMEM;
     192
     193        snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0);
     194       
     195        aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid);
     196        aim_putuserinfo(&fr->data, info);
     197
     198        aim_tx_enqueue(sess, fr);
     199
     200        return 0;
     201}
     202
     203/*
     204 * Subtype 0x000c
     205 *
     206 * XXX Why would we send this?
     207 *
     208 */
     209faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn)
     210{
     211        aim_frame_t *fr;
     212        aim_snacid_t snacid;
     213
     214        if (!sess || !conn || !sn)
     215                return -EINVAL;
     216
     217        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
     218                return -ENOMEM;
     219
     220        snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0);
     221       
     222        aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid);
     223        aimbs_put8(&fr->data, strlen(sn));
     224        aimbs_putraw(&fr->data, sn, strlen(sn));
     225
     226        aim_tx_enqueue(sess, fr);
     227
     228        return 0;
     229}
     230
     231/*
     232 * Subtypes 0x000b and 0x000c - Change in buddy status
     233 *
     234 * Oncoming Buddy notifications contain a subset of the
     235 * user information structure.  Its close enough to run
     236 * through aim_extractuserinfo() however.
     237 *
     238 * Although the offgoing notification contains no information,
     239 * it is still in a format parsable by extractuserinfo.
     240 *
     241 */
     242static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     243{
     244        aim_userinfo_t userinfo;
     245        aim_rxcallback_t userfunc;
     246
     247        aim_extractuserinfo(sess, bs, &userinfo);
     248
     249        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     250                return userfunc(sess, rx, &userinfo);
     251
     252        return 0;
    62253}
    63254
     
    86277        return 0;
    87278}
    88 
    89 /*
    90  * aim_add_buddy()
    91  *
    92  * Adds a single buddy to your buddy list after login.
    93  *
    94  * XXX this should just be an extension of setbuddylist()
    95  *
    96  */
    97 faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)
    98 {
    99         aim_frame_t *fr;
    100         aim_snacid_t snacid;
    101 
    102         if (!sn || !strlen(sn))
    103                 return -EINVAL;
    104 
    105         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
    106                 return -ENOMEM;
    107 
    108         snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);
    109         aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
    110 
    111         aimbs_put8(&fr->data, strlen(sn));
    112         aimbs_putraw(&fr->data, sn, strlen(sn));
    113 
    114         aim_tx_enqueue(sess, fr);
    115 
    116         return 0;
    117 }
    118 
    119 /*
    120  * XXX generalise to support removing multiple buddies (basically, its
    121  * the same as setbuddylist() but with a different snac subtype).
    122  *
    123  */
    124 faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)
    125 {
    126         aim_frame_t *fr;
    127         aim_snacid_t snacid;
    128 
    129         if (!sn || !strlen(sn))
    130                 return -EINVAL;
    131 
    132         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
    133                 return -ENOMEM;
    134 
    135         snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);
    136         aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid);
    137 
    138         aimbs_put8(&fr->data, strlen(sn));
    139         aimbs_putraw(&fr->data, sn, strlen(sn));
    140 
    141         aim_tx_enqueue(sess, fr);
    142 
    143         return 0;
    144 }
    145 
  • libfaim/chat.c

    r5e53c4a r862371b  
    11/*
    2  * aim_chat.c
    3  *
    4  * Routines for the Chat service.
     2 * Family 0x000e - Routines for the Chat service.
    53 *
    64 */
     
    1614};
    1715
    18 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)
    19 {
    20         int i;
    21 
    22         if (!sess || !buf || !len)
    23                 return;
    24 
    25         faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf);
    26 
    27         for (i = 0; i < len; i++) {
    28                 if ((i % 8) == 0)
    29                         faimdprintf(sess, 1, "\n\t");
    30 
    31                 faimdprintf(sess, 1, "0x%2x ", buf[i]);
    32         }
    33 
    34         faimdprintf(sess, 1, "\n\n");
    35 
    36         return;
    37 }
    38 
    3916faim_internal void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn)
    4017{
     
    10784}
    10885
     86static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance)
     87{
     88        fu8_t *buf;
     89        int buflen;
     90        aim_bstream_t bs;
     91
     92        buflen = 2 + 1 + strlen(roomname) + 2;
     93       
     94        if (!(buf = malloc(buflen)))
     95                return 0;
     96
     97        aim_bstream_init(&bs, buf, buflen);
     98
     99        aimbs_put16(&bs, exchange);
     100        aimbs_put8(&bs, strlen(roomname));
     101        aimbs_putraw(&bs, roomname, strlen(roomname));
     102        aimbs_put16(&bs, instance);
     103
     104        aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
     105
     106        free(buf);
     107
     108        return 0;
     109}
     110
    109111/*
    110  * Send a Chat Message.
     112 * Join a room of name roomname.  This is the first step to joining an
     113 * already created room.  It's basically a Service Request for
     114 * family 0x000e, with a little added on to specify the exchange and room
     115 * name.
     116 */
     117faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance)
     118{
     119        aim_frame_t *fr;
     120        aim_snacid_t snacid;
     121        aim_tlvlist_t *tl = NULL;
     122        struct chatsnacinfo csi;
     123       
     124        if (!sess || !conn || !roomname || !strlen(roomname))
     125                return -EINVAL;
     126
     127        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
     128                return -ENOMEM;
     129
     130        memset(&csi, 0, sizeof(csi));
     131        csi.exchange = exchange;
     132        strncpy(csi.name, roomname, sizeof(csi.name));
     133        csi.instance = instance;
     134
     135        snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
     136        aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid);
     137
     138        /*
     139         * Requesting service chat (0x000e)
     140         */
     141        aimbs_put16(&fr->data, 0x000e);
     142
     143        aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance);
     144        aim_writetlvchain(&fr->data, &tl);
     145        aim_freetlvchain(&tl);
     146
     147        aim_tx_enqueue(sess, fr);
     148
     149        return 0;
     150}
     151
     152faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo)
     153{
     154        int namelen;
     155
     156        if (!bs || !outinfo)
     157                return 0;
     158
     159        outinfo->exchange = aimbs_get16(bs);
     160        namelen = aimbs_get8(bs);
     161        outinfo->name = aimbs_getstr(bs, namelen);
     162        outinfo->instance = aimbs_get16(bs);
     163
     164        return 0;
     165}
     166
     167faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name)
     168{
     169        aim_conn_t *conn;
     170
     171        if (!(conn = aim_chat_getconn(sess, name)))
     172                return -ENOENT;
     173
     174        aim_conn_close(conn);
     175
     176        return 0;
     177}
     178
     179/*
     180 * conn must be a BOS connection!
     181 */
     182faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance)
     183{
     184        int i;
     185        aim_frame_t *fr;
     186        aim_msgcookie_t *cookie;
     187        struct aim_invite_priv *priv;
     188        fu8_t ckstr[8];
     189        aim_snacid_t snacid;
     190        aim_tlvlist_t *otl = NULL, *itl = NULL;
     191        fu8_t *hdr;
     192        int hdrlen;
     193        aim_bstream_t hdrbs;
     194       
     195        if (!sess || !conn || !sn || !msg || !roomname)
     196                return -EINVAL;
     197
     198        if (conn->type != AIM_CONN_TYPE_BOS)
     199                return -EINVAL;
     200
     201        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
     202                return -ENOMEM;
     203
     204        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
     205        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
     206
     207
     208        /*
     209         * Cookie
     210         */
     211        for (i = 0; i < sizeof(ckstr); i++)
     212                aimutil_put8(ckstr, (fu8_t) rand());
     213
     214        /* XXX should be uncached by an unwritten 'invite accept' handler */
     215        if ((priv = malloc(sizeof(struct aim_invite_priv)))) {
     216                priv->sn = strdup(sn);
     217                priv->roomname = strdup(roomname);
     218                priv->exchange = exchange;
     219                priv->instance = instance;
     220        }
     221
     222        if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv)))
     223                aim_cachecookie(sess, cookie);
     224        else
     225                free(priv);
     226
     227        for (i = 0; i < sizeof(ckstr); i++)
     228                aimbs_put8(&fr->data, ckstr[i]);
     229
     230
     231        /*
     232         * Channel (2)
     233         */
     234        aimbs_put16(&fr->data, 0x0002);
     235
     236        /*
     237         * Dest sn
     238         */
     239        aimbs_put8(&fr->data, strlen(sn));
     240        aimbs_putraw(&fr->data, sn, strlen(sn));
     241
     242        /*
     243         * TLV t(0005)
     244         *
     245         * Everything else is inside this TLV.
     246         *
     247         * Sigh.  AOL was rather inconsistent right here.  So we have
     248         * to play some minor tricks.  Right inside the type 5 is some
     249         * raw data, followed by a series of TLVs. 
     250         *
     251         */
     252        hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2;
     253        hdr = malloc(hdrlen);
     254        aim_bstream_init(&hdrbs, hdr, hdrlen);
     255       
     256        aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
     257        aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */
     258        aim_putcap(&hdrbs, AIM_CAPS_CHAT);
     259
     260        aim_addtlvtochain16(&itl, 0x000a, 0x0001);
     261        aim_addtlvtochain_noval(&itl, 0x000f);
     262        aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg);
     263        aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
     264        aim_writetlvchain(&hdrbs, &itl);
     265       
     266        aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
     267
     268        aim_writetlvchain(&fr->data, &otl);
     269
     270        free(hdr);
     271        aim_freetlvchain(&itl);
     272        aim_freetlvchain(&otl);
     273       
     274        aim_tx_enqueue(sess, fr);
     275
     276        return 0;
     277}
     278
     279/*
     280 * Subtype 0x0002 - General room information.  Lots of stuff.
     281 *
     282 * Values I know are in here but I havent attached
     283 * them to any of the 'Unknown's:
     284 *      - Language (English)
     285 *
     286 */
     287static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     288{
     289        aim_userinfo_t *userinfo = NULL;
     290        aim_rxcallback_t userfunc;
     291        int ret = 0;
     292        int usercount = 0;
     293        fu8_t detaillevel = 0;
     294        char *roomname = NULL;
     295        struct aim_chat_roominfo roominfo;
     296        fu16_t tlvcount = 0;
     297        aim_tlvlist_t *tlvlist;
     298        char *roomdesc = NULL;
     299        fu16_t flags = 0;
     300        fu32_t creationtime = 0;
     301        fu16_t maxmsglen = 0, maxvisiblemsglen = 0;
     302        fu16_t unknown_d2 = 0, unknown_d5 = 0;
     303
     304        aim_chat_readroominfo(bs, &roominfo);
     305
     306        detaillevel = aimbs_get8(bs);
     307
     308        if (detaillevel != 0x02) {
     309                faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
     310                return 1;
     311        }
     312
     313        tlvcount = aimbs_get16(bs);
     314
     315        /*
     316         * Everything else are TLVs.
     317         */
     318        tlvlist = aim_readtlvchain(bs);
     319
     320        /*
     321         * TLV type 0x006a is the room name in Human Readable Form.
     322         */
     323        if (aim_gettlv(tlvlist, 0x006a, 1))
     324                roomname = aim_gettlv_str(tlvlist, 0x006a, 1);
     325
     326        /*
     327         * Type 0x006f: Number of occupants.
     328         */
     329        if (aim_gettlv(tlvlist, 0x006f, 1))
     330                usercount = aim_gettlv16(tlvlist, 0x006f, 1);
     331
     332        /*
     333         * Type 0x0073:  Occupant list.
     334         */
     335        if (aim_gettlv(tlvlist, 0x0073, 1)) {   
     336                int curoccupant = 0;
     337                aim_tlv_t *tmptlv;
     338                aim_bstream_t occbs;
     339
     340                tmptlv = aim_gettlv(tlvlist, 0x0073, 1);
     341
     342                /* Allocate enough userinfo structs for all occupants */
     343                userinfo = calloc(usercount, sizeof(aim_userinfo_t));
     344
     345                aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);
     346
     347                while (curoccupant < usercount)
     348                        aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);
     349        }
     350
     351        /*
     352         * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
     353         */
     354        if (aim_gettlv(tlvlist, 0x00c9, 1))
     355                flags = aim_gettlv16(tlvlist, 0x00c9, 1);
     356
     357        /*
     358         * Type 0x00ca: Creation time (4 bytes)
     359         */
     360        if (aim_gettlv(tlvlist, 0x00ca, 1))
     361                creationtime = aim_gettlv32(tlvlist, 0x00ca, 1);
     362
     363        /*
     364         * Type 0x00d1: Maximum Message Length
     365         */
     366        if (aim_gettlv(tlvlist, 0x00d1, 1))
     367                maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1);
     368
     369        /*
     370         * Type 0x00d2: Unknown. (2 bytes)
     371         */
     372        if (aim_gettlv(tlvlist, 0x00d2, 1))
     373                unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1);
     374
     375        /*
     376         * Type 0x00d3: Room Description
     377         */
     378        if (aim_gettlv(tlvlist, 0x00d3, 1))
     379                roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1);
     380
     381        /*
     382         * Type 0x000d4: Unknown (flag only)
     383         */
     384        if (aim_gettlv(tlvlist, 0x000d4, 1))
     385                ;
     386
     387        /*
     388         * Type 0x00d5: Unknown. (1 byte)
     389         */
     390        if (aim_gettlv(tlvlist, 0x00d5, 1))
     391                unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1);
     392
     393
     394        /*
     395         * Type 0x00d6: Encoding 1 ("us-ascii")
     396         */
     397        if (aim_gettlv(tlvlist, 0x000d6, 1))
     398                ;
     399       
     400        /*
     401         * Type 0x00d7: Language 1 ("en")
     402         */
     403        if (aim_gettlv(tlvlist, 0x000d7, 1))
     404                ;
     405
     406        /*
     407         * Type 0x00d8: Encoding 2 ("us-ascii")
     408         */
     409        if (aim_gettlv(tlvlist, 0x000d8, 1))
     410                ;
     411       
     412        /*
     413         * Type 0x00d9: Language 2 ("en")
     414         */
     415        if (aim_gettlv(tlvlist, 0x000d9, 1))
     416                ;
     417
     418        /*
     419         * Type 0x00da: Maximum visible message length
     420         */
     421        if (aim_gettlv(tlvlist, 0x000da, 1))
     422                maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1);
     423
     424        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
     425                ret = userfunc(sess,
     426                                rx,
     427                                &roominfo,
     428                                roomname,
     429                                usercount,
     430                                userinfo,       
     431                                roomdesc,
     432                                flags,
     433                                creationtime,
     434                                maxmsglen,
     435                                unknown_d2,
     436                                unknown_d5,
     437                                maxvisiblemsglen);
     438        }
     439
     440        free(roominfo.name);
     441        free(userinfo);
     442        free(roomname);
     443        free(roomdesc);
     444        aim_freetlvchain(&tlvlist);
     445
     446        return ret;
     447}
     448
     449/* Subtypes 0x0003 and 0x0004 */
     450static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     451{
     452        aim_userinfo_t *userinfo = NULL;
     453        aim_rxcallback_t userfunc;
     454        int curcount = 0, ret = 0;
     455
     456        while (aim_bstream_empty(bs)) {
     457                curcount++;
     458                userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t));
     459                aim_extractuserinfo(sess, bs, &userinfo[curcount-1]);
     460        }
     461
     462        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     463                ret = userfunc(sess, rx, curcount, userinfo);
     464
     465        free(userinfo);
     466
     467        return ret;
     468}
     469
     470/*
     471 * Subtype 0x0005 - Send a Chat Message.
    111472 *
    112473 * Possible flags:
     
    204565}
    205566
    206 static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance)
    207 {
    208         fu8_t *buf;
    209         int buflen;
    210         aim_bstream_t bs;
    211 
    212         buflen = 2 + 1 + strlen(roomname) + 2;
    213        
    214         if (!(buf = malloc(buflen)))
    215                 return 0;
    216 
    217         aim_bstream_init(&bs, buf, buflen);
    218 
    219         aimbs_put16(&bs, exchange);
    220         aimbs_put8(&bs, strlen(roomname));
    221         aimbs_putraw(&bs, roomname, strlen(roomname));
    222         aimbs_put16(&bs, instance);
    223 
    224         aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
    225 
    226         free(buf);
    227 
    228         return 0;
    229 }
    230 
    231567/*
    232  * Join a room of name roomname.  This is the first step to joining an
    233  * already created room.  It's basically a Service Request for
    234  * family 0x000e, with a little added on to specify the exchange and room
    235  * name.
    236  */
    237 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance)
    238 {
    239         aim_frame_t *fr;
    240         aim_snacid_t snacid;
    241         aim_tlvlist_t *tl = NULL;
    242         struct chatsnacinfo csi;
    243        
    244         if (!sess || !conn || !roomname || !strlen(roomname))
    245                 return -EINVAL;
    246 
    247         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
    248                 return -ENOMEM;
    249 
    250         memset(&csi, 0, sizeof(csi));
    251         csi.exchange = exchange;
    252         strncpy(csi.name, roomname, sizeof(csi.name));
    253         csi.instance = instance;
    254 
    255         snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
    256         aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid);
    257 
    258         /*
    259          * Requesting service chat (0x000e)
    260          */
    261         aimbs_put16(&fr->data, 0x000e);
    262 
    263         aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance);
    264         aim_writetlvchain(&fr->data, &tl);
    265         aim_freetlvchain(&tl);
    266 
    267         aim_tx_enqueue(sess, fr);
    268 
    269         return 0;
    270 }
    271 
    272 faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo)
    273 {
    274         int namelen;
    275 
    276         if (!bs || !outinfo)
    277                 return 0;
    278 
    279         outinfo->exchange = aimbs_get16(bs);
    280         namelen = aimbs_get8(bs);
    281         outinfo->name = aimbs_getstr(bs, namelen);
    282         outinfo->instance = aimbs_get16(bs);
    283 
    284         return 0;
    285 }
    286 
    287 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name)
    288 {
    289         aim_conn_t *conn;
    290 
    291         if (!(conn = aim_chat_getconn(sess, name)))
    292                 return -ENOENT;
    293 
    294         aim_conn_close(conn);
    295 
    296         return 0;
    297 }
    298 
    299 /*
    300  * conn must be a BOS connection!
    301  */
    302 faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance)
    303 {
    304         int i;
    305         aim_frame_t *fr;
    306         aim_msgcookie_t *cookie;
    307         struct aim_invite_priv *priv;
    308         fu8_t ckstr[8];
    309         aim_snacid_t snacid;
    310         aim_tlvlist_t *otl = NULL, *itl = NULL;
    311         fu8_t *hdr;
    312         int hdrlen;
    313         aim_bstream_t hdrbs;
    314        
    315         if (!sess || !conn || !sn || !msg || !roomname)
    316                 return -EINVAL;
    317 
    318         if (conn->type != AIM_CONN_TYPE_BOS)
    319                 return -EINVAL;
    320 
    321         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
    322                 return -ENOMEM;
    323 
    324         snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
    325         aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    326 
    327 
    328         /*
    329          * Cookie
    330          */
    331         for (i = 0; i < sizeof(ckstr); i++)
    332                 aimutil_put8(ckstr, (fu8_t) rand());
    333 
    334         /* XXX should be uncached by an unwritten 'invite accept' handler */
    335         if ((priv = malloc(sizeof(struct aim_invite_priv)))) {
    336                 priv->sn = strdup(sn);
    337                 priv->roomname = strdup(roomname);
    338                 priv->exchange = exchange;
    339                 priv->instance = instance;
    340         }
    341 
    342         if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv)))
    343                 aim_cachecookie(sess, cookie);
    344         else
    345                 free(priv);
    346 
    347         for (i = 0; i < sizeof(ckstr); i++)
    348                 aimbs_put8(&fr->data, ckstr[i]);
    349 
    350 
    351         /*
    352          * Channel (2)
    353          */
    354         aimbs_put16(&fr->data, 0x0002);
    355 
    356         /*
    357          * Dest sn
    358          */
    359         aimbs_put8(&fr->data, strlen(sn));
    360         aimbs_putraw(&fr->data, sn, strlen(sn));
    361 
    362         /*
    363          * TLV t(0005)
    364          *
    365          * Everything else is inside this TLV.
    366          *
    367          * Sigh.  AOL was rather inconsistent right here.  So we have
    368          * to play some minor tricks.  Right inside the type 5 is some
    369          * raw data, followed by a series of TLVs. 
    370          *
    371          */
    372         hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2;
    373         hdr = malloc(hdrlen);
    374         aim_bstream_init(&hdrbs, hdr, hdrlen);
    375        
    376         aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
    377         aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */
    378         aim_putcap(&hdrbs, AIM_CAPS_CHAT);
    379 
    380         aim_addtlvtochain16(&itl, 0x000a, 0x0001);
    381         aim_addtlvtochain_noval(&itl, 0x000f);
    382         aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg);
    383         aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
    384         aim_writetlvchain(&hdrbs, &itl);
    385        
    386         aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
    387 
    388         aim_writetlvchain(&fr->data, &otl);
    389 
    390         free(hdr);
    391         aim_freetlvchain(&itl);
    392         aim_freetlvchain(&otl);
    393        
    394         aim_tx_enqueue(sess, fr);
    395 
    396         return 0;
    397 }
    398 
    399 /*
    400  * General room information.  Lots of stuff.
     568 * Subtype 0x0006
    401569 *
    402  * Values I know are in here but I havent attached
    403  * them to any of the 'Unknown's:
    404  *      - Language (English)
    405  *
    406  * SNAC 000e/0002
    407  */
    408 static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    409 {
    410         aim_userinfo_t *userinfo = NULL;
    411         aim_rxcallback_t userfunc;
    412         int ret = 0;
    413         int usercount = 0;
    414         fu8_t detaillevel = 0;
    415         char *roomname = NULL;
    416         struct aim_chat_roominfo roominfo;
    417         fu16_t tlvcount = 0;
    418         aim_tlvlist_t *tlvlist;
    419         char *roomdesc = NULL;
    420         fu16_t flags = 0;
    421         fu32_t creationtime = 0;
    422         fu16_t maxmsglen = 0, maxvisiblemsglen = 0;
    423         fu16_t unknown_d2 = 0, unknown_d5 = 0;
    424 
    425         dumpbox(sess, bs->data + bs->offset, aim_bstream_empty(bs));
    426 
    427         aim_chat_readroominfo(bs, &roominfo);
    428 
    429         detaillevel = aimbs_get8(bs);
    430 
    431         if (detaillevel != 0x02) {
    432                 faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
    433                 return 1;
    434         }
    435 
    436         tlvcount = aimbs_get16(bs);
    437 
    438         /*
    439          * Everything else are TLVs.
    440          */
    441         tlvlist = aim_readtlvchain(bs);
    442 
    443         /*
    444          * TLV type 0x006a is the room name in Human Readable Form.
    445          */
    446         if (aim_gettlv(tlvlist, 0x006a, 1))
    447                 roomname = aim_gettlv_str(tlvlist, 0x006a, 1);
    448 
    449         /*
    450          * Type 0x006f: Number of occupants.
    451          */
    452         if (aim_gettlv(tlvlist, 0x006f, 1))
    453                 usercount = aim_gettlv16(tlvlist, 0x006f, 1);
    454 
    455         /*
    456          * Type 0x0073:  Occupant list.
    457          */
    458         if (aim_gettlv(tlvlist, 0x0073, 1)) {   
    459                 int curoccupant = 0;
    460                 aim_tlv_t *tmptlv;
    461                 aim_bstream_t occbs;
    462 
    463                 tmptlv = aim_gettlv(tlvlist, 0x0073, 1);
    464 
    465                 /* Allocate enough userinfo structs for all occupants */
    466                 userinfo = calloc(usercount, sizeof(aim_userinfo_t));
    467 
    468                 aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);
    469 
    470                 while (curoccupant < usercount)
    471                         aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);
    472         }
    473 
    474         /*
    475          * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
    476          */
    477         if (aim_gettlv(tlvlist, 0x00c9, 1))
    478                 flags = aim_gettlv16(tlvlist, 0x00c9, 1);
    479 
    480         /*
    481          * Type 0x00ca: Creation time (4 bytes)
    482          */
    483         if (aim_gettlv(tlvlist, 0x00ca, 1))
    484                 creationtime = aim_gettlv32(tlvlist, 0x00ca, 1);
    485 
    486         /*
    487          * Type 0x00d1: Maximum Message Length
    488          */
    489         if (aim_gettlv(tlvlist, 0x00d1, 1))
    490                 maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1);
    491 
    492         /*
    493          * Type 0x00d2: Unknown. (2 bytes)
    494          */
    495         if (aim_gettlv(tlvlist, 0x00d2, 1))
    496                 unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1);
    497 
    498         /*
    499          * Type 0x00d3: Room Description
    500          */
    501         if (aim_gettlv(tlvlist, 0x00d3, 1))
    502                 roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1);
    503 
    504         /*
    505          * Type 0x000d4: Unknown (flag only)
    506          */
    507         if (aim_gettlv(tlvlist, 0x000d4, 1))
    508                 ;
    509 
    510         /*
    511          * Type 0x00d5: Unknown. (1 byte)
    512          */
    513         if (aim_gettlv(tlvlist, 0x00d5, 1))
    514                 unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1);
    515 
    516 
    517         /*
    518          * Type 0x00d6: Encoding 1 ("us-ascii")
    519          */
    520         if (aim_gettlv(tlvlist, 0x000d6, 1))
    521                 ;
    522        
    523         /*
    524          * Type 0x00d7: Language 1 ("en")
    525          */
    526         if (aim_gettlv(tlvlist, 0x000d7, 1))
    527                 ;
    528 
    529         /*
    530          * Type 0x00d8: Encoding 2 ("us-ascii")
    531          */
    532         if (aim_gettlv(tlvlist, 0x000d8, 1))
    533                 ;
    534        
    535         /*
    536          * Type 0x00d9: Language 2 ("en")
    537          */
    538         if (aim_gettlv(tlvlist, 0x000d9, 1))
    539                 ;
    540 
    541         /*
    542          * Type 0x00da: Maximum visible message length
    543          */
    544         if (aim_gettlv(tlvlist, 0x000da, 1))
    545                 maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1);
    546 
    547         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
    548                 ret = userfunc(sess,
    549                                 rx,
    550                                 &roominfo,
    551                                 roomname,
    552                                 usercount,
    553                                 userinfo,       
    554                                 roomdesc,
    555                                 flags,
    556                                 creationtime,
    557                                 maxmsglen,
    558                                 unknown_d2,
    559                                 unknown_d5,
    560                                 maxvisiblemsglen);
    561         }
    562 
    563         free(roominfo.name);
    564         free(userinfo);
    565         free(roomname);
    566         free(roomdesc);
    567         aim_freetlvchain(&tlvlist);
    568 
    569         return ret;
    570 }
    571 
    572 static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    573 {
    574         aim_userinfo_t *userinfo = NULL;
    575         aim_rxcallback_t userfunc;
    576         int curcount = 0, ret = 0;
    577 
    578         while (aim_bstream_empty(bs)) {
    579                 curcount++;
    580                 userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t));
    581                 aim_extractuserinfo(sess, bs, &userinfo[curcount-1]);
    582         }
    583 
    584         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    585                 ret = userfunc(sess, rx, curcount, userinfo);
    586 
    587         free(userinfo);
    588 
    589         return ret;
    590 }
    591 
    592 /*
    593570 * We could probably include this in the normal ICBM parsing
    594571 * code as channel 0x0003, however, since only the start
     
    734711        return 0;
    735712}
    736 
    737 
  • libfaim/chatnav.c

    r5e53c4a r862371b  
    11/*
    2  * Handle ChatNav.
    3  *
    4  * [The ChatNav(igation) service does various things to keep chat
    5  *  alive.  It provides room information, room searching and creating,
    6  *  as well as giving users the right ("permission") to use chat.]
     2 * Family 0x000d - Handle ChatNav.
     3 *
     4 * The ChatNav(igation) service does various things to keep chat
     5 * alive.  It provides room information, room searching and creating,
     6 * as well as giving users the right ("permission") to use chat.
    77 *
    88 */
     
    1212
    1313/*
     14 * Subtype 0x0002
     15 *
    1416 * conn must be a chatnav connection!
     17 *
    1518 */
    1619faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn)
     
    1922}
    2023
     24/*
     25 * Subtype 0x0008
     26 */
    2127faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange)
    2228{
     
    346352
    347353/*
     354 * Subtype 0x0009
     355 *
    348356 * Since multiple things can trigger this callback, we must lookup the
    349357 * snacid to determine the original snac subtype that was called.
     
    416424
    417425        mod->family = 0x000d;
    418         mod->version = 0x0001;
     426        mod->version = 0x0003;
    419427        mod->toolid = 0x0010;
    420428        mod->toolversion = 0x047c;
  • libfaim/conn.c

    r5e53c4a r862371b  
    1 
    21/*
    32 * conn.c
     
    1514#include <sys/socket.h>
    1615#include <netinet/in.h>
     16#endif
     17
     18#ifdef _WIN32
     19#include "win32dep.h"
    1720#endif
    1821
     
    446449                        i = 3;
    447450                }
    448 
    449451                if (write(fd, buf, i) < i) {
    450452                        *statusret = errno;
     
    452454                        return -1;
    453455                }
    454 
    455456                if (read(fd, buf, 2) < 2) {
    456457                        *statusret = errno;
     
    502503                        return -1;
    503504                }
     505
    504506                if (read(fd, buf, 10) < 10) {
    505507                        *statusret = errno;
     
    877879        sess->modlistv = NULL;
    878880
     881        sess->ssi.received_data = 0;
     882        sess->ssi.waiting_for_ack = 0;
     883        sess->ssi.holding_queue = NULL;
     884        sess->ssi.revision = 0;
     885        sess->ssi.items = NULL;
     886        sess->ssi.timestamp = (time_t)0;
     887
     888        sess->emailinfo = NULL;
     889
    879890        /*
    880891         * Default to SNAC login unless XORLOGIN is explicitly set.
     
    909920        aim__registermodule(sess, chatnav_modfirst);
    910921        aim__registermodule(sess, chat_modfirst);
    911         /* missing 0x0f - 0x12 */
     922        aim__registermodule(sess, newsearch_modfirst);
     923        /* missing 0x10 - 0x12 */
    912924        aim__registermodule(sess, ssi_modfirst);
    913925        /* missing 0x14 */
    914         aim__registermodule(sess, icq_modfirst);
     926        aim__registermodule(sess, icq_modfirst); /* XXX - Make sure this isn't sent for AIM */
    915927        /* missing 0x16 */
    916928        aim__registermodule(sess, auth_modfirst);
     929        aim__registermodule(sess, email_modfirst);
    917930
    918931        return;
     
    981994        fd_set fds, wfds;
    982995        struct timeval tv;
    983         int res, error = ETIMEDOUT;
     996        int res;
     997        int error = ETIMEDOUT;
     998
    984999        aim_rxcallback_t userfunc;
    9851000
     
    10091024        if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
    10101025                int len = sizeof(error);
    1011 
    10121026                if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
    10131027                        error = errno;
     
    10191033                return -1;
    10201034        }
    1021 
    10221035        fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
    10231036
     
    10541067
    10551068        return 0;
    1056 
    10571069}
    10581070
     
    10611073 *
    10621074 * No-op.  WinAIM 4.x sends these _every minute_ to keep
    1063  * the connection alive. 
     1075 * the connection alive.
    10641076 */
    10651077faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn)
     
    10741086        return 0;
    10751087}
    1076 
    1077 
  • libfaim/ft.c

    r5e53c4a r862371b  
    1010#endif
    1111#include <aim.h>
    12 
    1312
    1413#ifndef _WIN32
     
    1716#include <netinet/in.h>
    1817#include <sys/utsname.h> /* for aim_directim_initiate */
    19 
    2018#include <arpa/inet.h> /* for inet_ntoa */
    21 
     19#define G_DIR_SEPARATOR '/'
    2220#endif
    2321
    24 /* TODO:
    25    o look for memory leaks.. there's going to be shitloads, i'm sure.
    26 */
     22#ifdef _WIN32
     23#include "win32dep.h"
     24#endif
     25
     26#define AIM_OFT_PROTO_OFFER          0x0101
     27#define AIM_OFT_PROTO_ACCEPT         0x0202
     28#define AIM_OFT_PROTO_RESUME         0x0205
     29#define AIM_OFT_PROTO_RESUMEACCEPT   0x0207
     30#define AIM_OFT_PROTO_ACK            0x0204
     31
     32struct aim_filetransfer_priv {
     33        char sn[MAXSNLEN+1];
     34        char cookie[8];
     35        char ip[30];
     36        int state;
     37        struct aim_fileheader_t fh;
     38};
    2739
    2840struct aim_directim_intdata {
     
    3345
    3446static int listenestablish(fu16_t portnum);
     47static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs);
     48static void oft_dirconvert(char *name);
     49static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh);
    3550 
    3651/**
     
    90105                aim_rxcallback_t userfunc;
    91106
    92 
    93107                newconn->priv = cur->priv;
    94108                cur->priv = NULL;
     
    100114                        ret = userfunc(sess, NULL, newconn, cur);
    101115#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);
    102129        } else {
    103130                faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n");
     
    110137
    111138/**
     139 * aim_send_typing - send client-to-client typing notification over established connection
     140 * @sess: session to conn
     141 * @conn: directim connection
     142 * @typing: If true, notify user has started typing; if false, notify user has stopped.
     143 *
     144 * The connection must have been previously established.
     145 */
     146faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
     147{
     148        struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
     149        aim_frame_t *fr;
     150        aim_bstream_t *hdrbs;
     151        fu8_t *hdr;
     152        int hdrlen = 0x44;
     153
     154        if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
     155                return -EINVAL;
     156
     157        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
     158                return -ENOMEM;
     159        memcpy(fr->hdr.rend.magic, "ODC2", 4);
     160        fr->hdr.rend.hdrlen = hdrlen;
     161
     162        if (!(hdr = calloc(1, hdrlen))) {
     163                aim_frame_destroy(fr);
     164                return -ENOMEM;
     165        }
     166
     167        hdrbs = &(fr->data);
     168        aim_bstream_init(hdrbs, hdr, hdrlen);
     169
     170        aimbs_put16(hdrbs, 0x0006);
     171        aimbs_put16(hdrbs, 0x0000);
     172        aimbs_putraw(hdrbs, intdata->cookie, 8);
     173        aimbs_put16(hdrbs, 0x0000);
     174        aimbs_put16(hdrbs, 0x0000);
     175        aimbs_put16(hdrbs, 0x0000);
     176        aimbs_put16(hdrbs, 0x0000);
     177        aimbs_put32(hdrbs, 0x00000000);
     178        aimbs_put16(hdrbs, 0x0000);
     179        aimbs_put16(hdrbs, 0x0000);
     180        aimbs_put16(hdrbs, 0x0000);
     181
     182        /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
     183        aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
     184
     185        aimbs_put16(hdrbs, 0x0000);
     186        aimbs_put16(hdrbs, 0x0000);
     187        aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
     188       
     189        aim_bstream_setpos(hdrbs, 52); /* bleeehh */
     190
     191        aimbs_put8(hdrbs, 0x00);
     192        aimbs_put16(hdrbs, 0x0000);
     193        aimbs_put16(hdrbs, 0x0000);
     194        aimbs_put16(hdrbs, 0x0000);
     195        aimbs_put16(hdrbs, 0x0000);
     196        aimbs_put16(hdrbs, 0x0000);
     197        aimbs_put16(hdrbs, 0x0000);
     198        aimbs_put16(hdrbs, 0x0000);
     199        aimbs_put8(hdrbs, 0x00);
     200
     201        /* end of hdr */
     202
     203        aim_tx_enqueue(sess, fr);
     204
     205        return 0;
     206}
     207
     208/**
    112209 * aim_send_im_direct - send IM client-to-client over established connection
    113210 * @sess: session to conn
    114211 * @conn: directim connection
    115  * @msg: null-terminated string to send; if this is NULL, it will send a "typing" notice.
    116  *
     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 *
    117216 * Call this just like you would aim_send_im, to send a directim. You
    118217 * _must_ have previously established the directim connection.
    119218 */
    120 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg)
     219faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
    121220{
    122221        struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
    123222        aim_frame_t *fr;
    124         aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */
    125 
    126         if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
     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))
    127228                return -EINVAL;
    128229
    129         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, strlen(msg))))
    130                return -ENOMEM; 
    131 
    132         memcpy(fr->hdr.oft.magic, "ODC2", 4);
     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;
    133235       
    134         fr->hdr.oft.hdr2len = 0x44;
    135        
    136         if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) {
     236        if (!(hdr = calloc(1, hdrlen + len))) {
    137237                aim_frame_destroy(fr);
    138238                return -ENOMEM;
    139239        }
     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);
    140255       
    141         aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
    142 
    143         aimbs_put16(&hdrbs, 0x0006);
    144         aimbs_put16(&hdrbs, 0x0000);
    145         aimbs_putraw(&hdrbs, intdata->cookie, 8);
    146         aimbs_put16(&hdrbs, 0x0000);
    147         aimbs_put16(&hdrbs, 0x0000);
    148         aimbs_put16(&hdrbs, 0x0000);
    149         aimbs_put16(&hdrbs, 0x0000);
    150         aimbs_put32(&hdrbs, strlen(msg));
    151         aimbs_put16(&hdrbs, 0x0000);
    152         aimbs_put16(&hdrbs, 0x0000);
    153         aimbs_put16(&hdrbs, 0x0000);
    154 
    155         /* flags -- 0x000e for "typing", 0x0000 for message */
    156         aimbs_put16(&hdrbs, msg ? 0x0000 : 0x000e);
    157 
    158         aimbs_put16(&hdrbs, 0x0000);
    159         aimbs_put16(&hdrbs, 0x0000);
    160         aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn));
    161 
    162         aim_bstream_setpos(&hdrbs, 52); /* bleeehh */
    163 
    164         aimbs_put8(&hdrbs, 0x00);
    165         aimbs_put16(&hdrbs, 0x0000);
    166         aimbs_put16(&hdrbs, 0x0000);
    167         aimbs_put16(&hdrbs, 0x0000);
    168         aimbs_put16(&hdrbs, 0x0000);
    169         aimbs_put16(&hdrbs, 0x0000);
    170         aimbs_put16(&hdrbs, 0x0000);
    171         aimbs_put16(&hdrbs, 0x0000);
    172 
     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       
    173275        /* end of hdr2 */
    174 
    175         if (msg) {
     276       
    176277#if 0 /* XXX this is how you send buddy icon info... */
    177                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);
    178                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);
    179                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
    180                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);
    181                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);
    182                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
    183                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
    184                 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
     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);
    185286#endif
    186                 aimbs_putraw(&fr->data, msg, strlen(msg));
    187         }
    188 
     287        aimbs_putraw(hdrbs, msg, len);
     288       
    189289        aim_tx_enqueue(sess, fr);
    190 
     290       
    191291        return 0;
    192292}
     
    279379 *
    280380 */
    281 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize)
     381faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret)
    282382{
    283383        aim_conn_t *newconn;
    284384        aim_msgcookie_t *cookie;
    285         struct aim_directim_intdata *priv;
     385        struct aim_filetransfer_priv *ft;
    286386        int listenfd;
     387
     388        /* XXX allow different ports */
    287389        fu16_t port = 4443;
    288390        fu8_t localip[4];
     
    299401        cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
    300402        memcpy(cookie->cookie, ck, 8);
    301         cookie->type = AIM_COOKIETYPE_OFTIM;
     403        cookie->type = AIM_COOKIETYPE_OFTSEND;
     404        memcpy(cookret, ck, 8);
    302405
    303406        /* this one is for the cookie */
    304         priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
    305 
    306         memcpy(priv->cookie, ck, 8);
    307         strncpy(priv->sn, destsn, sizeof(priv->sn));
    308         cookie->data = priv;
     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;
    309412        aim_cachecookie(sess, cookie);
    310413
    311         /* XXX switch to aim_cloneconn()? */
    312414        if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) {
    313415                close(listenfd);
     
    316418
    317419        /* this one is for the conn */
    318         priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
    319 
    320         memcpy(priv->cookie, ck, 8);
    321         strncpy(priv->sn, destsn, sizeof(priv->sn));
     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));
    322424
    323425        newconn->fd = listenfd;
    324426        newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
    325         newconn->internal = priv;
     427        newconn->internal = ft;
    326428        newconn->lastactivity = time(NULL);
    327429
     
    335437 * unsigned int aim_oft_listener_clean - close up old listeners
    336438 * @sess: session to clean up in
    337  * @age: maximum age in seconds 
     439 * @age: maximum age in seconds
    338440 *
    339441 * returns number closed, -1 on error.
    340442 */
    341 faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time_t age)
    342 {
    343   struct aim_conn_t *cur;
    344   time_t now;
    345   unsigned int hit = 0;
    346  
    347   if (!sess)
    348     return -1;
    349   now = time(NULL);
    350   faim_mutex_lock(&sess->connlistlock);
    351   for(cur = sess->connlist;cur; cur = cur->next)
    352     if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
    353       faim_mutex_lock(&cur->active);
    354       if (cur->lastactivity < (now - age) ) {
    355         faim_mutex_unlock(&cur->active);
    356         aim_conn_close(cur);
    357         hit++;
    358       } else
    359         faim_mutex_unlock(&cur->active);
    360     }
    361   faim_mutex_unlock(&sess->connlistlock);
    362   return hit;
    363 }
    364 #endif
     443faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age)
     444{
     445        aim_conn_t *cur;
     446        time_t now;
     447        unsigned int hit = 0;
     448
     449        if (!sess)
     450                return -1;
     451        now = time(NULL);
     452
     453        for(cur = sess->connlist;cur; cur = cur->next)
     454                if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
     455                        if (cur->lastactivity < (now - age) ) {
     456                                aim_conn_close(cur);
     457                                hit++;
     458                        }
     459                }
     460        return hit;
     461}
     462#endif
    365463
    366464faim_export const char *aim_directim_getsn(aim_conn_t *conn)
     
    369467
    370468        if (!conn)
    371                return NULL;
     469                return NULL;
    372470
    373471        if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
    374472                        (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
    375                return NULL;
     473                return NULL;
    376474
    377475        if (!conn->internal)
     
    432530 * aim_directim_getconn - find a directim conn for buddy name
    433531 * @sess: your session,
    434  * @name: the name to get, 
     532 * @name: the name to get,
    435533 *
    436534 * returns conn for directim with name, %NULL if none found.
     
    466564 * @cookie: the cookie used
    467565 * @ip: the ip to connect to
     566 * @port: the port to use
     567 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)
     568 *
    468569 * @listingfiles: number of files to share
    469570 * @listingtotsize: total size of shared files
    470571 * @listingsize: length of the listing file(buffer)
    471572 * @listingchecksum: checksum of the listing
    472  * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) 
    473573 *
    474574 * Returns new connection or %NULL on error.
     
    476576 * XXX this should take a struct.
    477577 */
    478 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess,
    479                                                   aim_conn_t *conn,
    480                                                   const char *sn, const fu8_t *cookie,
    481                                                   const fu8_t *ip,
    482                                                   fu16_t listingfiles,
    483                                                   fu16_t listingtotsize,
    484                                                   fu16_t listingsize,
    485                                                   fu32_t listingchecksum,
    486                                                   fu16_t rendid)
    487 {
    488        return NULL;     
     578faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn,
     579                                                const fu8_t *cookie, const fu8_t *ip,
     580                                                fu16_t port, fu16_t rendid, ...)
     581{
     582        aim_frame_t *newpacket;
     583        aim_conn_t *newconn;
     584        struct aim_filetransfer_priv *priv;
     585        int i;
     586        char addr[21];
     587
     588        if (!sess || !conn || !sn || !cookie || !ip) {
     589                return NULL;
     590        }
     591
     592        /* OSCAR CAP accept packet */
     593
     594        if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
     595                return NULL;
     596        }
     597
     598        aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
     599
     600        for (i = 0; i < 8; i++)
     601                aimbs_put8(&newpacket->data, cookie[i]);
     602
     603        aimbs_put16(&newpacket->data, 0x0002);
     604        aimbs_put8(&newpacket->data, strlen(sn));
     605        aimbs_putraw(&newpacket->data, sn, strlen(sn));
     606        aimbs_put16(&newpacket->data, 0x0005);
     607        aimbs_put16(&newpacket->data, 0x001a);
     608        aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT);
     609
     610        for (i = 0; i < 8; i++) /* yes, again... */
     611                aimbs_put8(&newpacket->data, cookie[i]);
     612
     613        aim_putcap(&newpacket->data, rendid);
     614        aim_tx_enqueue(sess, newpacket);
     615
     616        snprintf(addr, sizeof(addr), "%s:%d", ip, port);
     617        newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
     618
     619        if (newconn->status & AIM_CONN_STATUS_CONNERR) {
     620                return NULL;
     621        }
     622
     623        if (!newconn || (newconn->fd == -1)) {
     624                perror("aim_newconn");
     625        faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
     626                return newconn;
     627        }
     628
     629        priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
     630
     631        memcpy(priv->cookie, cookie, 8);
     632        priv->state = 0;
     633        strncpy(priv->sn, sn, MAXSNLEN);
     634        strncpy(priv->ip, ip, sizeof(priv->ip));
     635        newconn->internal = (void *)priv;
     636
     637        faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
     638
     639        if (rendid == AIM_CAPS_GETFILE) {
     640                return NULL; /* This should never happen for now. -- wtm */
     641
    489642#if 0
    490   struct command_tx_struct *newpacket, *newoft;
    491   struct aim_conn_t *newconn;
    492   struct aim_fileheader_t *fh;
    493   struct aim_filetransfer_priv *priv;
    494   struct aim_msgcookie_t *cachedcook;
    495   int curbyte, i;
    496 
    497   if (!sess || !conn || !sn || !cookie || !ip) {
    498     return NULL;
    499   }
    500 
    501   newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip);
    502 
    503   if (!newconn || (newconn->fd == -1)) {
    504     perror("aim_newconn");
    505     faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
    506     return newconn;
    507   } else {
    508     priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
    509 
    510     memcpy(priv->cookie, cookie, 8);
    511     priv->state = 0;
    512     strncpy(priv->sn, sn, MAXSNLEN);
    513     strncpy(priv->ip, ip, sizeof(priv->ip));
    514     newconn->priv = (void *)priv;
    515 
    516     faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
    517   }
    518 
    519   if (rendid == AIM_CAPS_GETFILE)  {
    520     newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
    521 
    522       faimdprintf(sess, 2, "faim: getfile request accept\n");
    523 
    524       if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) {
    525         faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
    526         /* XXX: conn leak here */
    527         return NULL;
    528       }
    529 
    530       newoft->lock = 1;
    531       memcpy(newoft->hdr.oft.magic, "OFT2", 4);
    532       newoft->hdr.oft.hdr2len = 0x100 - 8;
    533 
    534       if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
    535         /* XXX: conn leak here */
    536         perror("calloc");
    537         return NULL;
    538       }
    539 
    540       fh->encrypt = 0x0000;
    541       fh->compress = 0x0000;
    542       fh->totfiles = listingfiles;
    543       fh->filesleft = listingfiles;      /* is this right -- total parts and parts left?*/
    544       fh->totparts = 0x0001;
    545       fh->partsleft = 0x0001;
    546       fh->totsize = listingtotsize;
    547       fh->size = listingsize;      /* ls -l listing.txt */
    548       fh->modtime = (int)time(NULL); /* we'll go with current time for now */
    549       fh->checksum = listingchecksum;
    550       fh->rfcsum = 0x00000000;
    551       fh->rfsize = 0x00000000;
    552       fh->cretime = 0x00000000;
    553       fh->rfcsum = 0x00000000;
    554       fh->nrecvd = 0x00000000;
    555       fh->recvcsum = 0x00000000;
    556       memset(fh->idstring, 0, sizeof(fh->idstring));
    557       memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
    558       fh->flags = 0x02;
    559       fh->lnameoffset = 0x1a;
    560       fh->lsizeoffset = 0x10;
    561       memset(fh->dummy, 0, sizeof(fh->dummy));
    562       memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
    563 
    564       /* we need to figure out these encodings for filenames */
    565       fh->nencode = 0x0000;
    566       fh->nlanguage = 0x0000;
    567       memset(fh->name, 0, sizeof(fh->name));
    568       memcpy(fh->name, "listing.txt", sizeof(fh->name));
    569 
    570       if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
    571         newoft->lock = 0;
    572         aim_frame_destroy(newoft);
    573         /* XXX: conn leak */
    574         perror("calloc (1)");
    575         return NULL;
    576       }
    577 
    578       memcpy(fh->bcookie, cookie, 8);
    579 
    580       if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
    581         faimdprintf(sess, 1, "eek, bh fail!\n");
    582 
    583       newoft->lock = 0;
    584       aim_tx_enqueue(sess, newoft);
    585    
    586       if (!(cachedcook = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) {
    587         faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
    588         /* XXX: more cleanup, conn leak */
    589         perror("calloc (2)");
    590         return NULL;
    591       }
    592 
    593       memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
    594       memcpy(cachedcook->cookie, cookie, 8);
    595 
    596       cachedcook->type = AIM_COOKIETYPE_OFTGET;
    597       cachedcook->data = (void *)priv;
    598 
    599       if (aim_cachecookie(sess, cachedcook) == -1)
    600         faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
    601 
    602       free(fh);     
    603  
    604       /* OSCAR CAP accept packet */
    605    
    606       if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
    607         return NULL;
    608       }
    609   } else {
    610     return NULL;
    611   }
    612  
    613   newpacket->lock = 1;
    614   curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
    615 
    616   for (i = 0; i < 8; i++)
    617     curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
    618 
    619   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
    620   curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn));
    621   curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn));
    622   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
    623   curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a);
    624   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept*/);
    625 
    626   for (i = 0;i < 8; i++)
    627     curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
    628 
    629   curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid);
    630   newpacket->lock = 0;
    631   aim_tx_enqueue(sess, newpacket);
    632 
    633   return newconn;
     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);
    634734#endif
     735
     736        } else if (rendid == AIM_CAPS_SENDFILE) {
     737                newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
     738                priv->fh.recvcsum = 0xffff0000;
     739        } else {
     740                return NULL;
     741        }
     742
     743        return newconn;
     744}
     745
     746/* conn is a BOS connection over which to send the cancel msg */
     747faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
     748                const char *cookie, const char *sn, int rendid)
     749{
     750        aim_frame_t *newpacket;
     751        int i;
     752
     753        if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
     754                return 1;
     755        }
     756
     757        aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
     758
     759        for (i = 0; i < 8; i++)
     760                aimbs_put8(&newpacket->data, cookie[i]);
     761
     762        aimbs_put16(&newpacket->data, 0x0002);
     763        aimbs_put8(&newpacket->data, strlen(sn));
     764        aimbs_putraw(&newpacket->data, sn, strlen(sn));
     765        aimbs_put16(&newpacket->data, 0x0005);
     766        aimbs_put16(&newpacket->data, 0x001a);
     767        aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
     768
     769        for (i = 0; i < 8; i++)
     770                aimbs_put8(&newpacket->data, cookie[i]);
     771
     772        aim_putcap(&newpacket->data, rendid);
     773        aim_tx_enqueue(sess, newpacket);
     774
     775        return 0;
    635776}
    636777
    637778/**
    638779 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
    639  *  @file is an opened listing file
     780 * @file is an opened listing file
    640781 *
    641782 * returns a pointer to the filled-in fileheader_t
     
    649790        return NULL;
    650791#if 0
    651   struct aim_fileheader_t *fh;
    652   u_long totsize = 0, size = 0, checksum = 0xffff0000;
    653   short totfiles = 0;
    654   char *linebuf, sizebuf[9];
    655  
    656   int linelength = 1024;
    657 
    658   /* XXX: if we have a line longer than 1024chars, God help us. */
    659   if ( (linebuf = (char *)calloc(1, linelength)) == NULL ) {
    660     faimdprintf(sess, 2, "linebuf calloc failed\n");
    661     return NULL;
    662   } 
    663 
    664   if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
    665     perror("getlisting END1 fseek:");
    666     faimdprintf(sess, 2, "getlising fseek END1 error\n");
    667   }
    668 
    669   if ((size = ftell(file)) == -1) {
    670     perror("getlisting END1 getpos:");
    671     faimdprintf(sess, 2, "getlising getpos END1 error\n");
    672   }
    673 
    674   if (fseek(file, 0, SEEK_SET) != 0) {
    675     perror("getlesting fseek(SET):");
    676     faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
    677   }
    678 
    679   memset(linebuf, 0, linelength);
    680 
    681   size = 0;
    682 
    683   while(fgets(linebuf,  linelength, file)) {
    684     totfiles++;
    685     memset(sizebuf, 0, 9);
    686 
    687     size += strlen(linebuf);
    688    
    689     if (strlen(linebuf) < 23) {
    690       faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
    691       continue;
    692     }
    693     if (linebuf[strlen(linebuf)-1] != '\n') {
    694       faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
    695     }
    696 
    697     memcpy(sizebuf, linebuf+17, 8);
    698 
    699     totsize += strtol(sizebuf, NULL, 10);
    700     memset(linebuf, 0, linelength);
    701   }   
    702 
    703   if (fseek(file, 0, SEEK_SET) == -1) {
    704     perror("getlisting END2 fseek:");
    705     faimdprintf(sess, 2, "getlising fseek END2 error\n");
    706   } 
    707 
    708   free(linebuf);
    709 
    710   /* we're going to ignore checksumming the data for now -- that
    711   * requires walking the whole listing.txt. it should probably be
    712    * done at register time and cached, but, eh. */ 
    713 
    714   if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
    715     return NULL;
    716 
    717   fh->encrypt    = 0x0000;
    718   fh->compress    = 0x0000;
    719   fh->totfiles    = totfiles;
    720   fh->filesleft   = totfiles; /* is this right ?*/
    721   fh->totparts    = 0x0001;
    722   fh->partsleft  = 0x0001;
    723   fh->totsize    = totsize;
    724   fh->size        = size; /* ls -l listing.txt */
    725   fh->modtime    = (int)time(NULL); /* we'll go with current time for now */
    726   fh->checksum    = checksum; /* XXX: checksum ! */
    727   fh->rfcsum      = 0x00000000;
    728   fh->rfsize      = 0x00000000;
    729   fh->cretime    = 0x00000000;
    730   fh->rfcsum      = 0x00000000;
    731   fh->nrecvd      = 0x00000000;
    732   fh->recvcsum    = 0x00000000;
    733 
    734   /* memset(fh->idstring, 0, sizeof(fh->idstring)); */
    735   memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
    736   memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
    737 
    738   fh->flags      = 0x02;
    739   fh->lnameoffset = 0x1a;
    740   fh->lsizeoffset = 0x10;
    741 
    742   /* memset(fh->dummy, 0, sizeof(fh->dummy)); */
    743   memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
    744 
    745   fh->nencode    = 0x0000; /* we need to figure out these encodings for filenames */
    746   fh->nlanguage  = 0x0000;
    747 
    748   /* memset(fh->name, 0, sizeof(fh->name)); */
    749   memcpy(fh->name, "listing.txt", sizeof(fh->name));
    750   memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
    751 
    752   faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
    753   return fh;
     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;
    754895#endif
    755896}
     
    757898/**
    758899 * aim_listenestablish - create a listening socket on a port.
    759  * @portnum: the port number to bind to. 
     900 * @portnum: the port number to bind to.
    760901 *
    761902 * you need to call accept() when it's connected. returns your fd
     
    784925        ressave = res;
    785926        do {
    786                 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);   
     927                listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    787928                if (listenfd < 0)
    788929                        continue;
     
    802943        }
    803944
     945        fcntl(listenfd, F_SETFL, O_NONBLOCK);
     946
    804947        freeaddrinfo(ressave);
    805948        return listenfd;
     
    834977                return -1;
    835978        }
     979        fcntl(listenfd, F_SETFL, O_NONBLOCK);
    836980        return listenfd;
    837981#endif
     
    849993                int ret = 0;
    850994                char *listing;
    851                 struct command_tx_struct *newoft;
     995                aim_frame_t *newoft;
    852996
    853997                if (!(listing = malloc(ft->fh.size)))
     
    8601004                if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) {
    8611005                        faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n");
    862                         faim_mutex_unlock(&conn->active);
    8631006                        free(listing);
    8641007                        aim_conn_close(conn);
     
    8961039                /* waiting on file data */
    8971040                if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) )
    898                         return userfunc(sess, NULL, conn, ft);
     1041                        return userfunc(sess, NULL, conn, ft->fh.name,
     1042                                        ft->fh.size);
    8991043                return 0;
    9001044        }
     
    9161060{
    9171061        aim_msgcookie_t *cook;
    918         struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv;
     1062        struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->internal;
    9191063
    9201064        cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND);
     
    9261070static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn)
    9271071{
    928        
    9291072        free(conn->internal);
    9301073
     
    9341077static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn)
    9351078{
     1079#if 0
    9361080        aim_msgcookie_t *cook;
    9371081        struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv;
     
    9391083        cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET);
    9401084        aim_cookie_free(sess, cook);
    941 
     1085#endif
    9421086        return;
    9431087}
     
    10021146}
    10031147
    1004 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
     1148static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
    10051149{
    10061150        aim_frame_t fr;
    10071151        aim_rxcallback_t userfunc;
    10081152        fu32_t payloadlength;
    1009         fu16_t flags;
     1153        fu16_t flags, encoding;
    10101154        char *snptr = NULL;
    10111155
    10121156        fr.conn = conn;
    10131157
    1014         payloadlength = aimutil_get32(hdr+22);
    1015         flags = aimutil_get16(hdr+32);
    1016         snptr = (char *)hdr+38;
     1158        /* XXX ugly */
     1159        aim_bstream_setpos(bs, 20);
     1160        payloadlength = aimbs_get32(bs);
     1161
     1162        aim_bstream_setpos(bs, 24);
     1163        encoding = aimbs_get16(bs);
     1164
     1165        aim_bstream_setpos(bs, 30);
     1166        flags = aimbs_get16(bs);
     1167
     1168        aim_bstream_setpos(bs, 36);
     1169        /* XXX -create an aimbs_getnullstr function? */
     1170        snptr = aimbs_getstr(bs, MAXSNLEN);
    10171171
    10181172        faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr);
    10191173
    1020         if (flags == 0x000e) {
     1174        if (flags & 0x0002) {
    10211175                int ret = 0;
    10221176
     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
    10231183                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
    1024                         ret = userfunc(sess, &fr, snptr);
     1184                        ret = userfunc(sess, &fr, snptr, 0);
    10251185
    10261186                return ret;
    10271187
    1028         } else if ((flags == 0x0000) && payloadlength) {
    1029                 char *msg;
     1188        } else if (((flags & 0x000f) == 0x0000) && payloadlength) {
     1189                char *msg, *msg2;
    10301190                int ret = 0;
     1191                int recvd = 0;
     1192                int i;
    10311193
    10321194                if (!(msg = calloc(1, payloadlength+1)))
    10331195                        return -1;
    1034 
    1035                 if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) {
    1036                         free(msg);
    1037                         return -1;
     1196                msg2 = msg;
     1197               
     1198                while (payloadlength - recvd) {
     1199                        if (payloadlength - recvd >= 1024)
     1200                                i = aim_recv(conn->fd, msg2, 1024);
     1201                        else
     1202                                i = aim_recv(conn->fd, msg2, payloadlength - recvd);
     1203                        if (i <= 0) {
     1204                                free(msg);
     1205                                return -1;
     1206                        }
     1207                        recvd = recvd + i;
     1208                        msg2 = msg2 + i;
     1209                        if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
     1210                                userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
    10381211                }
    1039 
    1040                 msg[payloadlength] = '\0';
    1041 
     1212               
    10421213                if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
    1043                         ret = userfunc(sess, &fr, snptr, msg);
     1214                        ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
    10441215
    10451216                free(msg);
     
    10571228        struct aim_fileheader_t *fh;
    10581229        struct aim_msgcookie_t *cook;
    1059         struct command_tx_struct *newoft;
     1230        aim_frame_t *newoft;
    10601231        aim_rxcallback_t userfunc;
    10611232
     
    10811252                faimdprintf(sess, 1, "error caching cookie\n");
    10821253                return -1;
    1083         }     
     1254        }
    10841255
    10851256        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) {
     
    11211292
    11221293        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
    1123                 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n",  AIM_COOKIETYPE_OFTGET, fh->bcookie);
     1294                faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);
    11241295
    11251296        ft = cook->data;
     
    11731344#if 0
    11741345        struct aim_filetransfer_priv *ft;
    1175         struct aim_msgcookie_t *cook;
     1346        aim_msgcookie_t *cook;
    11761347        struct aim_fileheader_t *fh;
    1177         struct command_tx_struct *newoft;
     1348        aim_frame_t *newoft;
    11781349        int i = 0;
    11791350        aim_rxcallback_t userfunc;
     
    12051376        }
    12061377
    1207         newoft->lock = 1;
    12081378        memcpy(newoft->hdr.oft.magic, "OFT2", 4);
    12091379        newoft->hdr.oft.hdr2len = 0x100 - 8;
     
    12211391        aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
    12221392
    1223         newoft->lock = 0;
    12241393        aim_tx_enqueue(sess, newoft);
    12251394
     
    12881457}
    12891458
     1459/* We are receiving a file, and the buddy sent us this header describing
     1460 * it.  We send back a similar header to confirm, then we're ready to
     1461 * start reading the raw data.
     1462 */
     1463static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
     1464{
     1465        struct aim_filetransfer_priv *ft;
     1466        struct aim_fileheader_t *fh;
     1467        aim_frame_t *newoft;
     1468        aim_rxcallback_t userfunc;
     1469
     1470        fh = aim_oft_getfh(bs);
     1471
     1472        /* We receive a null cookie for the first file; we must fill
     1473         * it in to authenticate ourselves. -- wtm
     1474         */
     1475        ft = conn->internal;
     1476        memcpy(&(fh->bcookie), ft->cookie, 8);
     1477
     1478        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
     1479        free(fh);
     1480
     1481        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) {
     1482                faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
     1483                return -1;
     1484        }
     1485
     1486        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
     1487                return -1;
     1488        }
     1489        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
     1490        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
     1491
     1492        aim_tx_enqueue(sess, newoft);
     1493
     1494        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL)
     1495                return 1;
     1496
     1497        {
     1498                char *cur;
     1499                /* Convert the directory separator: it is sent
     1500                 * as ^A (0x01).
     1501                 */
     1502                while ((cur = strchr(ft->fh.name, 0x01))) {
     1503                        *cur = G_DIR_SEPARATOR;
     1504                }
     1505        }
     1506        return userfunc(sess, NULL, conn, &(ft->fh));
     1507}
     1508
     1509
     1510/*
     1511 * These were originally described by Josh Myer:
     1512 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/
     1513 * XXX this doesn't actually work yet
     1514 * -- wtm
     1515 */
     1516static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
     1517        aim_frame_t *newoft;
     1518        aim_msgcookie_t *cook;
     1519        struct aim_fileheader_t *fh;
     1520        struct aim_filetransfer_priv *ft;
     1521
     1522        fh = aim_oft_getfh(bs);
     1523        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
     1524                free(fh);
     1525                return -1;
     1526        }
     1527        ft = (struct aim_filetransfer_priv *)cook->data;
     1528
     1529        ft->fh.nrecvd = fh->nrecvd;
     1530        ft->fh.recvcsum = fh->recvcsum;
     1531        strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
     1532        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
     1533                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
     1534                free(fh);
     1535                return -1;
     1536        }
     1537
     1538        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
     1539                aim_frame_destroy(newoft);
     1540                free(fh);
     1541                return -1;
     1542        }
     1543        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
     1544        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
     1545
     1546        aim_tx_enqueue(sess, newoft);
     1547        free(fh);
     1548
     1549        return 0;
     1550}
     1551
     1552/* We are sending a file, and the buddy sent us this header indicating
     1553 * that he or she is ready for the raw data.
     1554 */
     1555static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
     1556        struct aim_fileheader_t *fh;
     1557        aim_msgcookie_t *cook;
     1558        int ret = 1;
     1559        struct aim_filetransfer_priv *ft;
     1560        aim_rxcallback_t userfunc;
     1561       
     1562        fh = aim_oft_getfh(bs);
     1563        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
     1564                free(fh);
     1565                return -1;
     1566        }
     1567        ft = (struct aim_filetransfer_priv *)cook->data;
     1568
     1569        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILESEND)) )
     1570                ret = userfunc(sess, NULL, conn, &(ft->fh));
     1571
     1572        free(fh);
     1573
     1574        return ret;
     1575}
     1576
    12901577static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
    12911578{
    12921579#if 0
    12931580        struct aim_fileheader_t *fh;
    1294         struct aim_filetransfer_priv *ft;
    12951581        struct aim_msgcookie_t *cook;
    12961582        int ret = 1;
    12971583        aim_rxcallback_t userfunc;
     1584        struct aim_filetransfer_priv *ft;
    12981585
    12991586        fh = aim_oft_getfh(hdr);
     
    13191606}
    13201607
     1608/* We just sent the raw data of a file, and the buddy sent us back this
     1609 * header indicating that the transfer is complete.
     1610 */
     1611static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
     1612{
     1613        struct aim_fileheader_t *fh;
     1614        aim_msgcookie_t *cook;
     1615        aim_rxcallback_t userfunc;
     1616
     1617        fh = aim_oft_getfh(bs);
     1618
     1619        if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
     1620                free(fh);
     1621                return -1;
     1622        }
     1623
     1624        if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILECOMPLETE)) )
     1625                userfunc(sess, NULL, conn, fh->bcookie);
     1626
     1627        free(fh);
     1628        return 0;
     1629}
     1630
    13211631static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
    13221632{
     
    13381648}
    13391649
    1340 /**
    1341  * aim_get_command_rendezvous - OFT equivalent of aim_get_command
    1342  * @sess: session to work on
    1343  * @conn: conn to pull data from
    1344  *
    1345  * this reads and handles data from conn->fd. currently a little rough
    1346  * around the edges
    1347  */
    1348 faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn)
    1349 {
    1350         fu8_t hdrbuf1[6];
    1351         fu8_t *hdr = NULL;
    1352         int hdrlen, hdrtype;
     1650faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
     1651{
     1652        aim_conn_t *conn = fr->conn;
     1653        aim_bstream_t *bs = &fr->data;
    13531654        int ret = -1;
    13541655
    1355         if (!sess || !conn)
    1356                 return -1;
    1357 
    1358         memset(hdrbuf1, 0, sizeof(hdrbuf1));
    1359 
    1360         /* I guess? I didn't understand any of that mess... */
    1361         if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE)
     1656        if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
     1657                /* This should never happen. -- wtm */
    13621658                return getcommand_getfile(sess, conn);
    13631659
    1364         /* XXX fix all the error cases here */
    1365         if (aim_recv(conn->fd, hdrbuf1, 6) < 6) {
    1366 
    1367                 faimdprintf(sess, 2, "faim: rend: read error (fd: %i)\n", conn->fd);
    1368 
    1369                 aim_conn_close(conn);
    1370 
    1371                 return -1;
    1372         }
    1373 
    1374         hdrlen = aimutil_get16(hdrbuf1+4);
    1375         hdrlen -= 6;
    1376 
    1377         hdr = malloc(hdrlen);
    1378 
    1379         if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) {
    1380                 faimdprintf(sess, 2, "faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen);
    1381                 free(hdr);
    1382                 aim_conn_close(conn);
    1383                 return -1;
    1384         }
    1385 
    1386         hdrtype = aimutil_get16(hdr);
    1387 
    1388         if (hdrtype == 0x0001)
    1389                 ret = handlehdr_directim(sess, conn, hdr);
    1390         else if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
    1391                 ret = handlehdr_getfile_listing(sess, conn, hdr);
    1392         else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
    1393                 ret = handlehdr_getfile_listing2(sess, conn, hdr);
    1394         else if (hdrtype == 0x120b) /* get file listing rx confirm */
    1395                 ret = handlehdr_getfile_listing3(sess, conn, hdr);
    1396         else if (hdrtype == 0x120c) /* getfile request */
    1397                 ret = handlehdr_getfile_request(sess, conn, hdr);
    1398         else if (hdrtype == 0x0101) /* getfile sending data */
    1399                 ret = handlehdr_getfile_sending(sess, conn, hdr);
    1400         else if (hdrtype == 0x0202) /* getfile recv data */
    1401                 ret = handlehdr_getfile_recv(sess, conn, hdr);
    1402         else if (hdrtype == 0x0204) /* getfile finished */
    1403                 ret = handlehdr_getfile_finish(sess, conn, hdr);
    1404         else {
    1405                 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
    1406                 ret = -1;
     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                }
    14071709        }
    14081710       
    1409         free(hdr);
    1410 
    14111711        if (ret == -1)
    14121712                aim_conn_close(conn);
     
    14151715}
    14161716
    1417 #if 0
    14181717/**
    14191718 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr.
    1420  * @hdr: buffer to extract header from 
    1421  *
    1422  * returns pointer to new struct on success; %NULL on error. 
    1423  *
    1424  */
    1425 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr)
    1426 {
    1427   struct aim_fileheader_t *fh;
    1428   int i, j;
    1429   if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
    1430     return NULL;
    1431  
    1432   /* [0] and [1] are the type. we can ignore those here. */
    1433   i = 2;
    1434   for(j = 0; j < 8; j++, i++)
    1435     fh->bcookie[j] = hdr[i];
    1436   fh->encrypt = aimutil_get16(hdr+i);
    1437   i += 2;
    1438   fh->compress = aimutil_get16(hdr+i);
    1439   i += 2;
    1440   fh->totfiles = aimutil_get16(hdr+i);
    1441   i += 2;
    1442   fh->filesleft = aimutil_get16(hdr+i);
    1443   i += 2;
    1444   fh->totparts = aimutil_get16(hdr+i);
    1445   i += 2;
    1446   fh->partsleft = aimutil_get16(hdr+i);
    1447   i += 2;
    1448   fh->totsize = aimutil_get32(hdr+i);
    1449   i += 4;
    1450   fh->size = aimutil_get32(hdr+i);
    1451   i += 4;
    1452   fh->modtime = aimutil_get32(hdr+i);
    1453   i += 4;
    1454   fh->checksum = aimutil_get32(hdr+i);
    1455   i += 4;
    1456   fh->rfrcsum = aimutil_get32(hdr+i);
    1457   i += 4;
    1458   fh->rfsize = aimutil_get32(hdr+i);
    1459   i += 4;
    1460   fh->cretime = aimutil_get32(hdr+i);
    1461   i += 4;
    1462   fh->rfcsum = aimutil_get32(hdr+i);
    1463   i += 4;
    1464   fh->nrecvd = aimutil_get32(hdr+i);
    1465   i += 4;
    1466   fh->recvcsum = aimutil_get32(hdr+i);
    1467   i += 4;
    1468   memcpy(fh->idstring, hdr+i, 32);
    1469   i += 32;
    1470   fh->flags = aimutil_get8(hdr+i);
    1471   i += 1;
    1472   fh->lnameoffset = aimutil_get8(hdr+i);
    1473   i += 1;
    1474   fh->lsizeoffset = aimutil_get8(hdr+i);
    1475   i += 1;
    1476   memcpy(fh->dummy, hdr+i, 69);
    1477   i += 69;
    1478   memcpy(fh->macfileinfo, hdr+i, 16);
    1479   i += 16;
    1480   fh->nencode = aimutil_get16(hdr+i);
    1481   i += 2;
    1482   fh->nlanguage = aimutil_get16(hdr+i);
    1483   i += 2;
    1484   memcpy(fh->name, hdr+i, 64);
    1485   i += 64;
    1486   return fh;
     1719 * @bs: bstream to extract header from
     1720 *
     1721 * returns pointer to new struct on success; %NULL on error.
     1722 *
     1723 */
     1724static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
     1725{
     1726        struct aim_fileheader_t *fh;
     1727
     1728        if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
     1729                return NULL;
     1730
     1731        /* The bstream should be positioned after the hdrtype. */
     1732        aimbs_getrawbuf(bs, fh->bcookie, 8);
     1733        fh->encrypt = aimbs_get16(bs);
     1734        fh->compress = aimbs_get16(bs);
     1735        fh->totfiles = aimbs_get16(bs);
     1736        fh->filesleft = aimbs_get16(bs);
     1737        fh->totparts = aimbs_get16(bs);
     1738        fh->partsleft = aimbs_get16(bs);
     1739        fh->totsize = aimbs_get32(bs);
     1740        fh->size = aimbs_get32(bs);
     1741        fh->modtime = aimbs_get32(bs);
     1742        fh->checksum = aimbs_get32(bs);
     1743        fh->rfrcsum = aimbs_get32(bs);
     1744        fh->rfsize = aimbs_get32(bs);
     1745        fh->cretime = aimbs_get32(bs);
     1746        fh->rfcsum = aimbs_get32(bs);
     1747        fh->nrecvd = aimbs_get32(bs);
     1748        fh->recvcsum = aimbs_get32(bs);
     1749        aimbs_getrawbuf(bs, fh->idstring, 32);
     1750        fh->flags = aimbs_get8(bs);
     1751        fh->lnameoffset = aimbs_get8(bs);
     1752        fh->lsizeoffset = aimbs_get8(bs);
     1753        aimbs_getrawbuf(bs, fh->dummy, 69);
     1754        aimbs_getrawbuf(bs, fh->macfileinfo, 16);
     1755        fh->nencode = aimbs_get16(bs);
     1756        fh->nlanguage = aimbs_get16(bs);
     1757        aimbs_getrawbuf(bs, fh->name, 64); /* XXX */
     1758
     1759        return fh;
    14871760}
    1488 #endif
    14891761
    14901762/**
     
    14921764 * @buffer: buffer of data to checksum
    14931765 * @bufsize: size of buffer
    1494  * @checksum: pointer to integer to place result in (pointer!)
    1495  *
    1496  *
    1497  * Note that checksum is a pointer. Checksum should be filled with
    1498  * 0xFFFF0000 for each new file; you can have this checksum chunks of
    1499  * files in series if you just call it repeatedly in a for(; ; ) loop
    1500  * and don't reset the checksum between each call. And you thought we
    1501  * didn't care about you and your pathetic client's meomry footprint
    1502  * ;^)
    1503  *
    1504  *
    1505  * Also, it's been said that this is incorrect as currently
    1506  * written. You were warned.
    1507  */
    1508 faim_export fu32_t aim_oft_checksum(aim_session_t *sess, const char *buffer, int bufsize, fu32_t *checksum)
    1509 {
    1510         return 0xdeadbeef;
    1511 #if 0
    1512   fu16_t check0, check1;
    1513   int i;
    1514 
    1515   check0 = ((*checksum & 0xFF000000) >> 16);
    1516   check1 = ((*checksum & 0x00ff0000) >> 16);
    1517   for(i = 0; i < bufsize; i++) {
    1518     if (i % 2) { /* use check1 -- second byte */
    1519       if ( (short)buffer[i] > check1 ) { /* wrapping */
    1520         check1 += 0x100;  /* this is a cheap way to wrap */
    1521 
    1522         /* if we're wrapping, decrement the other one */
    1523         /* XXX: check this corner case */
    1524         if (check0 == 0)
    1525           check0 = 0x00ff;
    1526         else
    1527           check0--;
    1528       }
    1529       check1 -= buffer[i];
    1530     } else { /* use check0 -- first byte  */
    1531       if ( (short)buffer[i] > check0 ) { /* wrapping */
    1532         check0 += 0x100;       /* this is a cheap way to wrap */
    1533  
    1534         /* if we're wrapping, decrement the other one */
    1535         /* XXX: check this corner case */
    1536         if (check1 == 0)
    1537           check1 = 0x00ff;
    1538         else
    1539           check1--;
    1540       }
    1541       check0 -= buffer[i];
    1542     }
    1543   }
    1544 
    1545   if (check0 > 0xff || check1 > 0xff)  {
    1546     /* they shouldn't be able to do this. error! */
    1547     faimdprintf(sess, 2, "check0 or check1 is too high: 0x%04x, 0x%04x\n", check0, check1);
    1548     return -1;
    1549   }
    1550 
    1551   /* grab just the lowest byte; this should be clean, but just in
    1552      case */
    1553   check0 &= 0xff;
    1554   check1 &= 0xff;
    1555 
    1556   *checksum = ((check0 * 0x1000000) + (check1 * 0x10000));
    1557   return *checksum;
    1558 #endif
    1559 }
    1560 
    1561 #if 0
     1766 * @prevcheck: previous checksum
     1767 *
     1768 * Prevcheck should be 0xFFFF0000 for each new file; you can have this
     1769 * checksum chunks of files in series if you just call it repeatedly in a
     1770 * for(; ; ) loop and don't reset the checksum between each call. And you
     1771 * thought we didn't care about you and your pathetic client's meomry
     1772 * footprint ;^)
     1773 *
     1774 * Thanks to Graham Booker for providing this improved checksum
     1775 * routine, which is simpler and should be more accurate than Josh
     1776 * Myer's original code. -- wtm
     1777 *
     1778 * This algorithim works every time I have tried it.  The other fails
     1779 * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
     1780 * checksum I have ever seen.
     1781 */
     1782faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) {
     1783        fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
     1784        int i;
     1785        unsigned short val;
     1786
     1787        for (i=0; i<bufferlen; i++) {
     1788                oldcheck = check;
     1789                if (i&1) {
     1790                        val = buffer[i];
     1791                } else {
     1792                        val = buffer[i] << 8;
     1793                }
     1794                check -= val;
     1795                /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */
     1796                if (check > oldcheck) {
     1797                        check--;
     1798                }
     1799        }
     1800        check = ((check & 0x0000ffff) + (check >> 16));
     1801        check = ((check & 0x0000ffff) + (check >> 16));
     1802        return check << 16;
     1803}
     1804
     1805faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
     1806                const unsigned char *buffer, int len) {
     1807        struct aim_filetransfer_priv *ft = conn->internal;
     1808
     1809        ft->fh.nrecvd += len;
     1810        ft->fh.recvcsum = aim_oft_checksum(buffer, len, ft->fh.recvcsum);
     1811
     1812        return 0;
     1813}
     1814
    15621815/**
    15631816 * aim_oft_buildheader - fills a buffer with network-order fh data
    1564  * @dest: buffer to fill -- pre-alloced
    1565  * @fh: fh to get data from 
    1566  *
    1567  * returns length written; -1 on error.
    1568  * DOES NOT DO BOUNDS CHECKING!
    1569  *
    1570  */
    1571 static int oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh)
     1817 * @bs: bstream to fill -- automatically initialized
     1818 * @fh: fh to get data from
     1819 *
     1820 * returns -1 on error.
     1821 *
     1822 */
     1823static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
    15721824{
    1573   int i, curbyte;
    1574   if (!dest || !fh)
    1575     return -1;
    1576   curbyte = 0;
    1577   for(i = 0; i < 8; i++)
    1578     curbyte += aimutil_put8(dest+curbyte, fh->bcookie[i]);
    1579   curbyte += aimutil_put16(dest+curbyte, fh->encrypt);
    1580   curbyte += aimutil_put16(dest+curbyte, fh->compress);
    1581   curbyte += aimutil_put16(dest+curbyte, fh->totfiles);
    1582   curbyte += aimutil_put16(dest+curbyte, fh->filesleft);
    1583   curbyte += aimutil_put16(dest+curbyte, fh->totparts);
    1584   curbyte += aimutil_put16(dest+curbyte, fh->partsleft);
    1585   curbyte += aimutil_put32(dest+curbyte, fh->totsize);
    1586   curbyte += aimutil_put32(dest+curbyte, fh->size);
    1587   curbyte += aimutil_put32(dest+curbyte, fh->modtime);
    1588   curbyte += aimutil_put32(dest+curbyte, fh->checksum);
    1589   curbyte += aimutil_put32(dest+curbyte, fh->rfrcsum);
    1590   curbyte += aimutil_put32(dest+curbyte, fh->rfsize);
    1591   curbyte += aimutil_put32(dest+curbyte, fh->cretime);
    1592   curbyte += aimutil_put32(dest+curbyte, fh->rfcsum);
    1593   curbyte += aimutil_put32(dest+curbyte, fh->nrecvd);
    1594   curbyte += aimutil_put32(dest+curbyte, fh->recvcsum);
    1595   memcpy(dest+curbyte, fh->idstring, 32);
    1596   curbyte += 32;
    1597   curbyte += aimutil_put8(dest+curbyte, fh->flags);
    1598   curbyte += aimutil_put8(dest+curbyte, fh->lnameoffset);
    1599   curbyte += aimutil_put8(dest+curbyte, fh->lsizeoffset);
    1600   memcpy(dest+curbyte, fh->dummy, 69);
    1601   curbyte += 69;
    1602   memcpy(dest+curbyte, fh->macfileinfo, 16);
    1603   curbyte += 16;
    1604   curbyte += aimutil_put16(dest+curbyte, fh->nencode);
    1605   curbyte += aimutil_put16(dest+curbyte, fh->nlanguage);
    1606   memset(dest+curbyte, 0x00, 64);
    1607   memcpy(dest+curbyte, fh->name, 64);
    1608 
    1609   /* XXX: Filenames longer than 64B  */
    1610   curbyte += 64;
    1611   return curbyte;
    1612 }
    1613 #endif
     1825        fu8_t *hdr;
     1826
     1827        if (!bs || !fh)
     1828                return -1;
     1829
     1830
     1831
     1832
     1833        if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
     1834                return -1;
     1835        }
     1836        aim_bstream_init(bs, hdr, 0x100 - 8);
     1837
     1838        aimbs_putraw(bs, fh->bcookie, 8);
     1839        aimbs_put16(bs, fh->encrypt);
     1840        aimbs_put16(bs, fh->compress);
     1841        aimbs_put16(bs, fh->totfiles);
     1842        aimbs_put16(bs, fh->filesleft);
     1843        aimbs_put16(bs, fh->totparts);
     1844        aimbs_put16(bs, fh->partsleft);
     1845        aimbs_put32(bs, fh->totsize);
     1846        aimbs_put32(bs, fh->size);
     1847        aimbs_put32(bs, fh->modtime);
     1848        aimbs_put32(bs, fh->checksum);
     1849        aimbs_put32(bs, fh->rfrcsum);
     1850        aimbs_put32(bs, fh->rfsize);
     1851        aimbs_put32(bs, fh->cretime);
     1852        aimbs_put32(bs, fh->rfcsum);
     1853        aimbs_put32(bs, fh->nrecvd);
     1854        aimbs_put32(bs, fh->recvcsum);
     1855        aimbs_putraw(bs, fh->idstring, 32);
     1856        aimbs_put8(bs, fh->flags);
     1857        aimbs_put8(bs, fh->lnameoffset);
     1858        aimbs_put8(bs, fh->lsizeoffset);
     1859        aimbs_putraw(bs, fh->dummy, 69);
     1860        aimbs_putraw(bs, fh->macfileinfo, 16);
     1861        aimbs_put16(bs, fh->nencode);
     1862        aimbs_put16(bs, fh->nlanguage);
     1863        aimbs_putraw(bs, fh->name, 64);
     1864
     1865        /* XXX: Filenames longer than 64B */
     1866        return 0;
     1867}
    16141868
    16151869/**
     
    16251879        return NULL;
    16261880#if 0
    1627   struct command_tx_struct *newpacket;
    1628   struct aim_conn_t *newconn;
    1629   struct aim_filetransfer_priv *priv;
    1630   struct aim_msgcookie_t *cookie;
    1631   int curbyte, i, listenfd;
    1632   short port = 4443;
    1633   struct hostent *hptr;
    1634   struct utsname myname;
    1635   char cap[16];
    1636   char d[4];
     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. */
    16371927 
    1638   /* Open our socket */
    1639 
    1640   if ( (listenfd = aim_listenestablish(port)) == -1)
    1641     return NULL;
    1642 
    1643   /* get our local IP */
    1644 
    1645   if (uname(&myname) < 0)
    1646     return NULL;
    1647   if ( (hptr = gethostbyname(myname.nodename)) == NULL)
    1648     return NULL;
    1649   memcpy(&d, hptr->h_addr_list[0], 4);
    1650 
    1651   aim_putcap(cap, 16, AIM_CAPS_GETFILE);
    1652 
    1653   /* create the OSCAR packet */
    1654 
    1655   if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
    1656     return NULL;
    1657   newpacket->lock = 1;
    1658 
    1659   /* lock struct */
    1660   curbyte = 0;
    1661   curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
    1662 
    1663   /* XXX: check the cookie before commiting to using it */
    1664 
    1665   /* Generate a random message cookie
    1666    * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
    1667   for (i=0; i<7; i++)
    1668     curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
    1669 
    1670   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
    1671 
    1672   /* grab all the data for cookie caching. */
     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 */
    16731979 
    1674   if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
    1675     return NULL;
    1676   memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
    1677   cookie->type = AIM_COOKIETYPE_OFTGET;
    1678 
    1679   if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
    1680     return NULL;
    1681   memcpy(priv->cookie, cookie, 8);
    1682   memcpy(priv->sn, destsn, sizeof(priv->sn));
    1683   memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
    1684   priv->state = 1;
    1685 
    1686   cookie->data = priv;
    1687 
    1688   aim_cachecookie(sess, cookie);
    1689 
    1690   /* Channel ID */
    1691   curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
    1692 
    1693   /* Destination SN (prepended with byte length) */
    1694   curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
    1695   curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
    1696   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
    1697   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
    1698 
    1699   /* enTLV start */
    1700   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
    1701   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
    1702 
    1703   /* Flag data / ICBM Parameters? */
    1704   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
    1705   curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
    1706 
    1707   /* Cookie */
    1708   curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
    1709 
    1710   /* Capability String */
    1711   curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
    1712 
    1713   /* 000a/0002 : 0001 */
    1714   curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
    1715   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
    1716   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
    1717 
    1718   /* 0003/0004: IP address */
    1719   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
    1720   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
    1721   for(i = 0; i < 4; i++)
    1722     curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
    1723 
    1724   /* already in network byte order  */
    1725  
    1726   /* 0005/0002: Port */
    1727   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
    1728   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
    1729   curbyte += aimutil_put16(newpacket->data+curbyte, port);
    1730 
    1731   /* 000f/0000: ?? */
    1732   curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
    1733   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
    1734 
    1735   /* 2711/000c: ?? */
    1736   curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
    1737   curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
    1738   curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
    1739 
    1740   for(i = 0; i < 0x000c - 4; i++)
    1741     curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
    1742 
    1743   newpacket->commandlen = curbyte;
    1744   newpacket->lock = 0;
    1745   aim_tx_enqueue(sess, newpacket);
    1746 
    1747   /* allocate and set up our connection */
    1748 
    1749   i = fcntl(listenfd, F_GETFL, 0);
    1750   fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
    1751   newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
    1752 
    1753   if (!newconn){
    1754     perror("aim_newconn");
    1755     return NULL;
    1756   }
    1757 
    1758   newconn->fd = listenfd;
    1759   newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
    1760   newconn->priv = priv;
    1761   faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
    1762 
    1763   return newconn;
     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;
    17642018#endif
    17652019}
     
    17752029 * returns -1 on error, 0 on successful enqueuing
    17762030 */
     2031#if 0
    17772032faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size)
    17782033{
    1779         return -EINVAL;
    1780 #if 0
    1781   struct command_tx_struct *newoft;
    1782   struct aim_filetransfer_priv *ft;
    1783   if (!sess || !conn || !conn->priv || !name)
    1784     return -1;
    1785 
    1786   if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
    1787     faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
    1788     return -1;
    1789   }
    1790 
    1791   newoft->lock = 1;
    1792 
    1793   memcpy(newoft->hdr.oft.magic, "OFT2", 4);
    1794   newoft->hdr.oft.hdr2len = 0x100 - 8;
    1795 
    1796   ft = (struct aim_filetransfer_priv *)conn->priv;
    1797   ft->fh.filesleft = 1;
    1798   ft->fh.totfiles = 1;
    1799   ft->fh.totparts = 1;
    1800   ft->fh.partsleft = 1;
    1801   ft->fh.totsize = size;
    1802   ft->fh.size = size;
    1803   ft->fh.checksum = 0;
    1804   memcpy(ft->fh.name, name, strlen(name));
    1805   memset(ft->fh.name+strlen(name), 0, 1);
    1806 
    1807   if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
    1808     newoft->lock = 0;
    1809     aim_frame_destroy(newoft);
    1810     return -1;
    1811   }
    1812 
    1813   if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
    1814     newoft->lock = 0;
    1815     aim_frame_destroy(newoft);
    1816     return -1;
    1817   }
    1818 
    1819   newoft->lock = 0;
    1820 
    1821   aim_tx_enqueue(sess, newoft);
    1822   return 0;
     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}
    18232070#endif
     2071
     2072/* Identify a file that we are about to send by transmitting the
     2073 * appropriate header.
     2074 */
     2075faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize)
     2076{
     2077        aim_frame_t *newoft;
     2078        aim_msgcookie_t *cook;
     2079        struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
     2080        struct aim_fileheader_t *fh;
     2081
     2082        if (!sess || !conn || !filename)
     2083                return -1;
     2084
     2085        if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
     2086                return -1;
     2087
     2088#ifdef DUMB_OFT_CHECKSUM
     2089        /* Yes, we are supposed to checksum the whole file before sending, and
     2090         * yes, it's dumb.  This is the only way to get some clients (such as
     2091         * Mac AIM v4.5.163) to successfully complete the transfer.  With
     2092         * the WinAIM clients, we seem to be able to get away with just
     2093         * setting the checksum to zero.
     2094         * -- wtm
     2095         */
     2096        {
     2097                int fd = open(filename, O_RDONLY);
     2098                if (fd >= 0) {
     2099                        int bytes;
     2100                        char buf[1024];
     2101                        fh->checksum = 0xffff0000;
     2102                        while ((bytes = aim_recv(fd, buf, 1024)) > 0) {
     2103                                fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
     2104                        }
     2105                }
     2106                close(fd);
     2107        }
     2108#else
     2109        fh->checksum = 0x00000000;
     2110#endif
     2111        fh->encrypt = 0x0000;
     2112        fh->compress = 0x0000;
     2113        fh->totfiles = numfiles;
     2114        fh->filesleft = numfiles - filesdone;
     2115        fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */
     2116        fh->partsleft = 0x0001;
     2117        fh->totsize = totsize;
     2118        fh->size = size;
     2119        fh->modtime = (int)time(NULL); /* we'll go with current time for now */
     2120        /* fh->checksum set above */
     2121        fh->rfcsum = 0x00000000;
     2122        fh->rfsize = 0x00000000;
     2123        fh->cretime = 0x00000000;
     2124        fh->rfcsum = 0x00000000;
     2125        fh->nrecvd = 0x00000000; /* always zero initially */
     2126        fh->recvcsum= 0x00000000; /* ditto */
     2127
     2128        strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
     2129        fh->flags = 0x02;
     2130        fh->lnameoffset = 0x1a;
     2131        fh->lsizeoffset = 0x10;
     2132        memset(fh->dummy, 0, sizeof(fh->dummy));
     2133        memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
     2134
     2135        /* apparently 0 is ASCII, 2 is UCS-2 */
     2136        /* it is likely that 3 is ISO 8859-1 */
     2137        fh->nencode = 0x0000;
     2138        fh->nlanguage = 0x0000;
     2139
     2140        /* Convert the directory separator to ^A for portability. */
     2141        strncpy(fh->name, filename, sizeof(fh->name));
     2142        oft_dirconvert(fh->name);
     2143
     2144        /* XXX we should normally send a null cookie here, and make
     2145         * the receiver fill it in for authentication -- wtm
     2146         */
     2147        memcpy(fh->bcookie, ft->cookie, 8);
     2148
     2149        if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
     2150                return -1;
     2151        }
     2152
     2153        /* Update both headers to be safe. */
     2154        memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
     2155        memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t));
     2156
     2157        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
     2158                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
     2159                free(fh);
     2160                return -1;
     2161        }
     2162
     2163        if (aim_oft_buildheader(&newoft->data, fh) == -1) {
     2164                aim_frame_destroy(newoft);
     2165                free(fh);
     2166                return -1;
     2167        }
     2168
     2169        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
     2170        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
     2171
     2172        aim_tx_enqueue(sess, newoft);
     2173        free(fh);
     2174        return 0;
    18242175}
    18252176 
     
    18372188        return -EINVAL;
    18382189#if 0
    1839   struct command_tx_struct *newoft;
    1840   struct aim_filetransfer_priv *ft;
    1841 
    1842   if (!sess || !conn || !conn->priv)
    1843     return -1;
    1844 
    1845   if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
    1846     faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
    1847     return -1;
    1848   }
    1849 
    1850   newoft->lock = 1;
    1851 
    1852   memcpy(newoft->hdr.oft.magic, "OFT2", 4);
    1853   newoft->hdr.oft.hdr2len = 0x100-8;
    1854 
    1855  if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
    1856    newoft->lock = 0;
    1857    aim_frame_destroy(newoft);
    1858    return -1;
    1859  }
    1860 
    1861  ft = (struct aim_filetransfer_priv *)conn->priv;
    1862 
    1863  if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
    1864    newoft->lock = 0;
    1865    aim_frame_destroy(newoft);
    1866    return -1;
    1867  }
    1868 
    1869  newoft->lock = 0;
    1870  aim_tx_enqueue(sess, newoft);
    1871  return 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;
    18722223#endif
    18732224}
    18742225 
    18752226/**
    1876  * aim_oft_getfile_end - end a getfile.
     2227 * aim_oft_end - end a getfile/sendfile.
    18772228 * @sess: your session
    18782229 * @conn: the getfile connection
     
    18812232 * receiving/requesting end.
    18822233 */
    1883 faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn)
    1884 {
    1885         return -EINVAL;
    1886 #if 0
    1887   struct command_tx_struct *newoft;
    1888   struct aim_filetransfer_priv *ft;
    1889  
    1890   if (!sess || !conn || !conn->priv)
    1891     return -1;
    1892 
    1893   if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0204, 0))) {
    1894     faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
    1895     return -1;
    1896   }
    1897  
    1898   newoft->lock = 1;
    1899  
    1900   memcpy(newoft->hdr.oft.magic, "OFT2", 4);
    1901   newoft->hdr.oft.hdr2len = 0x100 - 8;
    1902  
    1903   if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
    1904     newoft->lock = 0;
    1905     aim_frame_destroy(newoft);
    1906     return -1;
    1907   }
    1908  
    1909   ft = (struct aim_filetransfer_priv *)conn->priv;
    1910   ft->state = 4; /* no longer wanting data */
    1911   ft->fh.nrecvd = ft->fh.size;
    1912   ft->fh.recvcsum = ft->fh.checksum;
    1913   ft->fh.flags = 0x21;
    1914  
    1915   if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
    1916     newoft->lock = 0;
    1917     aim_frame_destroy(newoft);
    1918     return -1;
    1919   }
    1920  
    1921   newoft->lock = 0;
    1922   aim_tx_enqueue(sess, newoft);
    1923  
    1924   return 0;
    1925 #endif /* 0 */
    1926 }
    1927 
     2234faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn)
     2235{
     2236        aim_frame_t *newoft;
     2237        struct aim_filetransfer_priv *ft;
     2238
     2239        if (!sess || !conn || !conn->internal)
     2240                return -1;
     2241
     2242        if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) {
     2243                faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
     2244                return -1;
     2245        }
     2246
     2247        ft = (struct aim_filetransfer_priv *)conn->internal;
     2248        ft->state = 4; /* no longer wanting data */
     2249        ft->fh.flags = 0x21;
     2250
     2251        if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
     2252                aim_frame_destroy(newoft);
     2253                return -1;
     2254        }
     2255        memcpy(newoft->hdr.rend.magic, "OFT2", 4);
     2256        newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
     2257
     2258        aim_tx_enqueue(sess, newoft);
     2259
     2260        return 0;
     2261}
     2262
     2263/*
     2264 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability.
     2265 */
     2266static void oft_dirconvert(char *name) {
     2267        char *c = name;
     2268        while ((c = strchr(c, G_DIR_SEPARATOR)))
     2269                *c = 0x01;
     2270}
  • libfaim/icq.c

    r5e53c4a r862371b  
    11/*
    2  * Encapsulated ICQ.
     2 * Family 0x0015 - Encapsulated ICQ.
    33 *
    44 */
     
    263263        return 0;
    264264}
    265 
    266 
  • libfaim/im.c

    r5e53c4a r862371b  
    11/*
    2  *  aim_im.c
    3  *
    4  *  The routines for sending/receiving Instant Messages.
     2 *  Family 0x0004 - Routines for sending/receiving Instant Messages.
    53 *
    64 *  Note the term ICBM (Inter-Client Basic Message) which blankets
     
    119 *  is used for negotiating "rendezvous".  These transactions end in
    1210 *  something more complex happening, such as a chat invitation, or
    13  *  a file transfer.
     11 *  a file transfer.  Channel 3 is used for chat messages (not in
     12 *  the same family as these channels).  Channel 4 is used for
     13 *  various ICQ messages.  Examples are normal messages, URLs, and
     14 *  old-style authorization.
    1415 *
    1516 *  In addition to the channel, every ICBM contains a cookie.  For
     
    2223#define FAIM_INTERNAL
    2324#include <aim.h>
     25
     26#ifdef _WIN32
     27#include "win32dep.h"
     28#endif
    2429
    2530/*
     
    3742 *                                      4.3.2229, 4.4.2286
    3843 *  0501 0004 0101 0102 0101     WinAIM 4.1.2010, libfaim (right here)
     44 *  0501 0003 0101 02            WinAIM 5
     45 *  0501 0001 01                 iChat x.x
    3946 *  0501 0001 0101 01            AOL v6.0, CompuServe 2000 v6.0, any
    4047 *                                      TOC client
     
    8491}
    8592
     93/*
     94 * Subtype 0x0002
     95 *
     96 * I definitly recommend sending this.  If you don't, you'll be stuck
     97 * with the rather unreasonable defaults.  You don't want those.  Send this.
     98 *
     99 */
     100faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)
     101{
     102        aim_conn_t *conn;
     103        aim_frame_t *fr;
     104        aim_snacid_t snacid;
     105
     106        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     107                return -EINVAL;
     108
     109        if (!params)
     110                return -EINVAL;
     111
     112        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16)))
     113                return -ENOMEM;
     114
     115        snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
     116        aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
     117
     118        /* This is read-only (see Parameter Reply). Must be set to zero here. */
     119        aimbs_put16(&fr->data, 0x0000);
     120
     121        /* These are all read-write */
     122        aimbs_put32(&fr->data, params->flags);
     123        aimbs_put16(&fr->data, params->maxmsglen);
     124        aimbs_put16(&fr->data, params->maxsenderwarn);
     125        aimbs_put16(&fr->data, params->maxrecverwarn);
     126        aimbs_put32(&fr->data, params->minmsginterval);
     127
     128        aim_tx_enqueue(sess, fr);
     129
     130        return 0;
     131}
     132
     133/* Subtype 0x0004 - Request ICBM parameter information. */
     134faim_export int aim_reqicbmparams(aim_session_t *sess)
     135{
     136        aim_conn_t *conn;
     137
     138        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     139                return -EINVAL;
     140
     141        return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
     142}
     143
     144/* Subtype 0x0005 */
     145static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     146{
     147        struct aim_icbmparameters params;
     148        aim_rxcallback_t userfunc;
     149
     150        params.maxchan = aimbs_get16(bs);
     151        params.flags = aimbs_get32(bs);
     152        params.maxmsglen = aimbs_get16(bs);
     153        params.maxsenderwarn = aimbs_get16(bs);
     154        params.maxrecverwarn = aimbs_get16(bs);
     155        params.minmsginterval = aimbs_get32(bs);
     156       
     157        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     158                return userfunc(sess, rx, &params);
     159
     160        return 0;
     161}
     162
    86163/* This should be endian-safe now... but who knows... */
    87164faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen)
     
    101178
    102179/*
    103  * Send an ICBM (instant message). 
     180 * Subtype 0x0006 - Send an ICBM (instant message). 
    104181 *
    105182 *
     
    195272        }
    196273
    197 
    198274        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128)))
    199275                return -ENOMEM;
     
    315391        /*
    316392         * Set the I HAVE A REALLY PURTY ICON flag.
     393         * XXX - This should really only be sent on initial
     394         * IMs and when you change your icon.
    317395         */
    318396        if (args->flags & AIM_IMFLAGS_HASICON) {
     
    327405        /*
    328406         * Set the Buddy Icon Requested flag.
     407         * XXX - Everytime?  Surely not...
    329408         */
    330409        if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
     
    367446
    368447/*
     448 * Subtype 0x0006
     449 *
    369450 * This is also performance sensitive. (If you can believe it...)
    370451 *
     
    450531
    451532/*
     533 * Subtype 0x0006
     534 *
    452535 * This only works for ICQ 2001b (thats 2001 not 2000).  Better, only
    453536 * send it to clients advertising the RTF capability.  In fact, if you send
     
    565648}
    566649
     650/* Subtype 0x0006 */
    567651faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret)
    568652{
     
    641725}
    642726
     727/* Subtype 0x0006 */
    643728faim_internal int aim_request_sendfile(aim_session_t *sess, const char *sn, const char *filename, fu16_t numfiles, fu32_t totsize, fu8_t *ip, fu16_t port, fu8_t *ckret)
    644729{
     
    648733        aim_frame_t *fr;
    649734        aim_snacid_t snacid;
     735        struct aim_snac_destructor snacdest;
    650736
    651737        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     
    657743        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4)))
    658744                return -ENOMEM;
    659 
    660         snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
    661         aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    662745
    663746        for (i = 0; i < 7; i++)
     
    667750        if (ckret)
    668751                memcpy(ckret, ck, 8);
     752
     753        /* Fill in the snac destructor so we know if the request
     754         * times out.  Use the cookie in the data field, so we
     755         * know what request to cancel if there is an error.
     756         */
     757        snacdest.data = malloc(8);
     758        memcpy(snacdest.data, ck, 8);
     759        snacdest.conn = conn;
     760        snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, &snacdest, sizeof(snacdest));
     761        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    669762
    670763        /*
     
    720813
    721814        /* ? */
    722         aimbs_put16(&fr->data, 0x0001);
     815        aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001);
    723816        aimbs_put16(&fr->data, numfiles);
    724817        aimbs_put32(&fr->data, totsize);
     
    727820        /* ? */
    728821        aimbs_put32(&fr->data, 0x00000000);
     822
     823#if 0
     824        /* Newer clients seem to send this (?) -- wtm */
     825        aimbs_put32(&fr->data, 0x00030000);
     826#endif
     827
     828        aim_tx_enqueue(sess, fr);
     829
     830        return 0;
     831}
     832
     833/**
     834 * Subtype 0x0006 - Request the status message of the given ICQ user.
     835 *
     836 * @param sess The oscar session.
     837 * @param sn The UIN of the user of whom you wish to request info.
     838 * @param type The type of info you wish to request.  This should be the current
     839 *        state of the user, as one of the AIM_ICQ_STATE_* defines.
     840 * @return Return 0 if no errors, otherwise return the error number.
     841 */
     842faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type)
     843{
     844        aim_conn_t *conn;
     845        int i;
     846        fu8_t ck[8];
     847        aim_frame_t *fr;
     848        aim_snacid_t snacid;
     849
     850        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn)
     851                return -EINVAL;
     852
     853        for (i = 0; i < 8; i++)
     854                aimutil_put8(ck+i, (fu8_t) rand());
     855
     856        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4)))
     857                return -ENOMEM;
     858
     859        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
     860        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
     861
     862        /* Cookie */
     863        aimbs_putraw(&fr->data, ck, 8);
     864
     865        /* Channel (2) */
     866        aimbs_put16(&fr->data, 0x0002);
     867
     868        /* Dest sn */
     869        aimbs_put8(&fr->data, strlen(sn));
     870        aimbs_putraw(&fr->data, sn, strlen(sn));
     871
     872        /* TLV t(0005) - Encompasses almost everything below. */
     873        aimbs_put16(&fr->data, 0x0005); /* T */
     874        aimbs_put16(&fr->data, 0x005e); /* L */
     875        { /* V */
     876                aimbs_put16(&fr->data, 0x0000);
     877
     878                /* Cookie */
     879                aimbs_putraw(&fr->data, ck, 8);
     880
     881                /* Put the 16 byte server relay capability */
     882                aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY);
     883
     884                /* TLV t(000a) */
     885                aimbs_put16(&fr->data, 0x000a);
     886                aimbs_put16(&fr->data, 0x0002);
     887                aimbs_put16(&fr->data, 0x0001);
     888
     889                /* TLV t(000f) */
     890                aimbs_put16(&fr->data, 0x000f);
     891                aimbs_put16(&fr->data, 0x0000);
     892
     893                /* TLV t(2711) */
     894                aimbs_put16(&fr->data, 0x2711);
     895                aimbs_put16(&fr->data, 0x0036);
     896                { /* V */
     897                        aimbs_putle16(&fr->data, 0x001b); /* L */
     898                        aimbs_putle16(&fr->data, 0x0008); /* XXX - Protocol version */
     899                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     900                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     901                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     902                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     903                        aimbs_putle16(&fr->data, 0x0000); /* Unknown */
     904                        aimbs_putle16(&fr->data, 0x0003); /* Client features? */
     905                        aimbs_putle16(&fr->data, 0x0000); /* Unknown */
     906                        aimbs_putle8(&fr->data, 0x00); /* Unkizown */
     907                        aimbs_putle16(&fr->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
     908
     909                        aimbs_putle16(&fr->data, 0x000e); /* L */
     910                        aimbs_putle16(&fr->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
     911                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     912                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     913                        aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
     914
     915                        /* The type of status message being requested */
     916                        if (type & AIM_ICQ_STATE_CHAT)
     917                                aimbs_putle16(&fr->data, 0x03ec);
     918                        else if(type & AIM_ICQ_STATE_DND)
     919                                aimbs_putle16(&fr->data, 0x03eb);
     920                        else if(type & AIM_ICQ_STATE_OUT)
     921                                aimbs_putle16(&fr->data, 0x03ea);
     922                        else if(type & AIM_ICQ_STATE_BUSY)
     923                                aimbs_putle16(&fr->data, 0x03e9);
     924                        else if(type & AIM_ICQ_STATE_AWAY)
     925                                aimbs_putle16(&fr->data, 0x03e8);
     926
     927                        aimbs_putle16(&fr->data, 0x0000); /* Status? */
     928                        aimbs_putle16(&fr->data, 0x0001); /* Priority of this message? */
     929                        aimbs_putle16(&fr->data, 0x0001); /* L? */
     930                        aimbs_putle8(&fr->data, 0x00); /* Null termination? */
     931                } /* End TLV t(2711) */
     932        } /* End TLV t(0005) */
     933
     934        /* TLV t(0003) */
     935        aimbs_put16(&fr->data, 0x0003);
     936        aimbs_put16(&fr->data, 0x0000);
     937
     938        aim_tx_enqueue(sess, fr);
     939
     940        return 0;
     941}
     942
     943/**
     944 * Subtype 0x0006
     945 *
     946 * This can be used to send an ICQ authorization reply (deny or grant).  It is the "old way." 
     947 * The new way is to use SSI.  I like the new way a lot better.  This seems like such a hack,
     948 * mostly because it's in network byte order.  Figuring this stuff out sometimes takes a while,
     949 * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people
     950 * were taking when they merged the two protocols.
     951 *
     952 * @param sn The destination screen name.
     953 * @param type The type of message.  0x0007 for authorization denied.  0x0008 for authorization granted.
     954 * @param message The message you want to send, it should be null terminated.
     955 * @return Return 0 if no errors, otherwise return the error number.
     956 */
     957faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)
     958{
     959        aim_conn_t *conn;
     960        aim_frame_t *fr;
     961        aim_snacid_t snacid;
     962        int i;
     963
     964        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
     965                return -EINVAL;
     966
     967        if (!sn || !type || !message)
     968                return -EINVAL;
     969
     970        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+3+strlen(sn)+12+strlen(message)+1+4)))
     971                return -ENOMEM;
     972
     973        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
     974        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
     975
     976        /*
     977         * Cookie
     978         */
     979        for (i=0; i<8; i++)
     980                aimbs_put8(&fr->data, (fu8_t)rand());
     981
     982        /*
     983         * Channel (4)
     984         */
     985        aimbs_put16(&fr->data, 0x0004);
     986
     987        /*
     988         * Dest sn
     989         */
     990        aimbs_put8(&fr->data, strlen(sn));
     991        aimbs_putraw(&fr->data, sn, strlen(sn));
     992
     993        /*
     994         * TLV t(0005)
     995         *
     996         * ICQ data (the UIN and the message).
     997         */
     998        aimbs_put16(&fr->data, 0x0005);
     999        aimbs_put16(&fr->data, 4 + 2+2+strlen(message)+1);
     1000
     1001        /*
     1002         * Your UIN
     1003         */
     1004        aimbs_putle32(&fr->data, atoi(sess->sn));
     1005
     1006        /*
     1007         * TLV t(type) l(strlen(message)+1) v(message+NULL)
     1008         */
     1009        aimbs_putle16(&fr->data, type);
     1010        aimbs_putle16(&fr->data, strlen(message)+1);
     1011        aimbs_putraw(&fr->data, message, strlen(message)+1);
     1012
     1013        /*
     1014         * TLV t(0006) l(0000) v()
     1015         */
     1016        aimbs_put16(&fr->data, 0x0006);
     1017        aimbs_put16(&fr->data, 0x0000);
    7291018
    7301019        aim_tx_enqueue(sess, fr);
     
    11571446                        args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;
    11581447
     1448                } else if (type == 0x000b) { /* Non-direct connect typing notification */
     1449
     1450                        args.icbmflags |= AIM_IMFLAGS_TYPINGNOT;
     1451
    11591452                } else if (type == 0x0017) {
    11601453
     
    13311624}
    13321625
     1626static void incomingim_ch2_sendfile_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
     1627{
     1628        free(args->info.sendfile.filename);
     1629}
     1630
     1631static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata)
     1632{
     1633
     1634        args->destructor = (void *)incomingim_ch2_sendfile_free;
     1635
     1636        if (servdata) {
     1637                int flen;
     1638
     1639                /* subtype is one of AIM_OFT_SUBTYPE_* */
     1640                args->info.sendfile.subtype = aimbs_get16(servdata);
     1641                args->info.sendfile.totfiles = aimbs_get16(servdata);
     1642                args->info.sendfile.totsize = aimbs_get32(servdata);
     1643
     1644                /* XXX - create an aimbs_getnullstr function */
     1645                /* Use an inelegant way of getting the null-terminated filename,
     1646                 * since there's no easy bstream routine. */
     1647                for (flen = 0; aimbs_get8(servdata); flen++);
     1648                aim_bstream_advance(servdata, -flen -1);
     1649                args->info.sendfile.filename = aimbs_getstr(servdata, flen);
     1650
     1651                /* There is sometimes more after the null-terminated filename,
     1652                 * but I'm unsure of its format. */
     1653        }
     1654
     1655        return;
     1656}
     1657
    13331658typedef void (*ch2_args_destructor_t)(aim_session_t *sess, struct aim_incomingim_ch2_args *args);
    13341659
     
    13581683         * First two bytes represent the status of the connection.
    13591684         *
    1360          * 0 is a request, 1 is a deny (?), 2 is an accept
     1685         * 0 is a request, 1 is a cancel, 2 is an accept
    13611686         */
    13621687        args.status = aimbs_get16(&bbs);
     
    15021827        else if (args.reqclass & AIM_CAPS_ICQSERVERRELAY)
    15031828                incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);
     1829        else if (args.reqclass & AIM_CAPS_SENDFILE)
     1830                incomingim_ch2_sendfile(sess, mod, rx, snac, userinfo, &args, sdbsptr);
    15041831
    15051832
     
    15201847}
    15211848
     1849static int incomingim_ch4(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, fu8_t *cookie)
     1850{
     1851        aim_bstream_t meat;
     1852        aim_rxcallback_t userfunc;
     1853        aim_tlv_t *block;
     1854        struct aim_incomingim_ch4_args args;
     1855        int ret = 0;
     1856
     1857        /*
     1858         * Make a bstream for the meaty part.  Yum.  Meat.
     1859         */
     1860        if (!(block = aim_gettlv(tlvlist, 0x0005, 1)))
     1861                return -1;
     1862        aim_bstream_init(&meat, block->value, block->length);
     1863
     1864        args.uin = aimbs_getle32(&meat);
     1865        args.type = aimbs_getle16(&meat);
     1866        args.msg = aimbs_getraw(&meat, aimbs_getle16(&meat));
     1867
     1868        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1869                ret = userfunc(sess, rx, channel, userinfo, &args);
     1870
     1871        free(args.msg);
     1872
     1873        return ret;
     1874}
     1875
    15221876/*
     1877 * Subtype 0x0007
     1878 *
    15231879 * It can easily be said that parsing ICBMs is THE single
    15241880 * most difficult thing to do in the in AIM protocol.  In
     
    15571913         * is where Chat Invitiations and various client-client
    15581914         * connection negotiations come from.
    1559          *
     1915         *
     1916         * Channel 0x0004 is used for ICQ authorization, or
     1917         * possibly any system notice.
     1918         *
    15601919         */
    15611920        channel = aimbs_get16(bs);
     
    16031962                aim_freetlvchain(&tlvlist);
    16041963
     1964        } else if (channel == 4) {
     1965                aim_tlvlist_t *tlvlist;
     1966
     1967                tlvlist = aim_readtlvchain(bs);
     1968                ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
     1969                aim_freetlvchain(&tlvlist);
     1970
    16051971        } else {
    16061972
     
    16141980
    16151981/*
     1982 * Subtype 0x0008 - Send a warning to destsn.
     1983 *
     1984 * Flags:
     1985 *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much)
     1986 *
     1987 * returns -1 on error (couldn't alloc packet), 0 on success.
     1988 *
     1989 */
     1990faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags)
     1991{
     1992        aim_frame_t *fr;
     1993        aim_snacid_t snacid;
     1994        fu16_t outflags = 0x0000;
     1995
     1996        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13)))
     1997                return -ENOMEM;
     1998
     1999        snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1);
     2000
     2001        aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
     2002
     2003        if (flags & AIM_WARN_ANON)
     2004                outflags |= 0x0001;
     2005
     2006        aimbs_put16(&fr->data, outflags);
     2007        aimbs_put8(&fr->data, strlen(destsn));
     2008        aimbs_putraw(&fr->data, destsn, strlen(destsn));
     2009
     2010        aim_tx_enqueue(sess, fr);
     2011
     2012        return 0;
     2013}
     2014
     2015/* Subtype 0x000a */
     2016static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     2017{
     2018        int ret = 0;
     2019        aim_rxcallback_t userfunc;
     2020        fu16_t channel, nummissed, reason;
     2021        aim_userinfo_t userinfo;
     2022
     2023        while (aim_bstream_empty(bs)) {
     2024
     2025                channel = aimbs_get16(bs);
     2026                aim_extractuserinfo(sess, bs, &userinfo);
     2027                nummissed = aimbs_get16(bs);
     2028                reason = aimbs_get16(bs);
     2029
     2030                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     2031                         ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
     2032        }
     2033
     2034        return ret;
     2035}
     2036
     2037/*
     2038 * Subtype 0x000b
     2039 *
    16162040 * Possible codes:
    16172041 *    AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
     
    16522076
    16532077/*
    1654  * aim_reqicbmparaminfo()
    1655  *
    1656  * Request ICBM parameter information.
     2078 * Subtype 0x000b - Receive the response from an ICQ status message request.
     2079 *
     2080 * This contains the ICQ status message.  Go figure.
    16572081 *
    16582082 */
    1659 faim_export int aim_reqicbmparams(aim_session_t *sess)
    1660 {
    1661         aim_conn_t *conn;
    1662 
    1663         if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
    1664                 return -EINVAL;
    1665 
    1666         return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
    1667 }
    1668 
    1669 /*
    1670  *
    1671  * I definitly recommend sending this.  If you don't, you'll be stuck
    1672  * with the rather unreasonable defaults.  You don't want those.  Send this.
    1673  *
    1674  */
    1675 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)
    1676 {
    1677         aim_conn_t *conn;
    1678         aim_frame_t *fr;
    1679         aim_snacid_t snacid;
    1680 
    1681         if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
    1682                 return -EINVAL;
    1683 
    1684         if (!params)
    1685                 return -EINVAL;
    1686 
    1687         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16)))
    1688                 return -ENOMEM;
    1689 
    1690         snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
    1691         aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
    1692 
    1693         /* This is read-only (see Parameter Reply). Must be set to zero here. */
    1694         aimbs_put16(&fr->data, 0x0000);
    1695 
    1696         /* These are all read-write */
    1697         aimbs_put32(&fr->data, params->flags);
    1698         aimbs_put16(&fr->data, params->maxmsglen);
    1699         aimbs_put16(&fr->data, params->maxsenderwarn);
    1700         aimbs_put16(&fr->data, params->maxrecverwarn);
    1701         aimbs_put32(&fr->data, params->minmsginterval);
    1702 
    1703         aim_tx_enqueue(sess, fr);
    1704 
    1705         return 0;
    1706 }
    1707 
    1708 static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    1709 {
    1710         struct aim_icbmparameters params;
    1711         aim_rxcallback_t userfunc;
    1712 
    1713         params.maxchan = aimbs_get16(bs);
    1714         params.flags = aimbs_get32(bs);
    1715         params.maxmsglen = aimbs_get16(bs);
    1716         params.maxsenderwarn = aimbs_get16(bs);
    1717         params.maxrecverwarn = aimbs_get16(bs);
    1718         params.minmsginterval = aimbs_get32(bs);
    1719        
    1720         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1721                 return userfunc(sess, rx, &params);
    1722 
    1723         return 0;
    1724 }
    1725 
    1726 static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    1727 {
    1728         int ret = 0;
    1729         aim_rxcallback_t userfunc;
    1730         fu16_t channel, nummissed, reason;
    1731         aim_userinfo_t userinfo;
    1732 
    1733         while (aim_bstream_empty(bs)) {
    1734 
    1735                 channel = aimbs_get16(bs);
    1736                 aim_extractuserinfo(sess, bs, &userinfo);
    1737                 nummissed = aimbs_get16(bs);
    1738                 reason = aimbs_get16(bs);
    1739 
    1740                 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1741                          ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
    1742         }
    1743 
    1744         return ret;
    1745 }
    1746 
    1747 static int clienterr(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     2083static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    17482084{
    17492085        int ret = 0;
     
    17592095        reason = aimbs_get16(bs);
    17602096
    1761         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1762                  ret = userfunc(sess, rx, channel, sn, reason);
     2097        if (channel == 0x0002) { /* File transfer declined */
     2098                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     2099                        ret = userfunc(sess, rx, channel, sn, reason, ck);
     2100        } else if (channel == 0x0004) { /* ICQ message */
     2101                switch (reason) {
     2102                        case 0x0003: { /* ICQ status message.  Maybe other stuff too, you never know with these people. */
     2103                                fu8_t statusmsgtype, *msg;
     2104                                fu16_t len;
     2105                                fu32_t state;
     2106
     2107                                len = aimbs_getle16(bs); /* Should be 0x001b */
     2108                                aim_bstream_advance(bs, len); /* Unknown */
     2109
     2110                                len = aimbs_getle16(bs); /* Should be 0x000e */
     2111                                aim_bstream_advance(bs, len); /* Unknown */
     2112
     2113                                statusmsgtype = aimbs_getle8(bs);
     2114                                switch (statusmsgtype) {
     2115                                        case 0xe8:
     2116                                                state = AIM_ICQ_STATE_AWAY;
     2117                                                break;
     2118                                        case 0xe9:
     2119                                                state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
     2120                                                break;
     2121                                        case 0xea:
     2122                                                state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_OUT;
     2123                                                break;
     2124                                        case 0xeb:
     2125                                                state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
     2126                                                break;
     2127                                        case 0xec:
     2128                                                state = AIM_ICQ_STATE_CHAT;
     2129                                                break;
     2130                                        default:
     2131                                                state = 0;
     2132                                                break;
     2133                                }
     2134
     2135                                aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
     2136                                aimbs_getle16(bs); /* Unknown - 0x0000 */
     2137                                aimbs_getle16(bs); /* Unknown - 0x0000 */
     2138
     2139                                len = aimbs_getle16(bs);
     2140                                msg = aimbs_getraw(bs, len);
     2141
     2142                                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     2143                                        ret = userfunc(sess, rx, channel, sn, reason, state, msg);
     2144
     2145                                free(msg);
     2146                        } break;
     2147
     2148                        default: {
     2149                                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     2150                                        ret = userfunc(sess, rx, channel, sn, reason);
     2151                        } break;
     2152                } /* end switch */
     2153        }
    17632154
    17642155        free(ck);
     
    17682159}
    17692160
     2161/* Subtype 0x000c */
    17702162static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    17712163{
     
    17862178        free(sn);
    17872179        free(ck);
     2180
     2181        return ret;
     2182}
     2183
     2184/*
     2185 * Subtype 0x0014 - Send a mini typing notification (mtn) packet.
     2186 *
     2187 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
     2188 * and Gaim 0.60 and newer.
     2189 *
     2190 */
     2191faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2)
     2192{
     2193        aim_conn_t *conn;
     2194        aim_frame_t *fr;
     2195        aim_snacid_t snacid;
     2196
     2197        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
     2198                return -EINVAL;
     2199
     2200        if (!sn)
     2201                return -EINVAL;
     2202
     2203        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))
     2204                return -ENOMEM;
     2205
     2206        snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
     2207        aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);
     2208
     2209        /*
     2210         * 8 days of light
     2211         * Er, that is to say, 8 bytes of 0's
     2212         */
     2213        aimbs_put16(&fr->data, 0x0000);
     2214        aimbs_put16(&fr->data, 0x0000);
     2215        aimbs_put16(&fr->data, 0x0000);
     2216        aimbs_put16(&fr->data, 0x0000);
     2217
     2218        /*
     2219         * Type 1 (should be 0x0001 for mtn)
     2220         */
     2221        aimbs_put16(&fr->data, type1);
     2222
     2223        /*
     2224         * Dest sn
     2225         */
     2226        aimbs_put8(&fr->data, strlen(sn));
     2227        aimbs_putraw(&fr->data, sn, strlen(sn));
     2228
     2229        /*
     2230         * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
     2231         */
     2232        aimbs_put16(&fr->data, type2);
     2233
     2234        aim_tx_enqueue(sess, fr);
     2235
     2236        return 0;
     2237}
     2238
     2239/*
     2240 * Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
     2241 *
     2242 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
     2243 * and Gaim 0.60 and newer.
     2244 *
     2245 */
     2246static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     2247{
     2248        int ret = 0;
     2249        aim_rxcallback_t userfunc;
     2250        char *sn;
     2251        fu8_t snlen;
     2252        fu16_t type1, type2;
     2253
     2254        aim_bstream_advance(bs, 8); /* Unknown - All 0's */
     2255        type1 = aimbs_get16(bs);
     2256        snlen = aimbs_get8(bs);
     2257        sn = aimbs_getstr(bs, snlen);
     2258        type2 = aimbs_get16(bs);
     2259
     2260        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     2261                ret = userfunc(sess, rx, type1, sn, type2);
     2262
     2263        free(sn);
    17882264
    17892265        return ret;
     
    18022278                return missedcall(sess, mod, rx, snac, bs);
    18032279        else if (snac->subtype == 0x000b)
    1804                 return clienterr(sess, mod, rx, snac, bs);
     2280                return clientautoresp(sess, mod, rx, snac, bs);
    18052281        else if (snac->subtype == 0x000c)
    18062282                return msgack(sess, mod, rx, snac, bs);
     2283        else if (snac->subtype == 0x0014)
     2284                return mtn_receive(sess, mod, rx, snac, bs);
    18072285
    18082286        return 0;
     2287}
     2288
     2289static int snacdestructor(aim_session_t *sess, aim_conn_t *conn, aim_modsnac_t *snac, void *data)
     2290{
     2291        aim_rxcallback_t userfunc;
     2292        int ret = 0;
     2293
     2294        if (snac->subtype == 0x0006) {
     2295                if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_MSGTIMEOUT)))
     2296                        ret = userfunc(sess, NULL, conn, data);
     2297        }
     2298        /* Note that we return 1 for success, 0 for failure. */
     2299        return ret;
    18092300}
    18102301
     
    18192310        strncpy(mod->name, "messaging", sizeof(mod->name));
    18202311        mod->snachandler = snachandler;
     2312        mod->snacdestructor = snacdestructor;
    18212313
    18222314        return 0;
  • libfaim/info.c

    r5e53c4a r862371b  
    11/*
    2  * aim_info.c
     2 * Family 0x0002 - Information.
    33 *
    44 * The functions here are responsible for requesting and parsing information-
     
    1515};
    1616
     17/*
     18 * Subtype 0x0002
     19 *
     20 * Request Location services rights.
     21 *
     22 */
     23faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn)
     24{
     25        return aim_genericreq_n(sess, conn, 0x0002, 0x0002);
     26}
     27
     28/*
     29 * Subtype 0x0004
     30 *
     31 * Gives BOS your profile.
     32 *
     33 */
     34faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps)
     35{
     36        static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""};
     37        aim_frame_t *fr;
     38        aim_tlvlist_t *tl = NULL;
     39        aim_snacid_t snacid;
     40
     41        /* Build to packet first to get real length */
     42        if (profile) {
     43                aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding);
     44                aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile);
     45        }
     46
     47        /*
     48         * So here's how this works:
     49         *   - You are away when you have a non-zero-length type 4 TLV stored.
     50         *   - You become unaway when you clear the TLV with a zero-length
     51         *       type 4 TLV.
     52         *   - If you do not send the type 4 TLV, your status does not change
     53         *       (that is, if you were away, you'll remain away).
     54         */
     55        if (awaymsg) {
     56                if (strlen(awaymsg)) {
     57                        aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding);
     58                        aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg);
     59                } else
     60                        aim_addtlvtochain_noval(&tl, 0x0004);
     61        }
     62
     63        aim_addtlvtochain_caps(&tl, 0x0005, caps);
     64
     65        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl))))
     66                return -ENOMEM;