Changeset 862371b


Ignore:
Timestamp:
Jun 29, 2003, 1:47:04 PM (21 years ago)
Author:
James M. Kretchmar <kretch@mit.edu>
Branches:
master, barnowl_perlaim, debian, owl, release-1.10, 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;
     67
     68        snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
     69
     70        aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
     71        aim_writetlvchain(&fr->data, &tl);
     72        aim_freetlvchain(&tl);
     73
     74        aim_tx_enqueue(sess, fr);
     75
     76        return 0;
     77}
     78
     79/*
     80 * Subtype 0x0005 - Request info of another AIM user.
     81 *
     82 */
    1783faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype)
    1884{
     
    200266          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
    201267
     268        /* from ICQ2002a
     269        {AIM_CAPS_ICQUNKNOWN2,
     270         {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1,
     271          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, */
     272
    202273        {AIM_CAPS_ICQRTF,
    203274         {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
    204275          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}},
    205276
     277        /* supposed to be ICQRTF?
     278        {AIM_CAPS_TRILLUNKNOWN,
     279         {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
     280          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}}, */
     281
    206282        {AIM_CAPS_ICQUNKNOWN,
    207283         {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
     
    217293
    218294        {AIM_CAPS_APINFO,
    219          {0xAA, 0x4A, 0x32, 0xB5,
    220                  0xF8, 0x84,
    221                 0x48, 0xc6,
    222                  0xA3, 0xD7,
    223                  0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}},
     295         {0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6,
     296          0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}},
    224297
    225298        {AIM_CAPS_LAST}
     
    376449                } else if (type == 0x0002) {
    377450                        /*
    378                          * Type = 0x0002: Account creation time.
     451                         * Type = 0x0002: Account creation time. 
    379452                         *
    380453                         * The time/date that the user originally registered for
     
    424497                         * This is sometimes sent instead of type 2 ("account
    425498                         * creation time"), particularly in the self-info.
     499                         * And particularly for ICQ?
    426500                         */
    427501                        outinfo->membersince = aimbs_get32(bs);
     
    557631                aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
    558632
     633/* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */
    559634#if ICQ_OSCAR_SUPPORT
    560635        if (atoi(info->sn) != 0) {
     
    568643        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
    569644                aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities);
    570 
     645 
    571646        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
    572647                aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
     
    579654}
    580655
    581 faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info)
    582 {
    583         aim_frame_t *fr;
    584         aim_snacid_t snacid;
    585 
    586         if (!sess || !conn || !info)
    587                 return -EINVAL;
    588 
    589         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
    590                 return -ENOMEM;
    591 
    592         snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0);
    593        
    594         aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid);
    595         aim_putuserinfo(&fr->data, info);
    596 
    597         aim_tx_enqueue(sess, fr);
    598 
    599         return 0;
    600 }
    601 
    602 faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn)
    603 {
    604         aim_frame_t *fr;
    605         aim_snacid_t snacid;
    606 
    607         if (!sess || !conn || !sn)
    608                 return -EINVAL;
    609 
    610         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
    611                 return -ENOMEM;
    612 
    613         snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0);
    614        
    615         aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid);
    616         aimbs_put8(&fr->data, strlen(sn));
    617         aimbs_putraw(&fr->data, sn, strlen(sn));
    618 
    619         aim_tx_enqueue(sess, fr);
    620 
    621         return 0;
    622 }
    623 
    624 /*
    625  * Huh? What is this?
     656/*
     657 * Subtype 0x000b - Huh? What is this?
    626658 */
    627659faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn)
     
    648680
    649681/*
     682 * Subtype 0x0003
     683 *
    650684 * Normally contains:
    651685 *   t(0001)  - short containing max profile length (value = 1024)
    652686 *   t(0002)  - short - unknown (value = 16) [max MIME type length?]
    653687 *   t(0003)  - short - unknown (value = 10)
     688 *   t(0004)  - short - unknown (value = 2048) [ICQ only?]
    654689 */
    655690static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     
    673708}
    674709
     710/* Subtype 0x0006 */
    675711static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    676712{
     
    744780}
    745781
     782/*
     783 * Subtype 0x0009 - Set directory profile data.
     784 *
     785 * This is not the same as aim_bos_setprofile!
     786 * privacy: 1 to allow searching, 0 to disallow.
     787 *
     788 */
     789faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy)
     790{
     791        aim_frame_t *fr;
     792        aim_snacid_t snacid;
     793        aim_tlvlist_t *tl = NULL;
     794
     795        aim_addtlvtochain16(&tl, 0x000a, privacy);
     796
     797        if (first)
     798                aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first);
     799        if (last)
     800                aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last);
     801        if (middle)
     802                aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle);
     803        if (maiden)
     804                aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden);
     805
     806        if (state)
     807                aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state);
     808        if (city)
     809                aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city);
     810
     811        if (nickname)
     812                aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname);
     813        if (zip)
     814                aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip);
     815
     816        if (street)
     817                aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street);
     818
     819        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
     820                return -ENOMEM;
     821
     822        snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0);
     823
     824        aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid);
     825        aim_writetlvchain(&fr->data, &tl);
     826        aim_freetlvchain(&tl);
     827
     828        aim_tx_enqueue(sess, fr);
     829
     830        return 0;
     831}
     832
     833/*
     834 * Subtype 0x000f
     835 *
     836 * XXX pass these in better
     837 *
     838 */
     839faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy)
     840{
     841        aim_frame_t *fr;
     842        aim_snacid_t snacid;
     843        aim_tlvlist_t *tl = NULL;
     844
     845        /* ?? privacy ?? */
     846        aim_addtlvtochain16(&tl, 0x000a, privacy);
     847
     848        if (interest1)
     849                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1);
     850        if (interest2)
     851                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2);
     852        if (interest3)
     853                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3);
     854        if (interest4)
     855                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4);
     856        if (interest5)
     857                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5);
     858
     859        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
     860                return -ENOMEM;
     861
     862        snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0);
     863
     864        aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0);
     865        aim_writetlvchain(&fr->data, &tl);
     866        aim_freetlvchain(&tl);
     867
     868        aim_tx_enqueue(sess, fr);
     869
     870        return 0;
     871}
     872
    746873static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    747874{
  • libfaim/invite.c

    r5e53c4a r862371b  
    11/*
    2  * This isn't really ever used by anyone anymore.
     2 * Family 0x0006 - This isn't really ever used by anyone anymore.
    33 *
    44 * Once upon a time, there used to be a menu item in AIM clients that
     
    3333        return 0;
    3434}
    35 
    36 
  • libfaim/meta.c

    r5e53c4a r862371b  
    77#define FAIM_INTERNAL
    88#include <aim.h>
     9
     10#ifdef _WIN32
     11#include "win32dep.h"
     12#endif
    913
    1014faim_export char *aim_getbuilddate(void)
     
    3337faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...)
    3438{
     39  return; /* kretch */
     40 
    3541        if (!sess) {
    3642                fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format);
  • libfaim/misc.c

    r5e53c4a r862371b  
    1 
    21/*
    3  * aim_misc.c
     2 * misc.c
    43 *
    5  * TODO: Seperate a lot of this into an aim_bos.c.
    6  *
    7  * Other things...
    8  *
    9  *   - Idle setting
    10  *
     4 * Random stuff.  Basically just a few functions for sending
     5 * simple SNACs, and then the generic error handler.
    116 *
    127 */
     
    149#define FAIM_INTERNAL
    1510#include <aim.h>
    16 
    17 /*
    18  * aim_bos_setbuddylist(buddylist)
    19  *
    20  * This just builds the "set buddy list" command then queues it.
    21  *
    22  * buddy_list = "Screen Name One&ScreenNameTwo&";
    23  *
    24  * TODO: Clean this up. 
    25  *
    26  * XXX: I can't stress the TODO enough.
    27  *
    28  */
    29 faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list)
    30 {
    31         aim_frame_t *fr;
    32         aim_snacid_t snacid;
    33         int len = 0;
    34         char *localcpy = NULL;
    35         char *tmpptr = NULL;
    36 
    37         if (!buddy_list || !(localcpy = strdup(buddy_list)))
    38                 return -EINVAL;
    39 
    40         for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
    41                 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));
    42                 len += 1 + strlen(tmpptr);
    43                 tmpptr = strtok(NULL, "&");
    44         }
    45 
    46         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len)))
    47                 return -ENOMEM;
    48 
    49         snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0);
    50         aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
    51 
    52         strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
    53 
    54         for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
    55 
    56                 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));
    57 
    58                 aimbs_put8(&fr->data, strlen(tmpptr));
    59                 aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr));
    60                 tmpptr = strtok(NULL, "&");
    61         }
    62 
    63         aim_tx_enqueue(sess, fr);
    64 
    65         free(localcpy);
    66 
    67         return 0;
    68 }
    69 
    70 /*
    71  * aim_bos_setprofile(profile)
    72  *
    73  * Gives BOS your profile.
    74  *
    75  */
    76 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps)
    77 {
    78         static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""};
    79         aim_frame_t *fr;
    80         aim_tlvlist_t *tl = NULL;
    81         aim_snacid_t snacid;
    82 
    83         /* Build to packet first to get real length */
    84         if (profile) {
    85                 aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding);
    86                 aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile);
    87         }
    88 
    89         /*
    90          * So here's how this works:
    91          *   - You are away when you have a non-zero-length type 4 TLV stored.
    92          *   - You become unaway when you clear the TLV with a zero-length
    93          *       type 4 TLV.
    94          *   - If you do not send the type 4 TLV, your status does not change
    95          *       (that is, if you were away, you'll remain away).
    96          */
    97         if (awaymsg) {
    98                 if (strlen(awaymsg)) {
    99                         aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding);
    100                         aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg);
    101                 } else
    102                         aim_addtlvtochain_noval(&tl, 0x0004);
    103         }
    104 
    105         aim_addtlvtochain_caps(&tl, 0x0005, caps);
    106 
    107         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl))))
    108                 return -ENOMEM;
    109 
    110         snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
    111        
    112         aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
    113         aim_writetlvchain(&fr->data, &tl);
    114         aim_freetlvchain(&tl);
    115 
    116         aim_tx_enqueue(sess, fr);
    117 
    118         return 0;
    119 }
    120 
    121 /*
    122  * aim_bos_reqbuddyrights()
    123  *
    124  * Request Buddy List rights.
    125  *
    126  */
    127 faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn)
    128 {
    129         return aim_genericreq_n(sess, conn, 0x0003, 0x0002);
    130 }
    131 
    132 /*
    133  * Send a warning to destsn.
    134  *
    135  * Flags:
    136  *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much)
    137  *
    138  * returns -1 on error (couldn't alloc packet), 0 on success.
    139  *
    140  */
    141 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags)
    142 {
    143         aim_frame_t *fr;
    144         aim_snacid_t snacid;
    145         fu16_t outflags = 0x0000;
    146 
    147         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13)))
    148                 return -ENOMEM;
    149 
    150         snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1);
    151 
    152         aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
    153 
    154         if (flags & AIM_WARN_ANON)
    155                 outflags |= 0x0001;
    156 
    157         aimbs_put16(&fr->data, outflags);
    158         aimbs_put8(&fr->data, strlen(destsn));
    159         aimbs_putraw(&fr->data, destsn, strlen(destsn));
    160 
    161         aim_tx_enqueue(sess, fr);
    162 
    163         return 0;
    164 }
    16511
    16612/*
     
    25096
    25197/*
    252  * aim_bos_reqlocaterights()
    253  *
    254  * Request Location services rights.
    255  *
    256  */
    257 faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn)
    258 {
    259         return aim_genericreq_n(sess, conn, 0x0002, 0x0002);
    260 }
    261 
    262 /*
    263  * Set directory profile data (not the same as aim_bos_setprofile!)
    264  *
    265  * privacy: 1 to allow searching, 0 to disallow.
    266  */
    267 faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy)
    268 {
    269         aim_frame_t *fr;
    270         aim_snacid_t snacid;
    271         aim_tlvlist_t *tl = NULL;
    272 
    273 
    274         aim_addtlvtochain16(&tl, 0x000a, privacy);
    275 
    276         if (first)
    277                 aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first);
    278         if (last)
    279                 aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last);
    280         if (middle)
    281                 aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle);
    282         if (maiden)
    283                 aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden);
    284 
    285         if (state)
    286                 aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state);
    287         if (city)
    288                 aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city);
    289 
    290         if (nickname)
    291                 aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname);
    292         if (zip)
    293                 aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip);
    294 
    295         if (street)
    296                 aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street);
    297 
    298         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
    299                 return -ENOMEM;
    300 
    301         snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0);
    302        
    303         aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid);
    304         aim_writetlvchain(&fr->data, &tl);
    305         aim_freetlvchain(&tl);
    306 
    307         aim_tx_enqueue(sess, fr);
    308 
    309         return 0;
    310 }
    311 
    312 /* XXX pass these in better */
    313 faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy)
    314 {
    315         aim_frame_t *fr;
    316         aim_snacid_t snacid;
    317         aim_tlvlist_t *tl = NULL;
    318 
    319         /* ?? privacy ?? */
    320         aim_addtlvtochain16(&tl, 0x000a, privacy);
    321 
    322         if (interest1)
    323                 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1);
    324         if (interest2)
    325                 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2);
    326         if (interest3)
    327                 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3);
    328         if (interest4)
    329                 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4);
    330         if (interest5)
    331                 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5);
    332 
    333         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
    334                 return -ENOMEM;
    335 
    336         snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0);
    337 
    338         aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0);
    339         aim_writetlvchain(&fr->data, &tl);
    340         aim_freetlvchain(&tl);
    341 
    342         aim_tx_enqueue(sess, fr);
    343 
    344         return 0;
    345 }
    346 
    347 /*
    34898 * Should be generic enough to handle the errors for all groups.
    34999 *
     
    397147        return 0;
    398148}
    399 
    400 
  • libfaim/msgcookie.c

    r5e53c4a r862371b  
    193193        }           
    194194}
    195 
    196 
  • libfaim/popups.c

    r5e53c4a r862371b  
    1 
    21/*
     2 * Family 0x0008 - Popups.
     3 *
    34 * Popups are just what it sounds like.  They're a way for the server to
    45 * open up an informative box on the client's screen.
     
    6263        return 0;
    6364}
    64 
    65 
  • libfaim/rxhandlers.c

    r5e53c4a r862371b  
    11/*
    2  * aim_rxhandlers.c
     2 * rxhandlers.c
    33 *
    44 * This file contains most all of the incoming packet handlers, along
     
    6969        (aim_module_t *)sess->modlistv = mod;
    7070
    71         /* faimdprintf(sess, 1, "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion); */
     71        faimdprintf(sess, 1, "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion);
    7272
    7373        return 0;
     
    547547                                cur->handled = 1; /* get rid of it */
    548548                        } else {
    549                                 /* XXX: implement this */
    550                                 faimdprintf(sess, 0, "faim: OFT frame!\n");
    551                                 cur->handled = 1; /* get rid of it */
     549                                aim_rxdispatch_rendezvous(sess, cur);
     550                                cur->handled = 1;
    552551                        }
    553552                        continue;
     
    614613        return 1;
    615614}
    616 
    617 
    618 
  • libfaim/rxqueue.c

    r5e53c4a r862371b  
    11/*
    2  *  aim_rxqueue.c
     2 * rxqueue.c
    33 *
    44 * This file contains the management routines for the receive
     
    6464}
    6565
    66 faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len)
    67 {
    68        
    69         if (!bs)
    70                 return -1;
    71 
    72         bs->data = data;
    73         bs->len = len;
    74         bs->offset = 0;
    75 
    76         return 0;
    77 }
    78 
    79 faim_internal int aim_bstream_empty(aim_bstream_t *bs)
    80 {
    81         return bs->len - bs->offset;
    82 }
    83 
    84 faim_internal int aim_bstream_curpos(aim_bstream_t *bs)
    85 {
    86         return bs->offset;
    87 }
    88 
    89 faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off)
    90 {
    91 
    92         if (off > bs->len)
    93                 return -1;
    94 
    95         bs->offset = off;
    96 
    97         return off;
    98 }
    99 
    100 faim_internal void aim_bstream_rewind(aim_bstream_t *bs)
    101 {
    102 
    103         aim_bstream_setpos(bs, 0);
     66/**
     67 * aim_frame_destroy - free aim_frame_t
     68 * @frame: the frame to free
     69 *
     70 * returns -1 on error; 0 on success.
     71 *
     72 */
     73faim_internal void aim_frame_destroy(aim_frame_t *frame)
     74{
     75
     76        free(frame->data.data); /* XXX aim_bstream_free */
     77        free(frame);
    10478
    10579        return;
    10680}
    10781
    108 faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n)
    109 {
    110 
    111         if (aim_bstream_empty(bs) < n)
    112                 return 0; /* XXX throw an exception */
    113 
    114         bs->offset += n;
    115 
    116         return n;
    117 }
    118 
    119 faim_internal fu8_t aimbs_get8(aim_bstream_t *bs)
    120 {
    121        
    122         if (aim_bstream_empty(bs) < 1)
    123                 return 0; /* XXX throw an exception */
    124        
    125         bs->offset++;
    126        
    127         return aimutil_get8(bs->data + bs->offset - 1);
    128 }
    129 
    130 faim_internal fu16_t aimbs_get16(aim_bstream_t *bs)
    131 {
    132        
    133         if (aim_bstream_empty(bs) < 2)
    134                 return 0; /* XXX throw an exception */
    135        
    136         bs->offset += 2;
    137        
    138         return aimutil_get16(bs->data + bs->offset - 2);
    139 }
    140 
    141 faim_internal fu32_t aimbs_get32(aim_bstream_t *bs)
    142 {
    143        
    144         if (aim_bstream_empty(bs) < 4)
    145                 return 0; /* XXX throw an exception */
    146        
    147         bs->offset += 4;
    148        
    149         return aimutil_get32(bs->data + bs->offset - 4);
    150 }
    151 
    152 faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs)
    153 {
    154        
    155         if (aim_bstream_empty(bs) < 1)
    156                 return 0; /* XXX throw an exception */
    157        
    158         bs->offset++;
    159        
    160         return aimutil_getle8(bs->data + bs->offset - 1);
    161 }
    162 
    163 faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs)
    164 {
    165        
    166         if (aim_bstream_empty(bs) < 2)
    167                 return 0; /* XXX throw an exception */
    168        
    169         bs->offset += 2;
    170        
    171         return aimutil_getle16(bs->data + bs->offset - 2);
    172 }
    173 
    174 faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs)
    175 {
    176        
    177         if (aim_bstream_empty(bs) < 4)
    178                 return 0; /* XXX throw an exception */
    179        
    180         bs->offset += 4;
    181        
    182         return aimutil_getle32(bs->data + bs->offset - 4);
    183 }
    184 
    185 faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v)
    186 {
    187 
    188         if (aim_bstream_empty(bs) < 1)
    189                 return 0; /* XXX throw an exception */
    190 
    191         bs->offset += aimutil_put8(bs->data + bs->offset, v);
    192 
    193         return 1;
    194 }
    195 
    196 faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v)
    197 {
    198 
    199         if (aim_bstream_empty(bs) < 2)
    200                 return 0; /* XXX throw an exception */
    201 
    202         bs->offset += aimutil_put16(bs->data + bs->offset, v);
    203 
    204         return 2;
    205 }
    206 
    207 faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v)
    208 {
    209 
    210         if (aim_bstream_empty(bs) < 4)
    211                 return 0; /* XXX throw an exception */
    212 
    213         bs->offset += aimutil_put32(bs->data + bs->offset, v);
    214 
    215         return 1;
    216 }
    217 
    218 faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v)
    219 {
    220 
    221         if (aim_bstream_empty(bs) < 1)
    222                 return 0; /* XXX throw an exception */
    223 
    224         bs->offset += aimutil_putle8(bs->data + bs->offset, v);
    225 
    226         return 1;
    227 }
    228 
    229 faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v)
    230 {
    231 
    232         if (aim_bstream_empty(bs) < 2)
    233                 return 0; /* XXX throw an exception */
    234 
    235         bs->offset += aimutil_putle16(bs->data + bs->offset, v);
    236 
    237         return 2;
    238 }
    239 
    240 faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v)
    241 {
    242 
    243         if (aim_bstream_empty(bs) < 4)
    244                 return 0; /* XXX throw an exception */
    245 
    246         bs->offset += aimutil_putle32(bs->data + bs->offset, v);
    247 
    248         return 1;
    249 }
    250 
    251 faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len)
    252 {
    253 
    254         if (aim_bstream_empty(bs) < len)
    255                 return 0;
    256 
    257         memcpy(buf, bs->data + bs->offset, len);
    258         bs->offset += len;
    259 
    260         return len;
    261 }
    262 
    263 faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len)
    264 {
    265         fu8_t *ob;
    266 
    267         if (!(ob = malloc(len)))
    268                 return NULL;
    269 
    270         if (aimbs_getrawbuf(bs, ob, len) < len) {
    271                 free(ob);
    272                 return NULL;
    273         }
    274 
    275         return ob;
    276 }
    277 
    278 faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len)
    279 {
    280         char *ob;
    281 
    282         if (!(ob = malloc(len+1)))
    283                 return NULL;
    284 
    285         if (aimbs_getrawbuf(bs, ob, len) < len) {
    286                 free(ob);
    287                 return NULL;
    288         }
    289        
    290         ob[len] = '\0';
    291 
    292         return ob;
    293 }
    294 
    295 faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len)
    296 {
    297 
    298         if (aim_bstream_empty(bs) < len)
    299                 return 0; /* XXX throw an exception */
    300 
    301         memcpy(bs->data + bs->offset, v, len);
    302         bs->offset += len;
    303 
    304         return len;
    305 }
    306 
    307 faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len)
    308 {
    309 
    310         if (aim_bstream_empty(srcbs) < len)
    311                 return 0; /* XXX throw exception (underrun) */
    312 
    313         if (aim_bstream_empty(bs) < len)
    314                 return 0; /* XXX throw exception (overflow) */
    315 
    316         memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
    317         bs->offset += len;
    318         srcbs->offset += len;
    319 
    320         return len;
    321 }
    322 
    323 /**
    324  * aim_frame_destroy - free aim_frame_t
    325  * @frame: the frame to free 
    326  *
    327  * returns -1 on error; 0 on success. 
    328  *
    329  */
    330 faim_internal void aim_frame_destroy(aim_frame_t *frame)
    331 {
    332 
    333         free(frame->data.data); /* XXX aim_bstream_free */
    334 
    335         if (frame->hdrtype == AIM_FRAMETYPE_OFT)
    336                 free(frame->hdr.oft.hdr2);
    337         free(frame);
    338        
    339         return;
    340 }
    341 
    342 
    343 /*
    344  * Grab a single command sequence off the socket, and enqueue
    345  * it in the incoming event queue in a seperate struct.
    346  */
    347 faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
     82/*
     83 * Read a FLAP header from conn into fr, and return the number of bytes in the payload.
     84 */
     85static faim_shortfunc int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
    34886{
    34987        fu8_t flaphdr_raw[6];
    35088        aim_bstream_t flaphdr;
    351         aim_frame_t *newrx;
    35289        fu16_t payloadlen;
    35390       
    354         if (!sess || !conn)
    355                 return 0;
    356 
    357         if (conn->fd == -1)
    358                 return -1; /* its a aim_conn_close()'d connection */
    359 
    360         if (conn->fd < 3)  /* can happen when people abuse the interface */
    361                 return 0;
    362 
    363         if (conn->status & AIM_CONN_STATUS_INPROGRESS)
    364                 return aim_conn_completeconnect(sess, conn);
    365 
    366         /*
    367          * Rendezvous (client-client) connections do not speak
    368          * FLAP, so this function will break on them.
    369          */
    370         if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
    371                 return aim_get_command_rendezvous(sess, conn);
    372         else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
    373                 faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);
    374                 return 0;
    375         }
    376 
    37791        aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
    37892
    37993        /*
    38094         * Read FLAP header.  Six bytes:
    381          *   
    38295         *   0 char  -- Always 0x2a
    38396         *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
    384          *   2 short -- Sequence number 
     97         *   2 short -- Sequence number
    38598         *   4 short -- Number of data bytes that follow.
    38699         */
     
    406119        }       
    407120
    408         /* allocate a new struct */
    409         if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
    410                 return -1;
    411         memset(newrx, 0, sizeof(aim_frame_t));
    412 
    413121        /* we're doing FLAP if we're here */
    414         newrx->hdrtype = AIM_FRAMETYPE_FLAP;
    415        
    416         newrx->hdr.flap.type = aimbs_get8(&flaphdr);
    417         newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
    418         payloadlen = aimbs_get16(&flaphdr);
     122        fr->hdrtype = AIM_FRAMETYPE_FLAP;
     123
     124        fr->hdr.flap.type = aimbs_get8(&flaphdr);
     125        fr->hdr.flap.seqnum = aimbs_get16(&flaphdr);
     126        payloadlen = aimbs_get16(&flaphdr); /* length of payload */
     127
     128        return payloadlen;
     129}
     130
     131/*
     132 * Read a rendezvous header from conn into fr, and return the number of bytes in the payload.
     133 */
     134static int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
     135{
     136        fu8_t rendhdr_raw[8];
     137        aim_bstream_t rendhdr;
     138
     139        aim_bstream_init(&rendhdr, rendhdr_raw, sizeof(rendhdr_raw));
     140
     141        if (aim_bstream_recv(&rendhdr, conn->fd, 8) < 8) {
     142                aim_conn_close(conn);
     143                return -1;
     144        }
     145
     146        aim_bstream_rewind(&rendhdr);
     147
     148        fr->hdrtype = AIM_FRAMETYPE_OFT; /* a misnomer--rendezvous */
     149
     150        aimbs_getrawbuf(&rendhdr, fr->hdr.rend.magic, 4);
     151        fr->hdr.rend.hdrlen = aimbs_get16(&rendhdr) - 8;
     152        fr->hdr.rend.type = aimbs_get16(&rendhdr);
     153
     154        return fr->hdr.rend.hdrlen;
     155}
     156
     157/*
     158 * Grab a single command sequence off the socket, and enqueue it in the incoming event queue
     159 * in a separate struct.
     160 */
     161faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
     162{
     163        aim_frame_t *newrx;
     164        fu16_t payloadlen;
     165
     166        if (!sess || !conn)
     167                return -1;
     168
     169        if (conn->fd == -1)
     170                return -1; /* it's an aim_conn_close()'d connection */
     171
     172        if (conn->fd < 3) /* can happen when people abuse the interface */
     173                return -1;
     174
     175        if (conn->status & AIM_CONN_STATUS_INPROGRESS)
     176                return aim_conn_completeconnect(sess, conn);
     177
     178        if (!(newrx = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1)))
     179                return -1;
     180
     181        /*
     182         * Rendezvous (client to client) connections do not speak FLAP, so this
     183         * function will break on them.
     184         */
     185        if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
     186                payloadlen = aim_get_command_rendezvous(sess, conn, newrx);
     187        else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
     188                faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);
     189                free(newrx);
     190                return -1;
     191        } else
     192                payloadlen = aim_get_command_flap(sess, conn, newrx);
    419193
    420194        newrx->nofree = 0; /* free by default */
     
    508282        return;
    509283}
    510 
  • libfaim/search.c

    r5e53c4a r862371b  
    1 
    21/*
    3  * aim_search.c
     2 * Family 0x000a - User Search.
    43 *
    54 * TODO: Add aim_usersearch_name()
     
    109#include <aim.h>
    1110
    12 faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address)
    13 {
    14         aim_frame_t *fr;
    15         aim_snacid_t snacid;
    16 
    17         if (!sess || !conn || !address)
    18                 return -EINVAL;
    19 
    20         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address))))
    21                 return -ENOMEM;
    22 
    23         snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1);
    24         aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid);
    25        
    26         aimbs_putraw(&fr->data, address, strlen(address));
    27 
    28         aim_tx_enqueue(sess, fr);
    29 
    30         return 0;
    31 }
    32 
    33 /* XXX can this be integrated with the rest of the error handling? */
     11/*
     12 * Subtype 0x0001
     13 *
     14 * XXX can this be integrated with the rest of the error handling?
     15 */
    3416static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    3517{
     
    5537}
    5638
     39/*
     40 * Subtype 0x0002
     41 *
     42 */
     43faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address)
     44{
     45        aim_frame_t *fr;
     46        aim_snacid_t snacid;
     47
     48        if (!sess || !conn || !address)
     49                return -EINVAL;
     50
     51        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address))))
     52                return -ENOMEM;
     53
     54        snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1);
     55        aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid);
     56       
     57        aimbs_putraw(&fr->data, address, strlen(address));
     58
     59        aim_tx_enqueue(sess, fr);
     60
     61        return 0;
     62}
     63
     64/*
     65 * Subtype 0x0003
     66 *
     67 */
    5768static int reply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    5869{
     
    119130        return 0;
    120131}
    121 
    122 
  • libfaim/service.c

    r5e53c4a r862371b  
    11/*
    2  * Group 1. This is a very special group.  All connections support
     2 * Family 0x0001 - This is a very special group.  All connections support
    33 * this group, as it does some particularly good things (like rate limiting).
    44 */
     
    1010#include "md5.h"
    1111
    12 /* Client Online (group 1, subtype 2) */
     12/* Subtype 0x0002 - Client Online */
    1313faim_export int aim_clientready(aim_session_t *sess, aim_conn_t *conn)
    1414{
     
    4949
    5050/*
    51  * Host Online (group 1, type 3)
     51 * Subtype 0x0003 - Host Online
    5252 *
    5353 * See comments in conn.c about how the group associations are supposed
     
    9292}
    9393
    94 /* Service request (group 1, type 4) */
     94/* Subtype 0x0004 - Service request */
    9595faim_export int aim_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid)
    9696{
     
    9898}
    9999
    100 /* Redirect (group 1, type 5) */
     100/* Subtype 0x0005 - Redirect */
    101101static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    102102{
     
    148148}
    149149
    150 /* Request Rate Information. (group 1, type 6) */
     150/* Subtype 0x0006 - Request Rate Information. */
    151151faim_internal int aim_reqrates(aim_session_t *sess, aim_conn_t *conn)
    152152{
     
    258258}
    259259
    260 /* Rate Parameters (group 1, type 7) */
     260/* Subtype 0x0007 - Rate Parameters */
    261261static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    262262{
     
    345345}
    346346
    347 /* Add Rate Parameter (group 1, type 8) */
     347/* Subtype 0x0008 - Add Rate Parameter */
    348348faim_internal int aim_rates_addparam(aim_session_t *sess, aim_conn_t *conn)
    349349{
     
    367367}
    368368
    369 /* Delete Rate Parameter (group 1, type 9) */
     369/* Subtype 0x0009 - Delete Rate Parameter */
    370370faim_internal int aim_rates_delparam(aim_session_t *sess, aim_conn_t *conn)
    371371{
     
    389389}
    390390
    391 /* Rate Change (group 1, type 0x0a) */
     391/* Subtype 0x000a - Rate Change */
    392392static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    393393{
     
    414414
    415415/*
    416  * How Migrations work. 
     416 * How Migrations work.
    417417 *
    418418 * The server sends a Server Pause message, which the client should respond to
     
    426426 */
    427427
    428 /* Service Pause (group 1, type 0x0b) */
     428/* Subtype 0x000b - Service Pause */
    429429static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    430430{
     
    438438
    439439/*
    440  * Service Pause Acknowledgement (group 1, type 0x0c)
     440 * Subtype 0x000c - Service Pause Acknowledgement
    441441 *
    442442 * It is rather important that aim_sendpauseack() gets called for the exact
     
    474474}
    475475
    476 /* Service Resume (group 1, type 0x0d) */
     476/* Subtype 0x000d - Service Resume */
    477477static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    478478{
     
    485485}
    486486
    487 /* Request self-info (group 1, type 0x0e) */
     487/* Subtype 0x000e - Request self-info */
    488488faim_export int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn)
    489489{
     
    491491}
    492492
    493 /* Self User Info (group 1, type 0x0f) */
     493/* Subtype 0x000f - Self User Info */
    494494static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    495495{
     
    505505}
    506506
    507 /* Evil Notification (group 1, type 0x10) */
     507/* Subtype 0x0010 - Evil Notification */
    508508static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    509509{
     
    526526
    527527/*
    528  * Idle Notification (group 1, type 0x11)
     528 * Subtype 0x0011 - Idle Notification
    529529 *
    530530 * Should set your current idle time in seconds.  Note that this should
     
    540540
    541541/*
    542  * Service Migrate (group 1, type 0x12)
     542 * Subtype 0x0012 - Service Migrate
    543543 *
    544544 * This is the final SNAC sent on the original connection during a migration.
     
    592592}
    593593
    594 /* Message of the Day (group 1, type 0x13) */
     594/* Subtype 0x0013 - Message of the Day */
    595595static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    596596{
     
    632632
    633633/*
    634  * Set privacy flags (group 1, type 0x14)
     634 * Subtype 0x0014 - Set privacy flags
    635635 *
    636636 * Normally 0x03.
     
    646646
    647647/*
    648  * No-op (group 1, type 0x16)
     648 * Subtype 0x0016 - No-op
    649649 *
    650650 * WinAIM sends these every 4min or so to keep the connection alive.  Its not
    651  * real necessary.
     651 * really necessary.
    652652 *
    653653 */
     
    658658
    659659/*
    660  * Set client versions (group 1, subtype 0x17)
     660 * Subtype 0x0017 - Set client versions
    661661 *
    662662 * If you've seen the clientonline/clientready SNAC you're probably
     
    705705}
    706706
    707 /* Host versions (group 1, subtype 0x18) */
     707/* Subtype 0x0018 - Host versions */
    708708static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    709709{
     
    725725
    726726/*
    727  * Set Extended Status (group 1, type 0x1e)
     727 * Subtype 0x001e - Set Extended Status
    728728 *
    729729 * Currently only works if using ICQ.
     
    791791 *
    792792 */
    793 /* Client verification (group 1, subtype 0x1f) */
     793/* Subtype 0x001f - Client verification */
    794794static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    795795{
     
    816816}
    817817
    818 #if 0 
     818#if 0
    819819static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)
    820820{
     
    839839#endif
    840840
    841 /* Client verification reply (group 1, subtype 0x20) */
     841/* Subtype 0x0020 - Client verification reply */
    842842faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag)
    843843{
     
    970970        return 0;
    971971}
    972 
  • libfaim/snac.c

    r5e53c4a r862371b  
    9090                if (cur->id == id) {
    9191                        *prev = cur->next;
     92                        if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) {
     93                                struct aim_snac_destructor *asd = cur->data;
     94                                cur->data = asd->data;
     95                                free(asd);
     96                        }
    9297                        return cur;
    9398                } else
     
    97102        return cur;
    98103}
     104
     105/* Free a SNAC, and call the appropriate destructor if necessary.
     106 */
     107faim_internal faim_shortfunc void aim_cleansnac(aim_session_t *sess, aim_snac_t *snac)
     108{
     109        aim_module_t *cur;
     110
     111        if (snac->flags & AIM_SNACFLAGS_DESTRUCTOR) {
     112                struct aim_snac_destructor *d = snac->data;
     113                aim_modsnac_t modsnac;
     114
     115                modsnac.id = snac->id;
     116                modsnac.subtype = snac->type;
     117                modsnac.family = snac->family;
     118                modsnac.flags = snac->flags;
     119
     120                for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next)
     121                {
     122                        if (!cur->snacdestructor)
     123                                continue;
     124                        if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
     125                                (cur->family != modsnac.family))
     126                                continue;
     127                        if (cur->snacdestructor(sess, d->conn, &modsnac,
     128                                                d->data))
     129                                break;
     130                }
     131                free(d->data);
     132        }
     133
     134        free(snac->data);
     135        free(snac);
     136}
     137
    99138
    100139/*
     
    123162                                *prev = cur->next;
    124163
    125                                 /* XXX should we have destructors here? */
    126                                 free(cur->data);
    127                                 free(cur);
    128 
     164                                aim_cleansnac(sess, cur);
    129165                        } else
    130166                                prev = &cur->next;
  • libfaim/ssi.c

    r5e53c4a r862371b  
    66 * to be stored on the server, so that they can be accessed from any client.
    77 *
     8 * We keep a copy of the ssi data in sess->ssi, because the data needs to be
     9 * accessed for various reasons.  So all the "aim_ssi_itemlist_bleh" functions
     10 * near the top just manage the local data.
     11 *
     12 * The SNAC sending and receiving functions are lower down in the file, and
     13 * they're simpler.  They are in the order of the subtypes they deal with,
     14 * starting with the request rights function (subtype 0x0002), then parse
     15 * rights (subtype 0x0003), then--well, you get the idea.
     16 *
    817 * This is entirely too complicated.
     18 * You don't know the half of it.
     19 *
     20 * XXX - Test for memory leaks
     21 * XXX - Better parsing of rights, and use the rights info to limit adds
    922 *
    1023 */
     
    1326#include <aim.h>
    1427
     28/**
     29 * Locally add a new item to the given item list.
     30 *
     31 * @param list A pointer to a pointer to the current list of items.
     32 * @param parent A pointer to the parent group, or NULL if the item should have no
     33 *        parent group (ie. the group ID# should be 0).
     34 * @param name A null terminated string of the name of the new item, or NULL if the
     35 *        item should have no name.
     36 * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc.
     37 * @return The newly created item.
     38 */
     39static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, const char *name, fu16_t type)
     40{
     41        int i;
     42        struct aim_ssi_item *cur, *newitem;
     43
     44        if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
     45                return NULL;
     46
     47        /* Set the name */
     48        if (name) {
     49                if (!(newitem->name = (char *)malloc((strlen(name)+1)*sizeof(char)))) {
     50                        free(newitem);
     51                        return NULL;
     52                }
     53                strcpy(newitem->name, name);
     54        } else
     55                newitem->name = NULL;
     56
     57        /* Set the group ID# and the buddy ID# */
     58        newitem->gid = 0x0000;
     59        newitem->bid = 0x0000;
     60        if (type == AIM_SSI_TYPE_GROUP) {
     61                if (name)
     62                        do {
     63                                newitem->gid += 0x0001;
     64                                for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
     65                                        if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid))
     66                                                i=1;
     67                        } while (i);
     68        } else {
     69                if (parent)
     70                        newitem->gid = parent->gid;
     71                do {
     72                        newitem->bid += 0x0001;
     73                        for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
     74                                if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid))
     75                                        i=1;
     76                } while (i);
     77        }
     78
     79        /* Set the rest */
     80        newitem->type = type;
     81        newitem->data = NULL;
     82        newitem->next = *list;
     83        *list = newitem;
     84
     85        return newitem;
     86}
     87
     88/**
     89 * Locally rebuild the 0x00c8 TLV in the additional data of the given group.
     90 *
     91 * @param list A pointer to a pointer to the current list of items.
     92 * @param parentgroup A pointer to the group who's additional data you want to rebuild.
     93 * @return Return 0 if no errors, otherwise return the error number.
     94 */
     95static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup)
     96{
     97        int newlen;
     98        struct aim_ssi_item *cur;
     99
     100        /* Free the old additional data */
     101        if (parentgroup->data) {
     102                aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data);
     103                parentgroup->data = NULL;
     104        }
     105
     106        /* Find the length for the new additional data */
     107        newlen = 0;
     108        if (parentgroup->gid == 0x0000) {
     109                for (cur=*list; cur; cur=cur->next)
     110                        if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP))
     111                                newlen += 2;
     112        } else {
     113                for (cur=*list; cur; cur=cur->next)
     114                        if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     115                                newlen += 2;
     116        }
     117
     118        /* Rebuild the additional data */
     119        if (newlen>0) {
     120                fu8_t *newdata;
     121
     122                if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t))))
     123                        return -ENOMEM;
     124                newlen = 0;
     125                if (parentgroup->gid == 0x0000) {
     126                        for (cur=*list; cur; cur=cur->next)
     127                                if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP))
     128                                                newlen += aimutil_put16(newdata+newlen, cur->gid);
     129                } else {
     130                        for (cur=*list; cur; cur=cur->next)
     131                                if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     132                                                newlen += aimutil_put16(newdata+newlen, cur->bid);
     133                }
     134                aim_addtlvtochain_raw((aim_tlvlist_t **)&(parentgroup->data), 0x00c8, newlen, newdata);
     135
     136                free(newdata);
     137        }
     138
     139        return 0;
     140}
     141
     142/**
     143 * Locally free all of the stored buddy list information.
     144 *
     145 * @param sess The oscar session.
     146 * @return Return 0 if no errors, otherwise return the error number.
     147 */
     148static int aim_ssi_freelist(aim_session_t *sess)
     149{
     150        struct aim_ssi_item *cur, *delitem;
     151
     152        cur = sess->ssi.items;
     153        while (cur) {
     154                if (cur->name)  free(cur->name);
     155                if (cur->data)  aim_freetlvchain((aim_tlvlist_t **)&cur->data);
     156                delitem = cur;
     157                cur = cur->next;
     158                free(delitem);
     159        }
     160
     161        sess->ssi.items = NULL;
     162        sess->ssi.revision = 0;
     163        sess->ssi.timestamp = (time_t)0;
     164
     165        return 0;
     166}
     167
     168/**
     169 * Locally find an item given a group ID# and a buddy ID#.
     170 *
     171 * @param list A pointer to the current list of items.
     172 * @param gid The group ID# of the desired item.
     173 * @param bid The buddy ID# of the desired item.
     174 * @return Return a pointer to the item if found, else return NULL;
     175 */
     176faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid)
     177{
     178        struct aim_ssi_item *cur;
     179        for (cur=list; cur; cur=cur->next)
     180                if ((cur->gid == gid) && (cur->bid == bid))
     181                        return cur;
     182        return NULL;
     183}
     184
     185/**
     186 * Locally find an item given a group name, screen name, and type.  If group name
     187 * and screen name are null, then just return the first item of the given type.
     188 *
     189 * @param list A pointer to the current list of items.
     190 * @param gn The group name of the desired item.
     191 * @param bn The buddy name of the desired item.
     192 * @param type The type of the desired item.
     193 * @return Return a pointer to the item if found, else return NULL;
     194 */
     195faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type)
     196{
     197        struct aim_ssi_item *cur;
     198        if (!list)
     199                return NULL;
     200
     201        if (gn && sn) { /* For finding buddies in groups */
     202                for (cur=list; cur; cur=cur->next)
     203                        if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
     204                                struct aim_ssi_item *curg;
     205                                for (curg=list; curg; curg=curg->next)
     206                                        if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn)))
     207                                                return cur;
     208                        }
     209
     210        } else if (sn) { /* For finding groups, permits, denies, and ignores */
     211                for (cur=list; cur; cur=cur->next)
     212                        if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn)))
     213                                return cur;
     214
     215        /* For stuff without names--permit deny setting, visibility mask, etc. */
     216        } else for (cur=list; cur; cur=cur->next) {
     217                if (cur->type == type)
     218                        return cur;
     219        }
     220
     221        return NULL;
     222}
     223
     224/**
     225 * Locally find the parent item of the given buddy name.
     226 *
     227 * @param list A pointer to the current list of items.
     228 * @param bn The buddy name of the desired item.
     229 * @return Return a pointer to the item if found, else return NULL;
     230 */
     231faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn)
     232{
     233        struct aim_ssi_item *cur, *curg;
     234        if (!list || !sn)
     235                return NULL;
     236        if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY)))
     237                return NULL;
     238        for (curg=list; curg; curg=curg->next)
     239                if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid))
     240                        return curg;
     241        return NULL;
     242}
     243
     244/**
     245 * Locally find the permit/deny setting item, and return the setting.
     246 *
     247 * @param list A pointer to the current list of items.
     248 * @return Return the current SSI permit deny setting, or 0 if no setting was found.
     249 */
     250faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list)
     251{
     252        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
     253        if (cur) {
     254                aim_tlvlist_t *tlvlist = cur->data;
     255                if (tlvlist) {
     256                        aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1);
     257                        if (tlv && tlv->value)
     258                                return aimutil_get8(tlv->value);
     259                }
     260        }
     261        return 0;
     262}
     263
     264/**
     265 * Locally find the presence flag item, and return the setting.  The returned setting is a
     266 * bitmask of the user flags that you are visible to.  See the AIM_FLAG_* #defines
     267 * in aim.h
     268 *
     269 * @param list A pointer to the current list of items.
     270 * @return Return the current visibility mask.
     271 */
     272faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list)
     273{
     274        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
     275        if (cur) {
     276                aim_tlvlist_t *tlvlist = cur->data;
     277                if (tlvlist) {
     278                        aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00c9, 1);
     279                        if (tlv && tlv->length)
     280                                return aimutil_get32(tlv->value);
     281                }
     282        }
     283        return 0xFFFFFFFF;
     284}
     285
     286/**
     287 * Add the given packet to the holding queue.  We totally need to send SSI SNACs one at
     288 * a time, so we have a local queue where packets get put before they are sent, and
     289 * then we send stuff one at a time, nice and orderly-like.
     290 *
     291 * @param sess The oscar session.
     292 * @param conn The bos connection for this session.
     293 * @param fr The newly created SNAC that you want to send.
     294 * @return Return 0 if no errors, otherwise return the error number.
     295 */
     296static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
     297{
     298        aim_frame_t *cur;
     299
     300        if (!sess || !conn || !fr)
     301                return -EINVAL;
     302
     303        fr->next = NULL;
     304        if (sess->ssi.holding_queue == NULL) {
     305                sess->ssi.holding_queue = fr;
     306                if (!sess->ssi.waiting_for_ack)
     307                        aim_ssi_modbegin(sess, conn);
     308        } else {
     309                for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) ;
     310                cur->next = fr;
     311        }
     312
     313        return 0;
     314}
     315
     316/**
     317 * Send the next SNAC from the holding queue.  This is called
     318 * automatically when an ack from an add, mod, or del is received. 
     319 * If the queue is empty, it sends the modend SNAC.
     320 *
     321 * @param sess The oscar session.
     322 * @param conn The bos connection for this session.
     323 * @return Return 0 if no errors, otherwise return the error number.
     324 */
     325static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn)
     326{
     327        aim_frame_t *cur;
     328
     329        if (!sess || !conn)
     330                return -EINVAL;
     331
     332        if (!sess->ssi.waiting_for_ack) {
     333                if (sess->ssi.holding_queue) {
     334                        sess->ssi.waiting_for_ack = 1;
     335                        cur = sess->ssi.holding_queue->next;
     336                        sess->ssi.holding_queue->next = NULL;
     337                        aim_tx_enqueue(sess, sess->ssi.holding_queue);
     338                        sess->ssi.holding_queue = cur;
     339                } else
     340                        aim_ssi_modend(sess, conn);
     341        }
     342
     343        return 0;
     344}
     345
     346/**
     347 * Send SNACs necessary to remove all SSI data from the server list,
     348 * and then free the local copy as well.
     349 *
     350 * @param sess The oscar session.
     351 * @param conn The bos connection for this session.
     352 * @return Return 0 if no errors, otherwise return the error number.
     353 */
     354faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn)
     355{
     356        int num;
     357        struct aim_ssi_item *cur, **items;
     358
     359        for (cur=sess->ssi.items, num=0; cur; cur=cur->next)
     360                num++;
     361
     362        if (!(items = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
     363                return -ENOMEM;
     364        memset(items, 0, num*sizeof(struct aim_ssi_item *));
     365        for (cur=sess->ssi.items, num=0; cur; cur=cur->next) {
     366                items[num] = cur;
     367                num++;
     368        }
     369
     370        aim_ssi_addmoddel(sess, conn, items, num, AIM_CB_SSI_DEL);
     371        free(items);
     372        aim_ssi_dispatch(sess, conn);
     373        aim_ssi_freelist(sess);
     374
     375        return 0;
     376}
     377
     378/**
     379 * This "cleans" the ssi list.  It does a few things, with the intent of making
     380 * sure there ain't nothin' wrong with your SSI.
     381 *   -Make sure all buddies are in a group, and all groups have the correct
     382 *     additional data.
     383 *   -Make sure there are no empty groups in the list.  While there is nothing
     384 *     wrong empty groups in the SSI, it's wiser to not have them.
     385 *
     386 * @param sess The oscar session.
     387 * @param conn The bos connection for this session.
     388 * @return Return 0 if no errors, otherwise return the error number.
     389 */
     390faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn)
     391{
     392        unsigned int i;
     393        struct aim_ssi_item *cur, *parentgroup;
     394
     395        /* Make sure we actually need to clean out the list */
     396        for (cur=sess->ssi.items, i=0; cur && !i; cur=cur->next)
     397                /* Any buddies directly in the master group */
     398                if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000))
     399                        i++;
     400        if (!i)
     401                return 0;
     402
     403        /* Remove all the additional data from all groups */
     404        for (cur=sess->ssi.items; cur; cur=cur->next)
     405                if ((cur->data) && (cur->type == AIM_SSI_TYPE_GROUP)) {
     406                        aim_freetlvchain((aim_tlvlist_t **)&cur->data);
     407                        cur->data = NULL;
     408                }
     409
     410        /* If there are buddies directly in the master group, make sure  */
     411        /* there is a group to put them in.  Any group, any group at all. */
     412        for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next);
     413        if (!cur) {
     414                for (parentgroup=sess->ssi.items; ((parentgroup) && (parentgroup->type!=AIM_SSI_TYPE_GROUP) && (parentgroup->gid==0x0000)); parentgroup=parentgroup->next);
     415                if (!parentgroup) {
     416                        char *newgroup;
     417                        newgroup = (char*)malloc(strlen("Unknown")*sizeof(char));
     418                        strcpy(newgroup, "Unknown");
     419                        aim_ssi_addgroups(sess, conn, (const char**)&newgroup, 1);
     420                }
     421        }
     422
     423        /* Set parentgroup equal to any arbitray group */
     424        for (parentgroup=sess->ssi.items; parentgroup->gid==0x0000 || parentgroup->type!=AIM_SSI_TYPE_GROUP; parentgroup=parentgroup->next);
     425
     426        /* If there are any buddies directly in the master group, put them in a real group */
     427        for (cur=sess->ssi.items; cur; cur=cur->next)
     428                if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) {
     429                        aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_DEL);
     430                        cur->gid = parentgroup->gid;
     431                        aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
     432                }
     433
     434        /* Rebuild additional data for all groups */
     435        for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next)
     436                if (parentgroup->type == AIM_SSI_TYPE_GROUP)
     437                        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);
     438
     439        /* Send a mod snac for all groups */
     440        i = 0;
     441        for (cur=sess->ssi.items; cur; cur=cur->next)
     442                if (cur->type == AIM_SSI_TYPE_GROUP)
     443                        i++;
     444        if (i > 0) {
     445                /* Allocate an array of pointers to each of the groups */
     446                struct aim_ssi_item **groups;
     447                if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *))))
     448                        return -ENOMEM;
     449
     450                for (cur=sess->ssi.items, i=0; cur; cur=cur->next)
     451                        if (cur->type == AIM_SSI_TYPE_GROUP)
     452                                groups[i] = cur;
     453
     454                aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_MOD);
     455                free(groups);
     456        }
     457
     458        /* Send a del snac for any empty groups */
     459        i = 0;
     460        for (cur=sess->ssi.items; cur; cur=cur->next)
     461                if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data))
     462                        i++;
     463        if (i > 0) {
     464                /* Allocate an array of pointers to each of the groups */
     465                struct aim_ssi_item **groups;
     466                if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *))))
     467                        return -ENOMEM;
     468
     469                for (cur=sess->ssi.items, i=0; cur; cur=cur->next)
     470                        if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data))
     471                                groups[i] = cur;
     472
     473                aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_DEL);
     474                free(groups);
     475        }
     476
     477        /* Begin sending SSI SNACs */
     478        aim_ssi_dispatch(sess, conn);
     479
     480        return 0;
     481}
     482
     483/**
     484 * Add an array of screen names to the given group.
     485 *
     486 * @param sess The oscar session.
     487 * @param conn The bos connection for this session.
     488 * @param gn The name of the group to which you want to add these names.
     489 * @param sn An array of null terminated strings of the names you want to add.
     490 * @param num The number of screen names you are adding (size of the sn array).
     491 * @return Return 0 if no errors, otherwise return the error number.
     492 */
     493faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num)
     494{
     495        struct aim_ssi_item *parentgroup, **newitems;
     496        fu16_t i;
     497
     498        if (!sess || !conn || !gn || !sn || !num)
     499                return -EINVAL;
     500
     501        /* Look up the parent group */
     502        if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) {
     503                aim_ssi_addgroups(sess, conn, (const char **)&gn, 1);
     504                if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP)))
     505                        return -ENOMEM;
     506        }
     507
     508        /* Allocate an array of pointers to each of the new items */
     509        if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
     510                return -ENOMEM;
     511
     512        /* Add items to the local list, and index them in the array */
     513        for (i=0; i<num; i++)
     514                if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) {
     515                        free(newitems);
     516                        return -ENOMEM;
     517                }
     518
     519        /* Send the add item SNAC */
     520        if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
     521                free(newitems);
     522                return -i;
     523        }
     524
     525        /* Free the array of pointers to each of the new items */
     526        free(newitems);
     527
     528        /* Rebuild the additional data in the parent group */
     529        if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup)))
     530                return i;
     531
     532        /* Send the mod item SNAC */
     533        if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD)))
     534                return i;
     535
     536        /* Begin sending SSI SNACs */
     537        if (!(i = aim_ssi_dispatch(sess, conn)))
     538                return i;
     539
     540        return 0;
     541}
     542
     543/**
     544 * Add the master group (the group containing all groups).  This is called by
     545 * aim_ssi_addgroups, if necessary.
     546 *
     547 * @param sess The oscar session.
     548 * @param conn The bos connection for this session.
     549 * @return Return 0 if no errors, otherwise return the error number.
     550 */
     551faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn)
     552{
     553        struct aim_ssi_item *newitem;
     554
     555        if (!sess || !conn)
     556                return -EINVAL;
     557
     558        /* Add the item to the local list, and keep a pointer to it */
     559        if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP)))
     560                return -ENOMEM;
     561
     562        /* If there are any existing groups (technically there shouldn't be, but */
     563        /* just in case) then add their group ID#'s to the additional data */
     564        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem);
     565
     566        /* Send the add item SNAC */
     567        aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD);
     568
     569        /* Begin sending SSI SNACs */
     570        aim_ssi_dispatch(sess, conn);
     571
     572        return 0;
     573}
     574
     575/**
     576 * Add an array of groups to the list.
     577 *
     578 * @param sess The oscar session.
     579 * @param conn The bos connection for this session.
     580 * @param gn An array of null terminated strings of the names you want to add.
     581 * @param num The number of groups names you are adding (size of the sn array).
     582 * @return Return 0 if no errors, otherwise return the error number.
     583 */
     584faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num)
     585{
     586        struct aim_ssi_item *parentgroup, **newitems;
     587        fu16_t i;
     588
     589        if (!sess || !conn || !gn || !num)
     590                return -EINVAL;
     591
     592        /* Look up the parent group */
     593        if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) {
     594                aim_ssi_addmastergroup(sess, conn);
     595                if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0)))
     596                        return -ENOMEM;
     597        }
     598
     599        /* Allocate an array of pointers to each of the new items */
     600        if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
     601                return -ENOMEM;
     602
     603        /* Add items to the local list, and index them in the array */
     604        for (i=0; i<num; i++)
     605                if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) {
     606                        free(newitems);
     607                        return -ENOMEM;
     608                }
     609
     610        /* Send the add item SNAC */
     611        if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
     612                free(newitems);
     613                return -i;
     614        }
     615
     616        /* Free the array of pointers to each of the new items */
     617        free(newitems);
     618
     619        /* Rebuild the additional data in the parent group */
     620        if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup)))
     621                return i;
     622
     623        /* Send the mod item SNAC */
     624        if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD)))
     625                return i;
     626
     627        /* Begin sending SSI SNACs */
     628        if (!(i = aim_ssi_dispatch(sess, conn)))
     629                return i;
     630
     631        return 0;
     632}
     633
     634/**
     635 * Add an array of a certain type of item to the list.  This can be used for
     636 * permit buddies, deny buddies, ICQ's ignore buddies, and probably other
     637 * types, also.
     638 *
     639 * @param sess The oscar session.
     640 * @param conn The bos connection for this session.
     641 * @param sn An array of null terminated strings of the names you want to add.
     642 * @param num The number of groups names you are adding (size of the sn array).
     643 * @param type The type of item you want to add.  See the AIM_SSI_TYPE_BLEH
     644 *        #defines in aim.h.
     645 * @return Return 0 if no errors, otherwise return the error number.
     646 */
     647faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type)
     648{
     649        struct aim_ssi_item **newitems;
     650        fu16_t i;
     651
     652        if (!sess || !conn || !sn || !num)
     653                return -EINVAL;
     654
     655        /* Allocate an array of pointers to each of the new items */
     656        if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
     657                return -ENOMEM;
     658
     659        /* Add items to the local list, and index them in the array */
     660        for (i=0; i<num; i++)
     661                if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) {
     662                        free(newitems);
     663                        return -ENOMEM;
     664                }
     665
     666        /* Send the add item SNAC */
     667        if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
     668                free(newitems);
     669                return -i;
     670        }
     671
     672        /* Free the array of pointers to each of the new items */
     673        free(newitems);
     674
     675        /* Begin sending SSI SNACs */
     676        if (!(i = aim_ssi_dispatch(sess, conn)))
     677                return i;
     678
     679        return 0;
     680}
     681
     682/**
     683 * Move a buddy from one group to another group.  This basically just deletes the
     684 * buddy and re-adds it.
     685 *
     686 * @param sess The oscar session.
     687 * @param conn The bos connection for this session.
     688 * @param oldgn The group that the buddy is currently in.
     689 * @param newgn The group that the buddy should be moved in to.
     690 * @param sn The name of the buddy to be moved.
     691 * @return Return 0 if no errors, otherwise return the error number.
     692 */
     693faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn)
     694{
     695        struct aim_ssi_item **groups, *buddy, *cur;
     696        fu16_t i;
     697
     698        if (!sess || !conn || !oldgn || !newgn || !sn)
     699                return -EINVAL;
     700
     701        /* Look up the buddy */
     702        if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY)))
     703                return -ENOMEM;
     704
     705        /* Allocate an array of pointers to the two groups */
     706        if (!(groups = (struct aim_ssi_item **)malloc(2*sizeof(struct aim_ssi_item *))))
     707                return -ENOMEM;
     708
     709        /* Look up the old parent group */
     710        if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) {
     711                free(groups);
     712                return -ENOMEM;
     713        }
     714
     715        /* Look up the new parent group */
     716        if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) {
     717                aim_ssi_addgroups(sess, conn, (const char**)&newgn, 1);
     718                if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) {
     719                        free(groups);
     720                        return -ENOMEM;
     721                }
     722        }
     723
     724        /* Send the delete item SNAC */
     725        aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL);
     726
     727        /* Put the buddy in the new group */
     728        buddy->gid = groups[1]->gid;
     729
     730        /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */
     731        buddy->bid = 0;
     732        do {
     733                buddy->bid += 0x0001;
     734                for (cur=sess->ssi.items, i=0; ((cur) && (!i)); cur=cur->next)
     735                        if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && aim_sncmp(cur->name, buddy->name))
     736                                i=1;
     737        } while (i);
     738
     739        /* Rebuild the additional data in the two parent groups */
     740        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]);
     741        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]);
     742
     743        /* Send the add item SNAC */
     744        aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD);
     745
     746        /* Send the mod item SNAC */
     747        aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD);
     748
     749        /* Free the temporary array */
     750        free(groups);
     751
     752        /* Begin sending SSI SNACs */
     753        aim_ssi_dispatch(sess, conn);
     754
     755        return 0;
     756}
     757
     758/**
     759 * Rename a group.  I really like how this is done.  It turns me on.
     760 *
     761 * Did I say that out loud?...
     762 *
     763 * @param sess The oscar session.
     764 * @param conn The bos connection for this session.
     765 * @param oldgn The old group name.
     766 * @param newgn The new group name.
     767 * @return Return 0 if no errors, otherwise return the error number.
     768 */
     769faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn)
     770{
     771        struct aim_ssi_item *group;
     772
     773        if (!sess || !conn || !oldgn || !newgn)
     774                return -EINVAL;
     775
     776        /* Look up the group */
     777        if (!(group = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP)))
     778                return -ENOMEM;
     779
     780        /* Free the old group name and copy the new one in its place. */
     781        if (group->name)
     782                free(group->name);
     783        if (!(group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)))) {
     784                group->name = NULL;
     785                return -ENOMEM;
     786        }
     787        strcpy(group->name, newgn);
     788
     789        /* Send the mod item SNAC */
     790        aim_ssi_addmoddel(sess, conn, &group, 1, AIM_CB_SSI_MOD);
     791
     792        /* Begin sending SSI SNACs */
     793        aim_ssi_dispatch(sess, conn);
     794
     795        return 0;
     796}
     797
     798/**
     799 * Delete an array of screen names from the given group.
     800 *
     801 * @param sess The oscar session.
     802 * @param conn The bos connection for this session.
     803 * @param gn The name of the group from which you want to delete these names.
     804 * @param sn An array of null terminated strings of the names you want to delete.
     805 * @param num The number of screen names you are deleting (size of the sn array).
     806 * @return Return 0 if no errors, otherwise return the error number.
     807 */
     808faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num)
     809{
     810        struct aim_ssi_item *cur, *parentgroup, **delitems;
     811        int i;
     812
     813        if (!sess || !conn || !gn || !sn || !num)
     814                return -EINVAL;
     815
     816        /* Look up the parent group */
     817        if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP)))
     818                return -EINVAL;
     819
     820        /* Allocate an array of pointers to each of the items to be deleted */
     821        delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
     822        memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
     823
     824        /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
     825        for (i=0; i<num; i++) {
     826                if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) {
     827                        free(delitems);
     828                        return -EINVAL;
     829                }
     830
     831                /* Remove the delitems from the item list */
     832                if (sess->ssi.items == delitems[i]) {
     833                        sess->ssi.items = sess->ssi.items->next;
     834                } else {
     835                        for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
     836                        if (cur->next)
     837                                cur->next = cur->next->next;
     838                }
     839        }
     840
     841        /* Send the del item SNAC */
     842        aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
     843
     844        /* Free the items */
     845        for (i=0; i<num; i++) {
     846                if (delitems[i]->name)
     847                        free(delitems[i]->name);
     848                if (delitems[i]->data)
     849                        aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
     850                free(delitems[i]);
     851        }
     852        free(delitems);
     853
     854        /* Rebuild the additional data in the parent group */
     855        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);
     856
     857        /* Send the mod item SNAC */
     858        aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
     859
     860        /* Delete the group, but only if it's empty */
     861        if (!parentgroup->data)
     862                aim_ssi_delgroups(sess, conn, &parentgroup->name, 1);
     863
     864        /* Begin sending SSI SNACs */
     865        aim_ssi_dispatch(sess, conn);
     866
     867        return 0;
     868}
     869
     870/**
     871 * Delete the master group from the item list.  There can be only one.
     872 * Er, so just find the one master group and delete it.
     873 *
     874 * @param sess The oscar session.
     875 * @param conn The bos connection for this session.
     876 * @return Return 0 if no errors, otherwise return the error number.
     877 */
     878faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn)
     879{
     880        struct aim_ssi_item *cur, *delitem;
     881
     882        if (!sess || !conn)
     883                return -EINVAL;
     884
     885        /* Make delitem a pointer to the aim_ssi_item to be deleted */
     886        if (!(delitem = aim_ssi_itemlist_find(sess->ssi.items, 0, 0)))
     887                return -EINVAL;
     888
     889        /* Remove delitem from the item list */
     890        if (sess->ssi.items == delitem) {
     891                sess->ssi.items = sess->ssi.items->next;
     892        } else {
     893                for (cur=sess->ssi.items; (cur->next && (cur->next!=delitem)); cur=cur->next);
     894                if (cur->next)
     895                        cur->next = cur->next->next;
     896        }
     897
     898        /* Send the del item SNAC */
     899        aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL);
     900
     901        /* Free the item */
     902        if (delitem->name)
     903                free(delitem->name);
     904        if (delitem->data)
     905                aim_freetlvchain((aim_tlvlist_t **)&delitem->data);
     906        free(delitem);
     907
     908        /* Begin sending SSI SNACs */
     909        aim_ssi_dispatch(sess, conn);
     910
     911        return 0;
     912}
     913
     914/**
     915 * Delete an array of groups.
     916 *
     917 * @param sess The oscar session.
     918 * @param conn The bos connection for this session.
     919 * @param gn An array of null terminated strings of the groups you want to delete.
     920 * @param num The number of groups you are deleting (size of the gn array).
     921 * @return Return 0 if no errors, otherwise return the error number.
     922 */
     923faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) {
     924        struct aim_ssi_item *cur, *parentgroup, **delitems;
     925        int i;
     926
     927        if (!sess || !conn || !gn || !num)
     928                return -EINVAL;
     929
     930        /* Look up the parent group */
     931        if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0)))
     932                return -EINVAL;
     933
     934        /* Allocate an array of pointers to each of the items to be deleted */
     935        delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
     936        memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
     937
     938        /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
     939        for (i=0; i<num; i++) {
     940                if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) {
     941                        free(delitems);
     942                        return -EINVAL;
     943                }
     944
     945                /* Remove the delitems from the item list */
     946                if (sess->ssi.items == delitems[i]) {
     947                        sess->ssi.items = sess->ssi.items->next;
     948                } else {
     949                        for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
     950                        if (cur->next)
     951                                cur->next = cur->next->next;
     952                }
     953        }
     954
     955        /* Send the del item SNAC */
     956        aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
     957
     958        /* Free the items */
     959        for (i=0; i<num; i++) {
     960                if (delitems[i]->name)
     961                        free(delitems[i]->name);
     962                if (delitems[i]->data)
     963                        aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
     964                free(delitems[i]);
     965        }
     966        free(delitems);
     967
     968        /* Rebuild the additional data in the parent group */
     969        aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);
     970
     971        /* Send the mod item SNAC */
     972        aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
     973
     974        /* Delete the group, but only if it's empty */
     975        if (!parentgroup->data)
     976                aim_ssi_delmastergroup(sess, conn);
     977
     978        /* Begin sending SSI SNACs */
     979        aim_ssi_dispatch(sess, conn);
     980
     981        return 0;
     982}
     983
     984/**
     985 * Delete an array of a certain type of item from the list.  This can be
     986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and
     987 * probably other types, also.
     988 *
     989 * @param sess The oscar session.
     990 * @param conn The bos connection for this session.
     991 * @param sn An array of null terminated strings of the items you want to delete.
     992 * @param num The number of items you are deleting (size of the sn array).
     993 * @return Return 0 if no errors, otherwise return the error number.
     994 */
     995faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) {
     996        struct aim_ssi_item *cur, **delitems;
     997        int i;
     998
     999        if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY))
     1000                return -EINVAL;
     1001
     1002        /* Allocate an array of pointers to each of the items to be deleted */
     1003        delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
     1004        memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
     1005
     1006        /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
     1007        for (i=0; i<num; i++) {
     1008                if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) {
     1009                        free(delitems);
     1010                        return -EINVAL;
     1011                }
     1012
     1013                /* Remove the delitems from the item list */
     1014                if (sess->ssi.items == delitems[i]) {
     1015                        sess->ssi.items = sess->ssi.items->next;
     1016                } else {
     1017                        for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
     1018                        if (cur->next)
     1019                                cur->next = cur->next->next;
     1020                }
     1021        }
     1022
     1023        /* Send the del item SNAC */
     1024        aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
     1025
     1026        /* Free the items */
     1027        for (i=0; i<num; i++) {
     1028                if (delitems[i]->name)
     1029                        free(delitems[i]->name);
     1030                if (delitems[i]->data)
     1031                        aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
     1032                free(delitems[i]);
     1033        }
     1034        free(delitems);
     1035
     1036        /* Begin sending SSI SNACs */
     1037        aim_ssi_dispatch(sess, conn);
     1038
     1039        return 0;
     1040}
     1041
     1042/**
     1043 * Stores your permit/deny setting on the server, and starts using it.
     1044 *
     1045 * @param sess The oscar session.
     1046 * @param conn The bos connection for this session.
     1047 * @param permdeny Your permit/deny setting.  Can be one of the following:
     1048 *        1 - Allow all users
     1049 *        2 - Block all users
     1050 *        3 - Allow only the users below
     1051 *        4 - Block only the users below
     1052 *        5 - Allow only users on my buddy list
     1053 * @param vismask A bitmask of the class of users to whom you want to be
     1054 *        visible.  See the AIM_FLAG_BLEH #defines in aim.h
     1055 * @return Return 0 if no errors, otherwise return the error number.
     1056 */
     1057faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) {
     1058        struct aim_ssi_item *cur;
     1059        aim_tlv_t *tlv;
     1060
     1061        if (!sess || !conn)
     1062                return -EINVAL;
     1063
     1064        /* Look up the permit/deny settings item */
     1065        cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO);
     1066
     1067        if (cur) {
     1068                /* The permit/deny item exists */
     1069                if (cur->data && (tlv = aim_gettlv(cur->data, 0x00ca, 1))) {
     1070                        /* Just change the value of the x00ca TLV */
     1071                        if (tlv->length != 1) {
     1072                                tlv->length = 1;
     1073                                free(tlv->value);
     1074                                tlv->value = (fu8_t *)malloc(sizeof(fu8_t));
     1075                        }
     1076                        tlv->value[0] = permdeny;
     1077                } else {
     1078                        /* Need to add the x00ca TLV to the TLV chain */
     1079                        aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny);
     1080                }
     1081
     1082                if (cur->data && (tlv = aim_gettlv(cur->data, 0x00cb, 1))) {
     1083                        /* Just change the value of the x00cb TLV */
     1084                        if (tlv->length != 4) {
     1085                                tlv->length = 4;
     1086                                free(tlv->value);
     1087                                tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t));
     1088                        }
     1089                        aimutil_put32(tlv->value, vismask);
     1090                } else {
     1091                        /* Need to add the x00cb TLV to the TLV chain */
     1092                        aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask);
     1093                }
     1094
     1095                /* Send the mod item SNAC */
     1096                aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD);
     1097        } else {
     1098                /* Need to add the permit/deny item */
     1099                if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO)))
     1100                        return -ENOMEM;
     1101                aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny);
     1102                aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask);
     1103                aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
     1104        }
     1105
     1106        /* Begin sending SSI SNACs */
     1107        aim_ssi_dispatch(sess, conn);
     1108
     1109        return 0;
     1110}
     1111
     1112/**
     1113 * Stores your setting for whether you should show up as idle or not.
     1114 *
     1115 * @param sess The oscar session.
     1116 * @param conn The bos connection for this session.
     1117 * @param presence I think it's a bitmask, but I only know what one of the bits is:
     1118 *        0x00000400 - Allow others to see your idle time
     1119 * @return Return 0 if no errors, otherwise return the error number.
     1120 */
     1121faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) {
     1122        struct aim_ssi_item *cur;
     1123        aim_tlv_t *tlv;
     1124
     1125        if (!sess || !conn)
     1126                return -EINVAL;
     1127
     1128        /* Look up the item */
     1129        cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
     1130
     1131        if (cur) {
     1132                /* The item exists */
     1133                if (cur->data && (tlv = aim_gettlv(cur->data, 0x00c9, 1))) {
     1134                        /* Just change the value of the x00c9 TLV */
     1135                        if (tlv->length != 4) {
     1136                                tlv->length = 4;
     1137                                free(tlv->value);
     1138                                tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t));
     1139                        }
     1140                        aimutil_put32(tlv->value, presence);
     1141                } else {
     1142                        /* Need to add the x00c9 TLV to the TLV chain */
     1143                        aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence);
     1144                }
     1145
     1146                /* Send the mod item SNAC */
     1147                aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD);
     1148        } else {
     1149                /* Need to add the item */
     1150                if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS)))
     1151                        return -ENOMEM;
     1152                aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence);
     1153                aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
     1154        }
     1155
     1156        /* Begin sending SSI SNACs */
     1157        aim_ssi_dispatch(sess, conn);
     1158
     1159        return 0;
     1160}
     1161
    151162/*
    161163 * Request SSI Rights.
     
    181165faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn)
    191166{
    20         return aim_genericreq_n(sess, conn, 0x0013, 0x0002);
     1167        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
    211168}
    221169
     
    551202                return -ENOMEM;
    561203
    57         snacid = aim_cachesnac(sess, 0x0013, 0x0005, 0x0000, NULL, 0);
    58 
    59         aim_putsnac(&fr->data, 0x0013, 0x0005, 0x0000, snacid);
     1204        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, NULL, 0);
     1205
     1206        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, snacid);
    601207        aimbs_put32(&fr->data, localstamp);
    611208        aimbs_put16(&fr->data, localrev);
     
    731220        int ret = 0;
    741221        aim_rxcallback_t userfunc;
    75         struct aim_ssi_item *list = NULL;
     1222        struct aim_ssi_item *cur = NULL;
    761223        fu8_t fmtver; /* guess */
    77         fu16_t itemcount;
    78         fu32_t stamp;
    79 
    80         fmtver = aimbs_get8(bs);
    81         itemcount = aimbs_get16(bs);
     1224        fu16_t revision;
     1225        fu32_t timestamp;
     1226
     1227        /* When you set the version for the SSI family to 2-4, the beginning of this changes.
     1228         * Instead of the version and then the revision, there is "0x0006" and then a type
     1229         * 0x0001 TLV containing the 2 byte SSI family version that you sent earlier.  Also,
     1230         * the SNAC flags go from 0x0000 to 0x8000.  I guess the 0x0006 is the length of the
     1231         * TLV(s) that follow.  The rights SNAC does the same thing, with the differing flag
     1232         * and everything.
     1233         */
     1234
     1235        fmtver = aimbs_get8(bs); /* Version of ssi data.  Should be 0x00 */
     1236        revision = aimbs_get16(bs); /* # of times ssi data has been modified */
     1237        if (revision != 0)
     1238                sess->ssi.revision = revision;
     1239
     1240        for (cur = sess->ssi.items; cur && cur->next; cur=cur->next) ;
    821241
    831242        while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */
    841243                fu16_t namelen, tbslen;
    85                 struct aim_ssi_item *nl, *el;
    86 
    87                 if (!(nl = malloc(sizeof(struct aim_ssi_item))))
    88                         break;
    89                 memset(nl, 0, sizeof(struct aim_ssi_item));
     1244
     1245                if (!sess->ssi.items) {
     1246                        if (!(sess->ssi.items = malloc(sizeof(struct aim_ssi_item))))
     1247                                return -ENOMEM;
     1248                        cur = sess->ssi.items;
     1249                } else {
     1250                        if (!(cur->next = malloc(sizeof(struct aim_ssi_item))))
     1251                                return -ENOMEM;
     1252                        cur = cur->next;
     1253                }
     1254                memset(cur, 0, sizeof(struct aim_ssi_item));
    901255
    911256                if ((namelen = aimbs_get16(bs)))
    92                         nl->name = aimbs_getstr(bs, namelen);
    93                 nl->gid = aimbs_get16(bs);
    94                 nl->bid = aimbs_get16(bs);
    95                 nl->type = aimbs_get16(bs);
     1257                        cur->name = aimbs_getstr(bs, namelen);
     1258                cur->gid = aimbs_get16(bs);
     1259                cur->bid = aimbs_get16(bs);
     1260                cur->type = aimbs_get16(bs);
    961261
    971262                if ((tbslen = aimbs_get16(bs))) {
     
    991264
    1001265                        aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen);
    101                         nl->data = (void *)aim_readtlvchain(&tbs);
     1266                        cur->data = (void *)aim_readtlvchain(&tbs);
    1021267                        aim_bstream_advance(bs, tbslen);
    1031268                }
    104 
    105                 for (el = list; el && el->next; el = el->next)
    106                         ;
    107                 if (el)
    108                         el->next = nl;
    109                 else
    110                         list = nl;
    111         }
    112 
    113         stamp = aimbs_get32(bs);
     1269        }
     1270
     1271        timestamp = aimbs_get32(bs);
     1272        if (timestamp != 0)
     1273                sess->ssi.timestamp = timestamp;
     1274        sess->ssi.received_data = 1;
    1141275
    1151276        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    116                 ret = userfunc(sess, rx, fmtver, itemcount, stamp, list);
    117 
    118         while (list) {
    119                 struct aim_ssi_item *tmp;
    120 
    121                 tmp = list->next;
    122                 aim_freetlvchain((aim_tlvlist_t **)&list->data);
    123                 free(list);
    124                 list = tmp;
    125         }
     1277                ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items);
    1261278
    1271279        return ret;
     
    1391291faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn)
    1401292{
    141         return aim_genericreq_n(sess, conn, 0x0013, 0x0007);
     1293        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
     1294}
     1295
     1296/*
     1297 * SSI Add/Mod/Del Item(s).
     1298 *
     1299 * Sends the SNAC to add, modify, or delete an item from the server-stored
     1300 * information.  These 3 SNACs all have an identical structure.  The only
     1301 * difference is the subtype that is set for the SNAC.
     1302 *
     1303 */
     1304faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype)
     1305{
     1306        aim_frame_t *fr;
     1307        aim_snacid_t snacid;
     1308        int i, snaclen;
     1309
     1310        if (!sess || !conn || !items || !num)
     1311                return -EINVAL;
     1312
     1313        snaclen = 10; /* For family, subtype, flags, and SNAC ID */
     1314        for (i=0; i<num; i++) {
     1315                snaclen += 10; /* For length, GID, BID, type, and length */
     1316                if (items[i]->name)
     1317                        snaclen += strlen(items[i]->name);
     1318                if (items[i]->data)
     1319                        snaclen += aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data);
     1320        }
     1321
     1322        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen)))
     1323                return -ENOMEM;
     1324
     1325        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, NULL, 0);
     1326        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid);
     1327
     1328        for (i=0; i<num; i++) {
     1329                aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0);
     1330                if (items[i]->name)
     1331                        aimbs_putraw(&fr->data, items[i]->name, strlen(items[i]->name));
     1332                aimbs_put16(&fr->data, items[i]->gid);
     1333                aimbs_put16(&fr->data, items[i]->bid);
     1334                aimbs_put16(&fr->data, items[i]->type);
     1335                aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data) : 0);
     1336                if (items[i]->data)
     1337                        aim_writetlvchain(&fr->data, (aim_tlvlist_t **)&items[i]->data);
     1338        }
     1339
     1340        aim_ssi_enqueue(sess, conn, fr);
     1341
     1342        return 0;
     1343}
     1344
     1345/*
     1346 * SSI Add/Mod/Del Ack.
     1347 *
     1348 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
     1349 *
     1350 */
     1351static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1352{
     1353        int ret = 0;
     1354        aim_rxcallback_t userfunc;
     1355
     1356        sess->ssi.waiting_for_ack = 0;
     1357        aim_ssi_dispatch(sess, rx->conn);
     1358
     1359        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1360                ret = userfunc(sess, rx);
     1361
     1362        return ret;
    1421363}
    1431364
     
    1501371faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn)
    1511372{
    152         return aim_genericreq_n(sess, conn, 0x0013, 0x0011);
     1373        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
    1531374}
    1541375
     
    1611382faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn)
    1621383{
    163         return aim_genericreq_n(sess, conn, 0x0013, 0x0012);
     1384        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
    1641385}
    1651386
     
    1761397        aim_rxcallback_t userfunc;
    1771398
     1399        sess->ssi.received_data = 1;
     1400
    1781401        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1791402                ret = userfunc(sess, rx);
     
    1851408{
    1861409
    187         if (snac->subtype == 0x0003)
     1410        if (snac->subtype == AIM_CB_SSI_RIGHTSINFO)
    1881411                return parserights(sess, mod, rx, snac, bs);
    189         else if (snac->subtype == 0x006)
     1412        else if (snac->subtype == AIM_CB_SSI_LIST)
    1901413                return parsedata(sess, mod, rx, snac, bs);
    191         else if (snac->subtype == 0x00f)
     1414        else if (snac->subtype == AIM_CB_SSI_SRVACK)
     1415                return parseack(sess, mod, rx, snac, bs);
     1416        else if (snac->subtype == AIM_CB_SSI_NOLIST)
    1921417                return parsedataunchanged(sess, mod, rx, snac, bs);
    1931418
     
    1951420}
    1961421
     1422static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod)
     1423{
     1424        aim_ssi_freelist(sess);
     1425
     1426        return;
     1427}
     1428
    1971429faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod)
    1981430{
    1991431
    200         mod->family = 0x0013;
     1432        mod->family = AIM_CB_FAM_SSI;
    2011433        mod->version = 0x0001;
    2021434        mod->toolid = 0x0110;
     
    2051437        strncpy(mod->name, "ssi", sizeof(mod->name));
    2061438        mod->snachandler = snachandler;
    207 
    208         return 0;
    209 }
    210 
    211 
     1439        mod->shutdown = ssi_shutdown;
     1440
     1441        return 0;
     1442}
  • libfaim/stats.c

    r5e53c4a r862371b  
     1/*
     2 * Family 0x000b - Statistics.
     3 *
     4 */
    15
    26#define FAIM_INTERNAL
  • libfaim/tlv.c

    r5e53c4a r862371b  
    2929/**
    3030 * aim_readtlvchain - Read a TLV chain from a buffer.
    31  * @buf: Input buffer
    32  * @maxlen: Length of input buffer
     31 * @param bs Input bstream
    3332 *
    3433 * Reads and parses a series of TLV patterns from a data buffer; the
     
    4746{
    4847        aim_tlvlist_t *list = NULL, *cur;
    49 
     48       
    5049        while (aim_bstream_empty(bs) > 0) {
    5150                fu16_t type, length;
     
    7170                else {
    7271
    73                         if (length > aim_bstream_empty(bs))
    74                                 goto errout;
     72                        if (length > aim_bstream_empty(bs)) {
     73                                aim_freetlvchain(&list);
     74                                return NULL;
     75                        }
    7576
    7677                        cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
    77                         if (!cur)
    78                                 goto errout;
     78                        if (!cur) {
     79                                aim_freetlvchain(&list);
     80                                return NULL;
     81                        }
    7982
    8083                        memset(cur, 0, sizeof(aim_tlvlist_t));
    8184
    82                         cur->tlv = createtlv(); 
     85                        cur->tlv = createtlv();
    8386                        if (!cur->tlv) {
    8487                                free(cur);
    85                                 goto errout;
     88                                aim_freetlvchain(&list);
     89                                return NULL;
    8690                        }
    8791                        cur->tlv->type = type;
     
    9195                                       freetlv(&cur->tlv);
    9296                                       free(cur);
    93                                        goto errout;
     97                                       aim_freetlvchain(&list);
     98                                       return NULL;
    9499                               }
    95100                        }
     
    101106
    102107        return list;
    103 
    104 errout:
    105         aim_freetlvchain(&list);
    106         return NULL;
     108}
     109
     110/**
     111 * aim_readtlvchain_num - Read a TLV chain from a buffer.
     112 * @param bs Input bstream
     113 * @param num The max number of TLVs that will be read, or -1 if unlimited. 
     114 *        There are a number of places where you want to read in a tlvchain,
     115 *        but the chain is not at the end of the SNAC, and the chain is
     116 *        preceeded by the number of TLVs.  So you can limit that.
     117 *
     118 * Reads and parses a series of TLV patterns from a data buffer; the
     119 * returned structure is manipulatable with the rest of the TLV
     120 * routines.  When done with a TLV chain, aim_freetlvchain() should
     121 * be called to free the dynamic substructures.
     122 *
     123 * XXX There should be a flag setable here to have the tlvlist contain
     124 * bstream references, so that at least the ->value portion of each
     125 * element doesn't need to be malloc/memcpy'd.  This could prove to be
     126 * just as effecient as the in-place TLV parsing used in a couple places
     127 * in libfaim.
     128 *
     129 */
     130faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num)
     131{
     132        aim_tlvlist_t *list = NULL, *cur;
     133       
     134        while ((aim_bstream_empty(bs) > 0) && (num != 0)) {
     135                fu16_t type, length;
     136
     137                type = aimbs_get16(bs);
     138                length = aimbs_get16(bs);
     139
     140                if (length > aim_bstream_empty(bs)) {
     141                        aim_freetlvchain(&list);
     142                        return NULL;
     143                }
     144
     145                cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
     146                if (!cur) {
     147                        aim_freetlvchain(&list);
     148                        return NULL;
     149                }
     150
     151                memset(cur, 0, sizeof(aim_tlvlist_t));
     152
     153                cur->tlv = createtlv();
     154                if (!cur->tlv) {
     155                        free(cur);
     156                        aim_freetlvchain(&list);
     157                        return NULL;
     158                }
     159                cur->tlv->type = type;
     160                if ((cur->tlv->length = length)) {
     161                       cur->tlv->value = aimbs_getraw(bs, length);     
     162                       if (!cur->tlv->value) {
     163                               freetlv(&cur->tlv);
     164                               free(cur);
     165                               aim_freetlvchain(&list);
     166                               return NULL;
     167                       }
     168                }
     169
     170                num--;
     171                cur->next = list;
     172                list = cur;
     173        }
     174
     175        return list;
    107176}
    108177
     
    182251
    183252/**
    184  * aim_addtlvtochain_str - Add a string to a TLV chain
     253 * aim_addtlvtochain_raw - Add a string to a TLV chain
    185254 * @list: Desination chain (%NULL pointer if empty)
    186  * @type: TLV type
    187  * @str: String to add
    188  * @len: Length of string to add (not including %NULL)
     255 * @t: TLV type
     256 * @l: Length of string to add (not including %NULL)
     257 * @v: String to add
    189258 *
    190259 * Adds the passed string as a TLV element of the passed type
     
    245314 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
    246315 * @list: Destination chain
    247  * @type: TLV type to add
    248  * @val: Value to add
     316 * @t: TLV type to add
     317 * @v: Value to add
    249318 *
    250319 * Adds a two-byte unsigned integer to a TLV chain.
     
    607676}
    608677#endif
    609 
  • libfaim/translate.c

    r5e53c4a r862371b  
    11/*
     2 * Family 0x000c - Translation.
     3 *
    24 * I have no idea why this group was issued.  I have never seen anything
    35 * that uses it.  From what I remember, the last time I tried to poke at
     
    2426        return 0;
    2527}
    26 
    27 
  • libfaim/txqueue.c

    r5e53c4a r862371b  
    11/*
    2  *  aim_txqueue.c
     2 * txqueue.c
    33 *
    44 * Herein lies all the mangement routines for the transmit (Tx) queue.
     
    1111#ifndef _WIN32
    1212#include <sys/socket.h>
     13#else
     14#include "win32dep.h"
    1315#endif
    1416
     
    2527 *
    2628 */
    27 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen)
     29faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen)
    2830{
    2931        aim_frame_t *fr;
     
    6264        } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) {
    6365
    64                 fr->hdr.oft.type = chan;
    65                 fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */
     66                fr->hdr.rend.type = chan;
    6667
    6768        } else
     
    231232{
    232233        int wrote = 0;
    233 
    234234        if (!bs || !conn || (count < 0))
    235235                return -EINVAL;
     
    238238                count = aim_bstream_empty(bs); /* truncate to remaining space */
    239239
    240         if (count)
    241                 wrote = aim_send(conn->fd, bs->data + bs->offset, count);
     240        if (count) {
     241                if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) &&
     242                    (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
     243                        /* I strongly suspect that this is a horrible thing to do
     244                         * and I feel really guilty doing it. */
     245                        const char *sn = aim_directim_getsn(conn);
     246                        aim_rxcallback_t userfunc;
     247                        while (count - wrote > 1024) {
     248                                wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, 1024);
     249                                if ((userfunc=aim_callhandler(conn->sessv, conn,
     250                                                              AIM_CB_FAM_SPECIAL,
     251                                                              AIM_CB_SPECIAL_IMAGETRANSFER)))
     252                                  userfunc(conn->sessv, NULL, sn,
     253                                           count-wrote>1024 ? ((double)wrote / count) : 1);
     254                        }
     255                }
     256                if (count - wrote) {
     257                        wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
     258                }
     259               
     260        }
     261       
    242262
    243263        if (((aim_session_t *)conn->sessv)->debug >= 2) {
     
    285305        obslen = aim_bstream_curpos(&obs);
    286306        aim_bstream_rewind(&obs);
    287 
    288307        if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)
    289308                err = -errno;
     
    297316}
    298317
    299 static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr)
    300 {
    301         aim_bstream_t hbs;
    302         fu8_t *hbs_raw;
    303         int hbslen;
     318static int sendframe_rendezvous(aim_session_t *sess, aim_frame_t *fr)
     319{
     320        aim_bstream_t bs;
     321        fu8_t *bs_raw;
    304322        int err = 0;
    305 
    306         hbslen = 8 + fr->hdr.oft.hdr2len;
    307 
    308         if (!(hbs_raw = malloc(hbslen)))
     323        int totlen = 8 + aim_bstream_curpos(&fr->data);
     324
     325        if (!(bs_raw = malloc(totlen)))
    309326                return -1;
    310327
    311         aim_bstream_init(&hbs, hbs_raw, hbslen);
    312 
    313         aimbs_putraw(&hbs, fr->hdr.oft.magic, 4);
    314         aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8);
    315         aimbs_put16(&hbs, fr->hdr.oft.type);
    316         aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
    317 
    318         aim_bstream_rewind(&hbs);
    319        
    320         if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) {
    321 
     328        aim_bstream_init(&bs, bs_raw, totlen);
     329
     330        aimbs_putraw(&bs, fr->hdr.rend.magic, 4);
     331        aimbs_put16(&bs, 8 + fr->hdr.rend.hdrlen);
     332        aimbs_put16(&bs, fr->hdr.rend.type);
     333
     334        /* payload */
     335        aim_bstream_rewind(&fr->data);
     336        aimbs_putbs(&bs, &fr->data, totlen - 8);
     337
     338        aim_bstream_rewind(&bs);
     339
     340        if (aim_bstream_send(&bs, fr->conn, totlen) != totlen)
    322341                err = -errno;
    323                
    324         } else if (aim_bstream_curpos(&fr->data)) {
    325                 int len;
    326 
    327                 len = aim_bstream_curpos(&fr->data);
    328                 aim_bstream_rewind(&fr->data);
    329                
    330                 if (aim_bstream_send(&fr->data, fr->conn, len) != len)
    331                         err = -errno;
    332         }
    333 
    334         free(hbs_raw); /* XXX aim_bstream_free */
     342
     343        free(bs_raw); /* XXX aim_bstream_free */
    335344
    336345        fr->handled = 1;
    337346        fr->conn->lastactivity = time(NULL);
    338 
    339347
    340348        return err;
     
    346354                return sendframe_flap(sess, fr);
    347355        else if (fr->hdrtype == AIM_FRAMETYPE_OFT)
    348                 return sendframe_oft(sess, fr);
     356                return sendframe_rendezvous(sess, fr);
    349357        return -1;
    350358}
     
    422430 *
    423431 */
    424 faim_export void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
     432faim_internal void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
    425433{
    426434        aim_frame_t *cur;
     
    433441        return;
    434442}
    435 
    436 
  • libfaim/util.c

    r5e53c4a r862371b  
    139139*
    140140*/
    141 
    142141faim_export int aim_sncmp(const char *sn1, const char *sn2)
    143142{
     
    205204        return p;
    206205}
    207 
    208 
Note: See TracChangeset for help on using the changeset viewer.