Changeset e374dee for libfaim


Ignore:
Timestamp:
Oct 10, 2003, 5:12:30 PM (22 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:
fe6f1d3
Parents:
f4d0975
Message:
*** empty log message ***
Location:
libfaim
Files:
32 edited

Legend:

Unmodified
Added
Removed
  • libfaim/admin.c

    r862371b re374dee  
    44 * Used for stuff like changing the formating of your screen name, changing your
    55 * email address, requesting an account confirmation email, getting account info,
    6  * 
     6 *
    77 */
    88
     
    197197static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    198198{
     199        int ret = 0;
    199200        aim_rxcallback_t userfunc;
    200201        fu16_t status;
     
    207208
    208209        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    209                 return userfunc(sess, rx, status);
    210 
    211         return 0;
     210                ret = userfunc(sess, rx, status);
     211
     212        return ret;
    212213}
    213214
     
    228229        mod->family = 0x0007;
    229230        mod->version = 0x0001;
    230         mod->toolid = AIM_TOOL_NEWWIN;
    231         mod->toolversion = 0x0361; /* XXX this and above aren't right */
     231        mod->toolid = 0x0010;
     232        mod->toolversion = 0x0629;
    232233        mod->flags = 0;
    233234        strncpy(mod->name, "admin", sizeof(mod->name));
  • libfaim/aim.h

    r862371b re374dee  
    33 *
    44 * "come on, i turned a chick lesbian; i think this is the hackish equivalent"
    5  *                                                -- Josh Meyer
     5 *                                                -- Josh Myer
    66 *
    77 */
     
    2929#include <sys/time.h>
    3030#include <unistd.h>
     31#include <netdb.h>
    3132#include <netinet/in.h>
    3233#include <sys/socket.h>
     
    3536#endif
    3637
     38#ifdef __cplusplus
     39extern "C" {
     40#endif
     41
    3742/* XXX adjust these based on autoconf-detected platform */
    3843typedef unsigned char fu8_t;
    3944typedef unsigned short fu16_t;
    40 typedef unsigned long fu32_t;
     45typedef unsigned int fu32_t;
    4146typedef fu32_t aim_snacid_t;
    4247typedef fu16_t flap_seqnum_t;
     
    4449#if defined(mach) && defined(__APPLE__)
    4550#define gethostbyname(x) gethostbyname2(x, AF_INET)
    46 #endif
    47 
    48 #if defined(_WIN32) || defined(STRICT_ANSI)
    49 #define faim_shortfunc
    50 #else
    51 #define faim_shortfunc inline
    5251#endif
    5352
     
    7372#endif
    7473
     74#ifndef FALSE
     75#define FALSE (0)
     76#endif
     77
     78#ifndef TRUE
     79#define TRUE (!FALSE)
     80#endif
     81
    7582/*
    7683 * Current Maximum Length for Screen Names (not including NULL)
     
    7986 * however it is aparently legal for them to be larger.
    8087 */
    81 #define MAXSNLEN 32
     88#define MAXSNLEN 97
    8289
    8390/*
     
    114121#define MAXCHATMSGLEN 512
    115122
    116 /*
    117  * Standard size of an AIM authorization cookie
    118  */
    119 #define AIM_COOKIELEN            0x100
     123/**
     124 * Maximum length for the password of an ICQ account
     125 */
     126#define MAXICQPASSLEN 8
    120127
    121128#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
     
    130137        const char *clientstring;
    131138        fu16_t clientid;
    132         int major;
    133         int minor;
    134         int point;
    135         int build;
     139        fu16_t major;
     140        fu16_t minor;
     141        fu16_t point;
     142        fu16_t build;
     143        fu32_t distrib;
    136144        const char *country; /* two-letter abbrev */
    137145        const char *lang; /* two-letter abbrev */
    138146};
    139147
     148/* Needs to be checked */
    140149#define CLIENTINFO_AIM_3_5_1670 { \
    141150        "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
    142151        0x0004, \
    143         0x0003, \
    144         0x0005, \
    145         0x0000, \
    146         0x0686, \
    147         "us", \
    148         "en", \
     152        0x0003, 0x0005, \
     153        0x0000, 0x0686, \
     154        0x0000002a, \
     155        "us", "en", \
    149156}
    150157
     158/* Needs to be checked */
     159/* Latest winaim without ssi */
    151160#define CLIENTINFO_AIM_4_1_2010 { \
    152           "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
    153           0x0004, \
    154           0x0004, \
    155           0x0001, \
    156           0x0000, \
    157           0x07da, \
    158           "us", \
    159           "en", \
     161        "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
     162        0x0004, \
     163        0x0004, 0x0001, \
     164        0x0000, 0x07da, \
     165        0x0000004b, \
     166        "us", "en", \
    160167}
    161168
     169/* Needs to be checked */
     170#define CLIENTINFO_AIM_4_3_2188 { \
     171        "AOL Instant Messenger (SM), version 4.3.2188/WIN32", \
     172        0x0109, \
     173        0x0400, 0x0003, \
     174        0x0000, 0x088c, \
     175        0x00000086, \
     176        "us", "en", \
     177}
     178
     179/* Needs to be checked */
     180#define CLIENTINFO_AIM_4_8_2540 { \
     181        "AOL Instant Messenger (SM), version 4.8.2540/WIN32", \
     182        0x0109, \
     183        0x0004, 0x0008, \
     184        0x0000, 0x09ec, \
     185        0x000000af, \
     186        "us", "en", \
     187}
     188
     189/* Needs to be checked */
    162190#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", \
     191        "AOL Instant Messenger, version 5.0.2938/WIN32", \
     192        0x0109, \
     193        0x0005, 0x0000, \
     194        0x0000, 0x0b7a, \
     195        0x00000000, \
     196        "us", "en", \
    171197}
    172198
     199#define CLIENTINFO_AIM_5_1_3036 { \
     200        "AOL Instant Messenger, version 5.1.3036/WIN32", \
     201        0x0109, \
     202        0x0005, 0x0001, \
     203        0x0000, 0x0bdc, \
     204        0x000000d2, \
     205        "us", "en", \
     206}
     207
     208#define CLIENTINFO_ICHAT_1_0 { \
     209        "Apple iChat", \
     210        0x311a, \
     211        0x0001, 0x0000, \
     212        0x0000, 0x003c, \
     213        0x000000c6, \
     214        "us", "en", \
     215}
     216
     217/* Needs to be checked */
    173218#define CLIENTINFO_ICQ_4_65_3281 { \
    174219        "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \
    175220        0x010a, \
    176         0x0004, \
    177         0x0041, \
    178         0x0001, \
    179         0x0cd1, \
    180         "us", \
    181         "en", \
     221        0x0004, 0x0041, \
     222        0x0001, 0x0cd1, \
     223        0x00000055, \
     224        "us", "en", \
    182225}
    183226
     227/* Needs to be checked */
    184228#define CLIENTINFO_ICQ_5_34_3728 { \
    185229        "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \
    186230        0x010a, \
    187         0x0005, \
    188         0x0022, \
    189         0x0001, \
    190         0x0e8f, \
    191         "us", \
    192         "en", \
     231        0x0005, 0x0022, \
     232        0x0001, 0x0e8f, \
     233        0x00000055, \
     234        "us", "en", \
    193235}
    194236
    195 /*
    196  * I would make 4.1.2010 the default, but they seem to have found
    197  * an alternate way of breaking that one.
    198  *
    199  * 3.5.1670 should work fine, however, you will be subjected to the
    200  * memory test, which may require you to have a WinAIM binary lying
    201  * around. (see login.c::memrequest())
    202  */
    203 #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_3_5_1670
    204 #define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_4_65_3281
    205 
    206 #ifndef TRUE
    207 #define TRUE 1
    208 #define FALSE 0
    209 #endif
     237#define CLIENTINFO_ICQ_5_45_3777 { \
     238        "ICQ Inc. - Product of ICQ (TM).2003a.5.45.1.3777.85", \
     239        0x010a, \
     240        0x0005, 0x002d, \
     241        0x0001, 0x0ec1, \
     242        0x00000055, \
     243        "us", "en", \
     244}
     245
     246#define CLIENTINFO_ICQBasic_14_3_1068 { \
     247        "ICQBasic", \
     248        0x010a, \
     249        0x0014, 0x0003, \
     250        0x0000, 0x042c, \
     251        0x0000043d, \
     252        "us", "en", \
     253}
     254
     255#define CLIENTINFO_Netscape_7_0_1 { \
     256        "Netscape 2000 an approved user of AOL Instant Messenger (SM)", \
     257        0x1d0d, \
     258        0x0007, 0x0000, \
     259        0x0001, 0x0000, \
     260        0x00000058, \
     261        "us", "en", \
     262}
     263
     264#define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036
     265#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_5_45_3777
    210266
    211267/*
    212268 * These could be arbitrary, but its easier to use the actual AIM values
    213269 */
    214 #define AIM_CONN_TYPE_AUTH          0x0007
    215 #define AIM_CONN_TYPE_ADS           0x0005
    216 #define AIM_CONN_TYPE_BOS           0x0002
    217 #define AIM_CONN_TYPE_CHAT          0x000e
    218 #define AIM_CONN_TYPE_CHATNAV       0x000d
    219 #define AIM_CONN_TYPE_SEARCH        0x000f
    220 #define AIM_CONN_TYPE_EMAIL         0x0018
    221 
    222 /* they start getting arbitrary in rendezvous stuff =) */
    223 #define AIM_CONN_TYPE_RENDEZVOUS    0x0101 /* these do not speak FLAP! */
    224 #define AIM_CONN_TYPE_RENDEZVOUS_OUT 0x0102 /* socket waiting for accept() */
     270#define AIM_CONN_TYPE_BOS               0x0002
     271#define AIM_CONN_TYPE_ADS               0x0005
     272#define AIM_CONN_TYPE_AUTH              0x0007
     273#define AIM_CONN_TYPE_CHATNAV           0x000d
     274#define AIM_CONN_TYPE_CHAT              0x000e
     275#define AIM_CONN_TYPE_SEARCH            0x000f
     276#define AIM_CONN_TYPE_ICON              0x0010
     277#define AIM_CONN_TYPE_EMAIL             0x0018
     278
     279/* they start getting arbitrary for rendezvous stuff =) */
     280#define AIM_CONN_TYPE_RENDEZVOUS        0xfffe /* these do not speak FLAP! */
     281#define AIM_CONN_TYPE_LISTENER          0xffff /* socket waiting for accept() */
    225282
    226283/*
    227284 * Subtypes, we need these for OFT stuff.
    228285 */
    229 #define AIM_CONN_SUBTYPE_OFT_DIRECTIM  0x0001
    230 #define AIM_CONN_SUBTYPE_OFT_GETFILE   0x0002
    231 #define AIM_CONN_SUBTYPE_OFT_SENDFILE  0x0003
    232 #define AIM_CONN_SUBTYPE_OFT_BUDDYICON 0x0004
    233 #define AIM_CONN_SUBTYPE_OFT_VOICE     0x0005
     286#define AIM_CONN_SUBTYPE_OFT_DIRECTIM   0x0001
     287#define AIM_CONN_SUBTYPE_OFT_GETFILE    0x0002
     288#define AIM_CONN_SUBTYPE_OFT_SENDFILE   0x0003
     289#define AIM_CONN_SUBTYPE_OFT_BUDDYICON  0x0004
     290#define AIM_CONN_SUBTYPE_OFT_VOICE      0x0005
    234291
    235292/*
    236293 * Status values returned from aim_conn_new().  ORed together.
    237294 */
    238 #define AIM_CONN_STATUS_READY       0x0001
    239 #define AIM_CONN_STATUS_INTERNALERR 0x0002
    240 #define AIM_CONN_STATUS_RESOLVERR   0x0040
    241 #define AIM_CONN_STATUS_CONNERR     0x0080
    242 #define AIM_CONN_STATUS_INPROGRESS  0x0100
    243 
    244 #define AIM_FRAMETYPE_FLAP 0x0000
    245 #define AIM_FRAMETYPE_OFT  0x0001
     295#define AIM_CONN_STATUS_READY           0x0001
     296#define AIM_CONN_STATUS_INTERNALERR     0x0002
     297#define AIM_CONN_STATUS_RESOLVERR       0x0040
     298#define AIM_CONN_STATUS_CONNERR         0x0080
     299#define AIM_CONN_STATUS_INPROGRESS      0x0100
     300
     301#define AIM_FRAMETYPE_FLAP              0x0000
     302#define AIM_FRAMETYPE_OFT               0x0001
    246303
    247304typedef struct aim_conn_s {
     
    289346                } flap;
    290347                struct {
    291                         fu8_t magic[4]; /* ODC2 OFT2 */
     348                        fu8_t magic[4]; /* ODC2 or OFT2 */
    292349                        fu16_t hdrlen;
    293350                        fu16_t type;
     
    297354        fu8_t handled;          /* 0 = new, !0 = been handled */
    298355        fu8_t nofree;           /* 0 = free data on purge, 1 = only unlink */
    299         aim_conn_t *conn;  /* the connection it came in on... */
     356        aim_conn_t *conn;       /* the connection it came in on... */
    300357        struct aim_frame_s *next;
    301358} aim_frame_t;
    302359
    303360typedef struct aim_msgcookie_s {
    304         unsigned char cookie[8];
     361        fu8_t cookie[8];
    305362        int type;
    306363        void *data;
     
    308365        struct aim_msgcookie_s *next;
    309366} aim_msgcookie_t;
     367
     368/* Values for sess->flags */
     369#define AIM_SESS_FLAGS_SNACLOGIN         0x00000001
     370#define AIM_SESS_FLAGS_XORLOGIN          0x00000002
     371#define AIM_SESS_FLAGS_NONBLOCKCONNECT   0x00000004
     372#define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008
    310373
    311374/*
     
    331394
    332395        /* ---- 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;
    345396
    346397        /* Connection information */
     
    368419        int (*tx_enqueue)(struct aim_session_s *, aim_frame_t *);
    369420
     421        void *modlistv;
     422
     423        struct {
     424                char server[128];
     425                char username[128];
     426                char password[128];
     427        } socksproxy;
     428
     429        fu32_t flags; /* AIM_SESS_FLAGS_ */
     430
     431        int debug;
     432        void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */
     433
    370434        /*
    371435         * Outstanding snac handling
     
    376440        aim_snacid_t snacid_next;
    377441
     442        aim_msgcookie_t *msgcookies;
     443        struct aim_icq_info *icq_info;
     444        struct aim_oft_info *oft_info;
     445        struct aim_authresp_info *authinfo;
     446        struct aim_emailinfo *emailinfo;
     447
     448        /* Server-stored information (ssi) */
    378449        struct {
    379                 char server[128];
    380                 char username[128];
    381                 char password[128];
    382         } socksproxy;
    383 
    384         fu32_t flags; /* AIM_SESS_FLAGS_ */
    385 
    386         int debug;
    387         void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */
    388 
    389         aim_msgcookie_t *msgcookies;
    390 
    391         void *modlistv;
     450                int received_data;
     451                fu16_t numitems;
     452                struct aim_ssi_item *official;
     453                struct aim_ssi_item *local;
     454                struct aim_ssi_tmp *pending;
     455                time_t timestamp;
     456                int waiting_for_ack;
     457        } ssi;
    392458} aim_session_t;
    393459
    394 /* Values for sess->flags */
    395 #define AIM_SESS_FLAGS_SNACLOGIN         0x00000001
    396 #define AIM_SESS_FLAGS_XORLOGIN          0x00000002
    397 #define AIM_SESS_FLAGS_NONBLOCKCONNECT   0x00000004
    398 #define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008
    399 
    400460/* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */
    401 #define AIM_ICQ_STATE_NORMAL    0x00000000
    402 #define AIM_ICQ_STATE_AWAY      0x00000001
    403 #define AIM_ICQ_STATE_DND       0x00000002
    404 #define AIM_ICQ_STATE_OUT       0x00000004
    405 #define AIM_ICQ_STATE_BUSY      0x00000010
    406 #define AIM_ICQ_STATE_CHAT      0x00000020
    407 #define AIM_ICQ_STATE_INVISIBLE 0x00000100
    408 #define AIM_ICQ_STATE_WEBAWARE  0x00010000
    409 
    410 /*
    411  * AIM User Info, Standard Form.
    412  */
    413 typedef struct {
    414         char sn[MAXSNLEN+1];
    415         fu16_t warnlevel; /* evil percent * 10 (999 = 99.9%) */
    416         fu16_t idletime; /* in seconds */
    417         fu16_t flags;
    418         fu32_t createtime; /* time_t */
    419         fu32_t membersince; /* time_t */
    420         fu32_t onlinesince; /* time_t */
    421         fu32_t sessionlen;  /* in seconds */
    422         fu32_t capabilities;
    423         struct {
    424                 fu32_t status;
    425                 fu32_t ipaddr;
    426                 fu8_t crap[0x25]; /* until we figure it out... */
    427         } icqinfo;
    428         fu32_t present;
    429 } aim_userinfo_t;
    430 
    431 #define AIM_USERINFO_PRESENT_FLAGS        0x00000001
    432 #define AIM_USERINFO_PRESENT_MEMBERSINCE  0x00000002
    433 #define AIM_USERINFO_PRESENT_ONLINESINCE  0x00000004
    434 #define AIM_USERINFO_PRESENT_IDLE         0x00000008
    435 #define AIM_USERINFO_PRESENT_ICQEXTSTATUS 0x00000010
    436 #define AIM_USERINFO_PRESENT_ICQIPADDR    0x00000020
    437 #define AIM_USERINFO_PRESENT_ICQDATA      0x00000040
    438 #define AIM_USERINFO_PRESENT_CAPABILITIES 0x00000080
    439 #define AIM_USERINFO_PRESENT_SESSIONLEN   0x00000100
    440 #define AIM_USERINFO_PRESENT_CREATETIME   0x00000200
    441 
    442 faim_export const char *aim_userinfo_sn(aim_userinfo_t *ui);
    443 faim_export fu16_t aim_userinfo_flags(aim_userinfo_t *ui);
    444 faim_export fu16_t aim_userinfo_idle(aim_userinfo_t *ui);
    445 faim_export float aim_userinfo_warnlevel(aim_userinfo_t *ui);
    446 faim_export time_t aim_userinfo_createtime(aim_userinfo_t *ui);
    447 faim_export time_t aim_userinfo_membersince(aim_userinfo_t *ui);
    448 faim_export time_t aim_userinfo_onlinesince(aim_userinfo_t *ui);
    449 faim_export fu32_t aim_userinfo_sessionlen(aim_userinfo_t *ui);
    450 faim_export int aim_userinfo_hascap(aim_userinfo_t *ui, fu32_t cap);
    451 
    452 #define AIM_FLAG_UNCONFIRMED    0x0001 /* "damned transients" */
    453 #define AIM_FLAG_ADMINISTRATOR  0x0002
    454 #define AIM_FLAG_AOL            0x0004
    455 #define AIM_FLAG_OSCAR_PAY      0x0008
    456 #define AIM_FLAG_FREE           0x0010
    457 #define AIM_FLAG_AWAY           0x0020
    458 #define AIM_FLAG_ICQ            0x0040
    459 #define AIM_FLAG_WIRELESS       0x0080
    460 #define AIM_FLAG_UNKNOWN100     0x0100
    461 #define AIM_FLAG_UNKNOWN200     0x0200
    462 #define AIM_FLAG_ACTIVEBUDDY    0x0400
    463 #define AIM_FLAG_UNKNOWN800     0x0800
    464 #define AIM_FLAG_ABINTERNAL     0x1000
    465 
    466 #define AIM_FLAG_ALLUSERS       0x001f
    467 
    468 
    469 #if defined(FAIM_INTERNAL) || defined(FAIM_NEED_TLV)
    470 /*
    471  * TLV handling
    472  */
    473 
    474 /* Generic TLV structure. */
    475 typedef struct aim_tlv_s {
    476         fu16_t type;
    477         fu16_t length;
    478         fu8_t *value;
    479 } aim_tlv_t;
    480 
    481 /* List of above. */
    482 typedef struct aim_tlvlist_s {
    483         aim_tlv_t *tlv;
    484         struct aim_tlvlist_s *next;
    485 } aim_tlvlist_t;
    486 
    487 /* TLV-handling functions */
    488 
    489 #if 0
    490 /* Very, very raw TLV handling. */
    491 faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v);
    492 faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v);
    493 faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v);
    494 faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v);
    495 #endif
    496 
    497 /* TLV list handling. */
    498 faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs);
    499 faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num);
    500 faim_internal void aim_freetlvchain(aim_tlvlist_t **list);
    501 faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n);
    502 faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n);
    503 faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num);
    504 faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n);
    505 faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n);
    506 faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list);
    507 faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v);
    508 faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v);
    509 faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v);
    510 faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v);
    511 faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu32_t caps);
    512 faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type);
    513 faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *ui);
    514 faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl);
    515 faim_internal int aim_counttlvchain(aim_tlvlist_t **list);
    516 faim_internal int aim_sizetlvchain(aim_tlvlist_t **list);
    517 #endif /* FAIM_INTERNAL */
     461#define AIM_ICQ_STATE_NORMAL            0x00000000
     462#define AIM_ICQ_STATE_AWAY              0x00000001
     463#define AIM_ICQ_STATE_DND               0x00000002
     464#define AIM_ICQ_STATE_OUT               0x00000004
     465#define AIM_ICQ_STATE_BUSY              0x00000010
     466#define AIM_ICQ_STATE_CHAT              0x00000020
     467#define AIM_ICQ_STATE_INVISIBLE         0x00000100
     468#define AIM_ICQ_STATE_WEBAWARE          0x00010000
     469#define AIM_ICQ_STATE_HIDEIP            0x00020000
     470#define AIM_ICQ_STATE_BIRTHDAY          0x00080000
     471#define AIM_ICQ_STATE_DIRECTDISABLED    0x00100000
     472#define AIM_ICQ_STATE_ICQHOMEPAGE       0x00200000
     473#define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000
     474#define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000
     475
    518476
    519477/*
     
    542500typedef int (*aim_rxcallback_t)(aim_session_t *, aim_frame_t *, ...);
    543501
     502
     503/* auth.c */
    544504struct aim_clientrelease {
    545505        char *name;
     
    556516        char *email;
    557517        char *bosip;
     518        fu16_t cookielen;
    558519        fu8_t *cookie;
    559520        char *chpassurl;
     
    566527        fu16_t group;
    567528        const char *ip;
     529        fu16_t cookielen;
    568530        const fu8_t *cookie;
    569531        struct { /* group == AIM_CONN_TYPE_CHAT */
     
    578540faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn);
    579541faim_export int aim_send_login(aim_session_t *, aim_conn_t *, const char *, const char *, struct client_info_s *, const char *key);
    580 faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest);
     542faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest);
    581543faim_export void aim_purge_rxqueue(aim_session_t *);
     544faim_export void aim_cleansnacs(aim_session_t *, int maxage);
    582545
    583546#define AIM_TX_QUEUED    0 /* default */
     
    591554faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval);
    592555
    593 faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags);
     556faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags);
    594557faim_export int aim_clearhandlers(aim_conn_t *conn);
    595558
     
    600563faim_export int aim_conngetmaxfd(aim_session_t *);
    601564faim_export aim_conn_t *aim_select(aim_session_t *, struct timeval *, int *);
     565faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn);
    602566faim_export int aim_conn_isready(aim_conn_t *);
    603567faim_export int aim_conn_setstatus(aim_conn_t *, int);
     
    607571typedef void (*faim_debugging_callback_t)(aim_session_t *sess, int level, const char *format, va_list va);
    608572faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t);
    609 faim_export void aim_session_init(aim_session_t *, unsigned long flags, int debuglevel);
     573faim_export void aim_session_init(aim_session_t *, fu32_t flags, int debuglevel);
    610574faim_export void aim_session_kill(aim_session_t *);
    611575faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password);
     
    614578faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd);
    615579
     580
     581
     582/* service.c */
     583faim_export int aim_srv_setavailmsg(aim_session_t *sess, char *msg);
     584
     585
     586
    616587/* misc.c */
    617588
     
    627598
    628599faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn);
    629 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags);
    630600faim_export int aim_nop(aim_session_t *, aim_conn_t *);
    631601faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn);
     
    633603faim_export int aim_bos_changevisibility(aim_session_t *, aim_conn_t *, int, const char *);
    634604faim_export int aim_bos_setbuddylist(aim_session_t *, aim_conn_t *, const char *);
    635 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps);
     605faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile_encoding, const char *profile, const int profile_len, const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len, fu32_t caps);
    636606faim_export int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, fu32_t mask);
    637607faim_export int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, fu32_t);
     
    643613faim_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);
    644614faim_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);
    645 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status);
    646 
    647 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *);
     615faim_export int aim_setextstatus(aim_session_t *sess, fu32_t status);
    648616
    649617#define AIM_CLIENTTYPE_UNKNOWN  0x0000
     
    652620#define AIM_CLIENTTYPE_WINAIM41 0x0003
    653621#define AIM_CLIENTTYPE_AOL_TOC  0x0004
    654 faim_export unsigned short aim_fingerprintclient(unsigned char *msghdr, int len);
     622faim_export fu16_t aim_im_fingerprint(const fu8_t *msghdr, int len);
    655623
    656624#define AIM_RATE_CODE_CHANGE     0x0001
     
    660628faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn);
    661629
     630
     631
    662632/* im.c */
    663 
    664 struct aim_fileheader_t {
    665 #if 0
    666         char  magic[4];         /* 0 */
    667         short hdrlen;           /* 4 */
    668         short hdrtype;          /* 6 */
    669 #endif
    670         char  bcookie[8];       /* 8 */
    671         short encrypt;          /* 16 */
    672         short compress;         /* 18 */
    673         short totfiles;         /* 20 */
    674         short filesleft;        /* 22 */
    675         short totparts;         /* 24 */
    676         short partsleft;        /* 26 */
    677         long  totsize;          /* 28 */
    678         long  size;             /* 32 */
    679         long  modtime;          /* 36 */
    680         long  checksum;         /* 40 */
    681         long  rfrcsum;          /* 44 */
    682         long  rfsize;           /* 48 */
    683         long  cretime;          /* 52 */
    684         long  rfcsum;           /* 56 */
    685         long  nrecvd;           /* 60 */
    686         long  recvcsum;         /* 64 */
    687         char  idstring[32];     /* 68 */
    688         char  flags;            /* 100 */
    689         char  lnameoffset;      /* 101 */
    690         char  lsizeoffset;      /* 102 */
    691         char  dummy[69];        /* 103 */
    692         char  macfileinfo[16];  /* 172 */
    693         short nencode;          /* 188 */
    694         short nlanguage;        /* 190 */
    695         char  name[64];         /* 192 */
    696                                 /* 256 */
    697 };
    698 
    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
     633#define AIM_OFT_SUBTYPE_SEND_FILE       0x0001
     634#define AIM_OFT_SUBTYPE_SEND_DIR        0x0002
     635#define AIM_OFT_SUBTYPE_GET_FILE        0x0011
     636#define AIM_OPT_SUBTYPE_GET_LIST        0x0012
     637
     638#define AIM_TRANSFER_DENY_NOTSUPPORTED  0x0000
     639#define AIM_TRANSFER_DENY_DECLINE       0x0001
     640#define AIM_TRANSFER_DENY_NOTACCEPTING  0x0002
     641
     642#define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED       0x00000001
     643#define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED    0x00000002
     644
     645/* This is what the server will give you if you don't set them yourself. */
     646#define AIM_IMPARAM_DEFAULTS { \
     647        0, \
     648        AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
     649        512, /* !! Note how small this is. */ \
     650        (99.9)*10, (99.9)*10, \
     651        1000 /* !! And how large this is. */ \
     652}
     653
     654/* This is what most AIM versions use. */
     655#define AIM_IMPARAM_REASONABLE { \
     656        0, \
     657        AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
     658        8000, \
     659        (99.9)*10, (99.9)*10, \
     660        0 \
     661}
     662
     663struct aim_icbmparameters {
     664        fu16_t maxchan;
     665        fu32_t flags; /* AIM_IMPARAM_FLAG_ */
     666        fu16_t maxmsglen; /* message size that you will accept */
     667        fu16_t maxsenderwarn; /* this and below are *10 (999=99.9%) */
     668        fu16_t maxrecverwarn;
     669        fu32_t minmsginterval; /* in milliseconds? */
     670};
    703671
    704672struct aim_chat_roominfo {
    705         unsigned short exchange;
     673        fu16_t exchange;
    706674        char *name;
    707         unsigned short instance;
     675        fu16_t instance;
    708676};
    709677
     
    717685#define AIM_IMFLAGS_CUSTOMFEATURES      0x0080 /* features field present */
    718686#define AIM_IMFLAGS_EXTDATA             0x0100
    719 #define AIM_IMFLAGS_CUSTOMCHARSET       0x0200 /* charset fields set */
     687#define AIM_IMFLAGS_X                   0x0200
    720688#define AIM_IMFLAGS_MULTIPART           0x0400 /* ->mpmsg section valid */
    721689#define AIM_IMFLAGS_OFFLINE             0x0800 /* send to offline user */
     
    829797
    830798/* Valid values for channel 2 args->status */
    831 #define AIM_RENDEZVOUS_PROPOSE 0x0000
    832 #define AIM_RENDEZVOUS_CANCEL  0x0001
    833 #define AIM_RENDEZVOUS_ACCEPT  0x0002
     799#define AIM_RENDEZVOUS_PROPOSE  0x0000
     800#define AIM_RENDEZVOUS_CANCEL   0x0001
     801#define AIM_RENDEZVOUS_ACCEPT   0x0002
    834802
    835803struct aim_incomingim_ch2_args {
     804        fu16_t status;
    836805        fu8_t cookie[8];
    837         fu16_t reqclass;
    838         fu16_t status;
    839         fu16_t errorcode;
     806        int reqclass;
     807        const char *proxyip;
    840808        const char *clientip;
    841         const char *clientip2;
    842809        const char *verifiedip;
    843810        fu16_t port;
     811        fu16_t errorcode;
    844812        const char *msg; /* invite message or file description */
    845813        const char *encoding;
     
    871839
    872840/* 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
     841#define AIM_ICQMSG_AUTHREQUEST  0x0006
     842#define AIM_ICQMSG_AUTHDENIED   0x0007
     843#define AIM_ICQMSG_AUTHGRANTED  0x0008
    876844
    877845struct aim_incomingim_ch4_args {
    878846        fu32_t uin; /* Of the sender of the ICBM */
    879         fu16_t type;
     847        fu8_t type;
     848        fu8_t flags;
    880849        char *msg; /* Reason for auth request, deny, or accept */
    881 };
    882 
    883 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args);
    884 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args);
    885 faim_export int aim_send_im(aim_session_t *, const char *destsn, unsigned short flags, const char *msg);
    886 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum);
    887 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen);
    888 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing);
    889 faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg, int len, int encoding);
    890 faim_export const char *aim_directim_getsn(aim_conn_t *conn);
    891 faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, const char *destsn);
    892 faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie);
    893 
    894 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type);
    895 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret);
    896 faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message);
    897 
    898 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2);
    899 
    900 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn);
    901 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size);
    902 faim_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);
    905 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn);
    906 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn);
     850        int msglen;
     851};
     852
     853/* SNAC sending functions */
     854/* 0x0002 */ faim_export int aim_im_setparams(aim_session_t *sess, struct aim_icbmparameters *params);
     855/* 0x0004 */ faim_export int aim_im_reqparams(aim_session_t *sess);
     856/* 0x0006 */ faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args);
     857/* 0x0006 */ faim_export int aim_im_sendch1(aim_session_t *, const char *destsn, fu16_t flags, const char *msg);
     858/* 0x0006 */ faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum);
     859/* 0x0006 */ faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args);
     860/* 0x0006 */ faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port);
     861/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info);
     862/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *info);
     863/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info);
     864/* 0x0006 */ faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type);
     865/* 0x0006 */ faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message);
     866/* 0x0008 */ faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags);
     867/* 0x000b */ faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code);
     868/* 0x0014 */ faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2);
     869
     870
     871
     872/* ft.c */
     873struct aim_fileheader_t {
     874#if 0
     875        char magic[4];          /* 0 */
     876        fu16_t hdrlen;          /* 4 */
     877        fu16_t hdrtype;         /* 6 */
     878#endif
     879        char bcookie[8];        /* 8 */
     880        fu16_t encrypt;         /* 16 */
     881        fu16_t compress;        /* 18 */
     882        fu16_t totfiles;        /* 20 */
     883        fu16_t filesleft;       /* 22 */
     884        fu16_t totparts;        /* 24 */
     885        fu16_t partsleft;       /* 26 */
     886        fu32_t totsize;         /* 28 */
     887        fu32_t size;            /* 32 */
     888        fu32_t modtime;         /* 36 */
     889        fu32_t checksum;        /* 40 */
     890        fu32_t rfrcsum;         /* 44 */
     891        fu32_t rfsize;          /* 48 */
     892        fu32_t cretime;         /* 52 */
     893        fu32_t rfcsum;          /* 56 */
     894        fu32_t nrecvd;          /* 60 */
     895        fu32_t recvcsum;        /* 64 */
     896        fu8_t idstring[32];     /* 68 */
     897        fu8_t flags;            /* 100 */
     898        fu8_t lnameoffset;      /* 101 */
     899        fu8_t lsizeoffset;      /* 102 */
     900        char dummy[69];         /* 103 */
     901        char macfileinfo[16];   /* 172 */
     902        fu16_t nencode;         /* 188 */
     903        fu16_t nlanguage;       /* 190 */
     904        char name[64];          /* 192 */
     905                                /* 256 */
     906};
     907
     908struct aim_oft_info {
     909        char cookie[8];
     910        char *sn;
     911        char *proxyip;
     912        char *clientip;
     913        char *verifiedip;
     914        fu16_t port;
     915        aim_conn_t *conn;
     916        aim_session_t *sess;
     917        struct aim_fileheader_t fh;
     918        struct aim_oft_info *next;
     919};
     920
     921faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck);
     922faim_export fu32_t aim_oft_checksum_file(char *filename);
     923faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur);
     924faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing);
     925faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg);
     926faim_export const char *aim_odc_getsn(aim_conn_t *conn);
     927faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn);
     928faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn);
     929faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie);
     930
     931faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename);
     932faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info);
     933faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info);
     934faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info);
     935
     936
    907937
    908938/* info.c */
    909 #define AIM_CAPS_BUDDYICON      0x00000001
    910 #define AIM_CAPS_VOICE          0x00000002
    911 #define AIM_CAPS_IMIMAGE        0x00000004
    912 #define AIM_CAPS_CHAT           0x00000008
    913 #define AIM_CAPS_GETFILE        0x00000010
    914 #define AIM_CAPS_SENDFILE       0x00000020
    915 #define AIM_CAPS_GAMES          0x00000040
    916 #define AIM_CAPS_SAVESTOCKS     0x00000080
    917 #define AIM_CAPS_SENDBUDDYLIST  0x00000100
    918 #define AIM_CAPS_GAMES2         0x00000200
    919 #define AIM_CAPS_ICQ            0x00000400
    920 #define AIM_CAPS_APINFO         0x00000800
     939/*
     940 * AIM User Info, Standard Form.
     941 */
     942#define AIM_FLAG_UNCONFIRMED    0x0001 /* "damned transients" */
     943#define AIM_FLAG_ADMINISTRATOR  0x0002
     944#define AIM_FLAG_AOL            0x0004
     945#define AIM_FLAG_OSCAR_PAY      0x0008
     946#define AIM_FLAG_FREE           0x0010
     947#define AIM_FLAG_AWAY           0x0020
     948#define AIM_FLAG_ICQ            0x0040
     949#define AIM_FLAG_WIRELESS       0x0080
     950#define AIM_FLAG_UNKNOWN100     0x0100
     951#define AIM_FLAG_UNKNOWN200     0x0200
     952#define AIM_FLAG_ACTIVEBUDDY    0x0400
     953#define AIM_FLAG_UNKNOWN800     0x0800
     954#define AIM_FLAG_ABINTERNAL     0x1000
     955#define AIM_FLAG_ALLUSERS       0x001f
     956
     957#define AIM_USERINFO_PRESENT_FLAGS        0x00000001
     958#define AIM_USERINFO_PRESENT_MEMBERSINCE  0x00000002
     959#define AIM_USERINFO_PRESENT_ONLINESINCE  0x00000004
     960#define AIM_USERINFO_PRESENT_IDLE         0x00000008
     961#define AIM_USERINFO_PRESENT_ICQEXTSTATUS 0x00000010
     962#define AIM_USERINFO_PRESENT_ICQIPADDR    0x00000020
     963#define AIM_USERINFO_PRESENT_ICQDATA      0x00000040
     964#define AIM_USERINFO_PRESENT_CAPABILITIES 0x00000080
     965#define AIM_USERINFO_PRESENT_SESSIONLEN   0x00000100
     966#define AIM_USERINFO_PRESENT_CREATETIME   0x00000200
     967
     968typedef struct {
     969        char sn[MAXSNLEN+1];
     970        fu16_t warnlevel; /* evil percent * 10 (999 = 99.9%) */
     971        fu16_t idletime; /* in seconds */
     972        fu16_t flags;
     973        fu32_t createtime; /* time_t */
     974        fu32_t membersince; /* time_t */
     975        fu32_t onlinesince; /* time_t */
     976        fu32_t sessionlen;  /* in seconds */
     977        fu32_t capabilities;
     978        struct {
     979                fu32_t status;
     980                fu32_t ipaddr;
     981                fu8_t crap[0x25]; /* until we figure it out... */
     982        } icqinfo;
     983        fu32_t present;
     984        fu16_t iconcsumlen;
     985        fu8_t *iconcsum;
     986        char *availmsg_encoding;
     987        char *availmsg;
     988        int availmsg_len;
     989} aim_userinfo_t;
     990
     991faim_export const char *aim_userinfo_sn(aim_userinfo_t *ui);
     992faim_export fu16_t aim_userinfo_flags(aim_userinfo_t *ui);
     993faim_export fu16_t aim_userinfo_idle(aim_userinfo_t *ui);
     994faim_export float aim_userinfo_warnlevel(aim_userinfo_t *ui);
     995faim_export time_t aim_userinfo_createtime(aim_userinfo_t *ui);
     996faim_export time_t aim_userinfo_membersince(aim_userinfo_t *ui);
     997faim_export time_t aim_userinfo_onlinesince(aim_userinfo_t *ui);
     998faim_export fu32_t aim_userinfo_sessionlen(aim_userinfo_t *ui);
     999faim_export int aim_userinfo_hascap(aim_userinfo_t *ui, fu32_t cap);
     1000
     1001#define AIM_CAPS_BUDDYICON      0x00000001
     1002#define AIM_CAPS_VOICE          0x00000002
     1003#define AIM_CAPS_DIRECTIM       0x00000004
     1004#define AIM_CAPS_CHAT           0x00000008
     1005#define AIM_CAPS_GETFILE        0x00000010
     1006#define AIM_CAPS_SENDFILE       0x00000020
     1007#define AIM_CAPS_GAMES          0x00000040
     1008#define AIM_CAPS_SAVESTOCKS     0x00000080
     1009#define AIM_CAPS_SENDBUDDYLIST  0x00000100
     1010#define AIM_CAPS_GAMES2         0x00000200
     1011#define AIM_CAPS_ICQ            0x00000400
     1012#define AIM_CAPS_APINFO         0x00000800
    9211013#define AIM_CAPS_ICQRTF         0x00001000
    9221014#define AIM_CAPS_EMPTY          0x00002000
    923 #define AIM_CAPS_ICQSERVERRELAY 0x00004000
    924 #define AIM_CAPS_ICQUNKNOWN     0x00008000
    925 #define AIM_CAPS_TRILLIANCRYPT  0x00010000
    926 #define AIM_CAPS_LAST           0x00020000
     1015#define AIM_CAPS_ICQSERVERRELAY 0x00004000
     1016#define AIM_CAPS_ICQUTF8OLD     0x00008000
     1017#define AIM_CAPS_TRILLIANCRYPT  0x00010000
     1018#define AIM_CAPS_ICQUTF8        0x00020000
     1019#define AIM_CAPS_INTEROPERATE   0x00040000
     1020#define AIM_CAPS_ICHAT          0x00080000
     1021#define AIM_CAPS_HIPTOP         0x00100000
     1022#define AIM_CAPS_SECUREIM       0x00200000
     1023#define AIM_CAPS_LAST           0x00400000
    9271024
    9281025faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn);
     
    9311028#define AIM_SENDMEMBLOCK_FLAG_ISHASH     1
    9321029
    933 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag);
     1030faim_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);
    9341031
    9351032#define AIM_GETINFO_GENERALINFO 0x00001
     
    9611058#define AIM_COOKIETYPE_OFTICON  0x15
    9621059
    963 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur);
    964 
    965 #define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000
    966 #define AIM_TRANSFER_DENY_DECLINE 0x0001
    967 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
    968 faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, unsigned short code);
    969 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 port, fu16_t rendid, ...);
    970 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
    971                                 const char *cookie, const char *sn, int rendid);
    972 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
    973                                 const unsigned char *buffer, int bufferlen);
    974 
    975 faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short);
    976 faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info);
    977 faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn);
    978 
    979 #define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED       0x00000001
    980 #define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED    0x00000002
    981 
    982 /* This is what the server will give you if you don't set them yourself. */
    983 #define AIM_IMPARAM_DEFAULTS { \
    984         0, \
    985         AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
    986         512, /* !! Note how small this is. */ \
    987         (99.9)*10, (99.9)*10, \
    988         1000 /* !! And how large this is. */ \
    989 }
    990 
    991 /* This is what most AIM versions use. */
    992 #define AIM_IMPARAM_REASONABLE { \
    993         0, \
    994         AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
    995         8000, \
    996         (99.9)*10, (99.9)*10, \
    997         0 \
    998 }
    999 
    1000 
    1001 struct aim_icbmparameters {
    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? */
    1008 };
    1009 
    1010 faim_export int aim_reqicbmparams(aim_session_t *sess);
    1011 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params);
    1012 
    1013 
    1014 /* auth.c */
    1015 faim_export int aim_sendcookie(aim_session_t *, aim_conn_t *, const fu8_t *);
    1016 
    1017 faim_export int aim_admin_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw);
    1018 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn);
    1019 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info);
    1020 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail);
    1021 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick);
    1022 
    1023 /* buddylist.c */
    1024 faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *);
    1025 faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *);
    1026 
    1027 /* search.c */
    1028 faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *);
    1029 
    1030 /* newsearch.c */
    1031 struct aim_usersearch {
     1060/* 0x0005 */ faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, fu16_t);
     1061
     1062
     1063
     1064/* 0x0003 - buddylist.c */
     1065/* 0x0004 */ faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *);
     1066/* 0x0005 */ faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *);
     1067/* 0x000b */ faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info);
     1068/* 0x000c */ faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn);
     1069
     1070
     1071
     1072/* 0x000a - search.c */
     1073faim_export int aim_search_address(aim_session_t *, aim_conn_t *, const char *);
     1074
     1075
     1076
     1077/* 0x000d - chatnav.c */
     1078/* 0x000e - chat.c */
     1079/* These apply to exchanges as well. */
     1080#define AIM_CHATROOM_FLAG_EVILABLE 0x0001
     1081#define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
     1082#define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004
     1083#define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008
     1084
     1085struct aim_chat_exchangeinfo {
     1086        fu16_t number;
     1087        fu16_t flags;
     1088        char *name;
     1089        char *charset1;
     1090        char *lang1;
     1091        char *charset2;
     1092        char *lang2;
     1093};
     1094
     1095#define AIM_CHATFLAGS_NOREFLECT 0x0001
     1096#define AIM_CHATFLAGS_AWAY      0x0002
     1097faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen);
     1098faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance);
     1099faim_export int aim_chat_attachname(aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance);
     1100faim_export char *aim_chat_getname(aim_conn_t *conn);
     1101faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name);
     1102
     1103faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn);
     1104
     1105faim_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);
     1106
     1107faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange);
     1108faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name);
     1109
     1110
     1111
     1112/* 0x000f - odir.c */
     1113struct aim_odir {
    10321114        char *first;
    10331115        char *last;
     
    10441126        char *region;
    10451127        char *address;
    1046         struct aim_usersearch *next;
    1047 };
    1048 
    1049 faim_export int aim_usersearch_email(aim_session_t *, const char *, const char *);
    1050 faim_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 *);
    1051 faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *);
    1052 
    1053 
    1054 /* These apply to exchanges as well. */
    1055 #define AIM_CHATROOM_FLAG_EVILABLE 0x0001
    1056 #define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
    1057 #define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004
    1058 #define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008
    1059 
    1060 struct aim_chat_exchangeinfo {
    1061         fu16_t number;
    1062         fu16_t flags;
    1063         char *name;
    1064         char *charset1;
    1065         char *lang1;
    1066         char *charset2;
    1067         char *lang2;
    1068 };
    1069 
    1070 #define AIM_CHATFLAGS_NOREFLECT 0x0001
    1071 #define AIM_CHATFLAGS_AWAY      0x0002
    1072 faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen);
    1073 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance);
    1074 faim_export int aim_chat_attachname(aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance);
    1075 faim_export char *aim_chat_getname(aim_conn_t *conn);
    1076 faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name);
    1077 
    1078 faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn);
    1079 
    1080 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);
    1081 
    1082 faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange);
    1083 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name);
    1084 
    1085 
    1086 #define AIM_SSI_TYPE_BUDDY         0x0000
    1087 #define AIM_SSI_TYPE_GROUP         0x0001
    1088 #define AIM_SSI_TYPE_PERMIT        0x0002
    1089 #define AIM_SSI_TYPE_DENY          0x0003
    1090 #define AIM_SSI_TYPE_PDINFO        0x0004
    1091 #define AIM_SSI_TYPE_PRESENCEPREFS 0x0005
     1128        struct aim_odir *next;
     1129};
     1130
     1131faim_export int aim_odir_email(aim_session_t *, const char *, const char *);
     1132faim_export int aim_odir_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 *);
     1133faim_export int aim_odir_interest(aim_session_t *, const char *, const char *);
     1134
     1135
     1136
     1137/* 0x0010 - icon.c */
     1138faim_export int aim_bart_upload(aim_session_t *sess, const fu8_t *icon, fu16_t iconlen);
     1139faim_export int aim_bart_request(aim_session_t *sess, const char *sn, const fu8_t *iconstr, fu16_t iconstrlen);
     1140
     1141
     1142
     1143/* 0x0013 - ssi.c */
     1144#define AIM_SSI_TYPE_BUDDY              0x0000
     1145#define AIM_SSI_TYPE_GROUP              0x0001
     1146#define AIM_SSI_TYPE_PERMIT             0x0002
     1147#define AIM_SSI_TYPE_DENY               0x0003
     1148#define AIM_SSI_TYPE_PDINFO             0x0004
     1149#define AIM_SSI_TYPE_PRESENCEPREFS      0x0005
     1150#define AIM_SSI_TYPE_ICONINFO           0x0014
     1151
     1152#define AIM_SSI_ACK_SUCCESS             0x0000
     1153#define AIM_SSI_ACK_ITEMNOTFOUND        0x0002
     1154#define AIM_SSI_ACK_IDNUMINUSE          0x000a
     1155#define AIM_SSI_ACK_ATMAX               0x000c
     1156#define AIM_SSI_ACK_INVALIDNAME         0x000d
     1157#define AIM_SSI_ACK_AUTHREQUIRED        0x000e
    10921158
    10931159struct aim_ssi_item {
     
    10961162        fu16_t bid;
    10971163        fu16_t type;
    1098         void *data;
     1164        struct aim_tlvlist_s *data;
    10991165        struct aim_ssi_item *next;
    11001166};
    11011167
     1168struct aim_ssi_tmp {
     1169        fu16_t action;
     1170        fu16_t ack;
     1171        char *name;
     1172        struct aim_ssi_item *item;
     1173        struct aim_ssi_tmp *next;
     1174};
     1175
    11021176/* These build the actual SNACs and queue them to be sent */
    1103 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn);
    1104 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev);
    1105 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn);
    1106 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype);
    1107 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn);
    1108 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn);
    1109 
    1110 /* These handle the local variables */
     1177/* 0x0002 */ faim_export int aim_ssi_reqrights(aim_session_t *sess);
     1178/* 0x0004 */ faim_export int aim_ssi_reqdata(aim_session_t *sess);
     1179/* 0x0005 */ faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t localstamp, fu16_t localrev);
     1180/* 0x0007 */ faim_export int aim_ssi_enable(aim_session_t *sess);
     1181/* 0x0008 */ faim_export int aim_ssi_addmoddel(aim_session_t *sess);
     1182/* 0x0011 */ faim_export int aim_ssi_modbegin(aim_session_t *sess);
     1183/* 0x0012 */ faim_export int aim_ssi_modend(aim_session_t *sess);
     1184/* 0x0014 */ faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg);
     1185/* 0x0018 */ faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg);
     1186/* 0x001a */ faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg);
     1187
     1188/* Client functions for retrieving SSI data */
    11111189faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid);
    11121190faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type);
    1113 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn);
     1191faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn);
     1192faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn);
    11141193faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list);
    11151194faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list);
    1116 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn);
    1117 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num);
    1118 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn);
    1119 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num);
    1120 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type);
    1121 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn);
    1122 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn);
    1123 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num);
    1124 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn);
    1125 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num);
    1126 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn);
    1127 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type);
    1128 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask);
    1129 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence);
     1195faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn);
     1196faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn);
     1197
     1198/* Client functions for changing SSI data */
     1199faim_export int aim_ssi_addbuddy(aim_session_t *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth);
     1200faim_export int aim_ssi_addpermit(aim_session_t *sess, const char *name);
     1201faim_export int aim_ssi_adddeny(aim_session_t *sess, const char *name);
     1202faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group);
     1203faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name);
     1204faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name);
     1205faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn);
     1206faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias);
     1207faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn);
     1208faim_export int aim_ssi_cleanlist(aim_session_t *sess);
     1209faim_export int aim_ssi_deletelist(aim_session_t *sess);
     1210faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask);
     1211faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence);
     1212faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen);
     1213
     1214
     1215
     1216/* 0x0015 - icq.c */
     1217#define AIM_ICQ_INFO_SIMPLE     0x001
     1218#define AIM_ICQ_INFO_SUMMARY    0x002
     1219#define AIM_ICQ_INFO_EMAIL      0x004
     1220#define AIM_ICQ_INFO_PERSONAL   0x008
     1221#define AIM_ICQ_INFO_ADDITIONAL 0x010
     1222#define AIM_ICQ_INFO_WORK       0x020
     1223#define AIM_ICQ_INFO_INTERESTS  0x040
     1224#define AIM_ICQ_INFO_ORGS       0x080
     1225#define AIM_ICQ_INFO_UNKNOWN    0x100
     1226#define AIM_ICQ_INFO_HAVEALL    0x1ff
    11301227
    11311228struct aim_icq_offlinemsg {
     
    11331230        fu16_t year;
    11341231        fu8_t month, day, hour, minute;
    1135         fu16_t type;
     1232        fu8_t type;
     1233        fu8_t flags;
    11361234        char *msg;
    1137 };
    1138 
    1139 struct aim_icq_simpleinfo {
     1235        int msglen;
     1236};
     1237
     1238struct aim_icq_info {
     1239        fu16_t reqid;
     1240
     1241        /* simple */
    11401242        fu32_t uin;
     1243
     1244        /* general and "home" information (0x00c8) */
    11411245        char *nick;
    11421246        char *first;
    11431247        char *last;
    11441248        char *email;
     1249        char *homecity;
     1250        char *homestate;
     1251        char *homephone;
     1252        char *homefax;
     1253        char *homeaddr;
     1254        char *mobile;
     1255        char *homezip;
     1256        fu16_t homecountry;
     1257/*      fu8_t timezone;
     1258        fu8_t hideemail; */
     1259
     1260        /* personal (0x00dc) */
     1261        fu8_t age;
     1262        fu8_t unknown;
     1263        fu8_t gender;
     1264        char *personalwebpage;
     1265        fu16_t birthyear;
     1266        fu8_t birthmonth;
     1267        fu8_t birthday;
     1268        fu8_t language1;
     1269        fu8_t language2;
     1270        fu8_t language3;
     1271
     1272        /* work (0x00d2) */
     1273        char *workcity;
     1274        char *workstate;
     1275        char *workphone;
     1276        char *workfax;
     1277        char *workaddr;
     1278        char *workzip;
     1279        fu16_t workcountry;
     1280        char *workcompany;
     1281        char *workdivision;
     1282        char *workposition;
     1283        char *workwebpage;
     1284
     1285        /* additional personal information (0x00e6) */
     1286        char *info;
     1287
     1288        /* email (0x00eb) */
     1289        fu16_t numaddresses;
     1290        char **email2;
     1291
     1292        /* we keep track of these in a linked list because we're 1337 */
     1293        struct aim_icq_info *next;
    11451294};
    11461295
    11471296faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess);
    11481297faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess);
     1298faim_export int aim_icq_hideip(aim_session_t *sess);
     1299faim_export int aim_icq_changepasswd(aim_session_t *sess, const char *passwd);
    11491300faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin);
    1150 
    1151 /* email.c */
     1301faim_export int aim_icq_getalias(aim_session_t *sess, const char *uin);
     1302faim_export int aim_icq_getallinfo(aim_session_t *sess, const char *uin);
     1303
     1304
     1305
     1306/* 0x0017 - auth.c */
     1307faim_export int aim_sendcookie(aim_session_t *, aim_conn_t *, const fu16_t length, const fu8_t *);
     1308faim_export int aim_admin_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw);
     1309faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn);
     1310faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info);
     1311faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail);
     1312faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick);
     1313
     1314
     1315
     1316/* 0x0018 - email.c */
    11521317struct aim_emailinfo {
    11531318        fu8_t *cookie16;
     
    11641329faim_export int aim_email_activate(aim_session_t *sess, aim_conn_t *conn);
    11651330
     1331
     1332
     1333/* tlv.c - TLV handling */
     1334#if defined(FAIM_INTERNAL) || defined(FAIM_NEED_TLV)
     1335/* Generic TLV structure. */
     1336typedef struct aim_tlv_s {
     1337        fu16_t type;
     1338        fu16_t length;
     1339        fu8_t *value;
     1340} aim_tlv_t;
     1341
     1342/* List of above. */
     1343typedef struct aim_tlvlist_s {
     1344        aim_tlv_t *tlv;
     1345        struct aim_tlvlist_s *next;
     1346} aim_tlvlist_t;
     1347
     1348/* TLV-handling functions */
     1349
     1350#if 0
     1351/* Very, very raw TLV handling. */
     1352faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v);
     1353faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v);
     1354faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v);
     1355faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v);
     1356#endif
     1357
     1358/* TLV list handling. */
     1359faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs);
     1360faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num);
     1361faim_internal aim_tlvlist_t *aim_readtlvchain_len(aim_bstream_t *bs, fu16_t len);
     1362faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig);
     1363faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two);
     1364faim_internal void aim_freetlvchain(aim_tlvlist_t **list);
     1365faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n);
     1366faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n);
     1367faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num);
     1368faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n);
     1369faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n);
     1370faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list);
     1371faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v);
     1372faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v);
     1373faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v);
     1374faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v);
     1375faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu32_t caps);
     1376faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type);
     1377faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *ui);
     1378faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl);
     1379faim_internal int aim_counttlvchain(aim_tlvlist_t **list);
     1380faim_internal int aim_sizetlvchain(aim_tlvlist_t **list);
     1381#endif /* FAIM_INTERNAL */
     1382
     1383
     1384
    11661385/* util.c */
    11671386/*
     
    11721391 *
    11731392 */
    1174 #define aimutil_put8(buf, data) ((*(buf) = (u_char)(data)&0xff),1)
     1393#define aimutil_put8(buf, data) ((*(buf) = (fu8_t)(data)&0xff),1)
    11751394#define aimutil_get8(buf) ((*(buf))&0xff)
    11761395#define aimutil_put16(buf, data) ( \
    1177                 (*(buf) = (u_char)((data)>>8)&0xff), \
    1178                 (*((buf)+1) = (u_char)(data)&0xff),  \
     1396                (*(buf) = (fu8_t)((data)>>8)&0xff), \
     1397                (*((buf)+1) = (fu8_t)(data)&0xff),  \
    11791398                2)
    11801399#define aimutil_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
    11811400#define aimutil_put32(buf, data) ( \
    1182                 (*((buf)) = (u_char)((data)>>24)&0xff), \
    1183                 (*((buf)+1) = (u_char)((data)>>16)&0xff), \
    1184                 (*((buf)+2) = (u_char)((data)>>8)&0xff), \
    1185                 (*((buf)+3) = (u_char)(data)&0xff), \
     1401                (*((buf)) = (fu8_t)((data)>>24)&0xff), \
     1402                (*((buf)+1) = (fu8_t)((data)>>16)&0xff), \
     1403                (*((buf)+2) = (fu8_t)((data)>>8)&0xff), \
     1404                (*((buf)+3) = (fu8_t)(data)&0xff), \
    11861405                4)
    11871406#define aimutil_get32(buf) ((((*(buf))<<24)&0xff000000) + \
     
    11921411/* Little-endian versions (damn ICQ) */
    11931412#define aimutil_putle8(buf, data) ( \
    1194                 (*(buf) = (unsigned char)(data) & 0xff), \
     1413                (*(buf) = (fu8_t)(data) & 0xff), \
    11951414                1)
    11961415#define aimutil_getle8(buf) ( \
     
    11981417                )
    11991418#define aimutil_putle16(buf, data) ( \
    1200                 (*((buf)+0) = (unsigned char)((data) >> 0) & 0xff),  \
    1201                 (*((buf)+1) = (unsigned char)((data) >> 8) & 0xff), \
     1419                (*((buf)+0) = (fu8_t)((data) >> 0) & 0xff),  \
     1420                (*((buf)+1) = (fu8_t)((data) >> 8) & 0xff), \
    12021421                2)
    12031422#define aimutil_getle16(buf) ( \
     
    12061425                )
    12071426#define aimutil_putle32(buf, data) ( \
    1208                 (*((buf)+0) = (unsigned char)((data) >>  0) & 0xff), \
    1209                 (*((buf)+1) = (unsigned char)((data) >>  8) & 0xff), \
    1210                 (*((buf)+2) = (unsigned char)((data) >> 16) & 0xff), \
    1211                 (*((buf)+3) = (unsigned char)((data) >> 24) & 0xff), \
     1427                (*((buf)+0) = (fu8_t)((data) >>  0) & 0xff), \
     1428                (*((buf)+1) = (fu8_t)((data) >>  8) & 0xff), \
     1429                (*((buf)+2) = (fu8_t)((data) >> 16) & 0xff), \
     1430                (*((buf)+3) = (fu8_t)((data) >> 24) & 0xff), \
    12121431                4)
    12131432#define aimutil_getle32(buf) ( \
     
    12181437
    12191438
    1220 faim_export int aimutil_putstr(u_char *, const char *, int);
    1221 faim_export int aimutil_tokslen(char *toSearch, int index, char dl);
     1439faim_export int aimutil_putstr(char *, const char *, int);
     1440faim_export fu16_t aimutil_iconsum(const fu8_t *buf, int buflen);
     1441faim_export int aim_util_getlocalip(fu8_t *ip);
     1442faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl);
    12221443faim_export int aimutil_itemcnt(char *toSearch, char dl);
    1223 faim_export char *aimutil_itemidx(char *toSearch, int index, char dl);
     1444faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl);
    12241445
    12251446faim_export int aim_snlen(const char *sn);
    12261447faim_export int aim_sncmp(const char *sn1, const char *sn2);
    12271448
    1228 /* for libc's that dont have it */
    1229 faim_export char *aim_strsep(char **pp, const char *delim);
    1230 
    1231 /* meta.c */
    1232 faim_export char *aim_getbuilddate(void);
    1233 faim_export char *aim_getbuildtime(void);
    1234 faim_export int aim_getbuildstring(char *buf, int buflen);
    1235 
    12361449#include <aim_internal.h>
    12371450
     1451#ifdef __cplusplus
     1452}
     1453#endif
     1454
    12381455#endif /* __AIM_H__ */
    1239 
  • libfaim/aim_cbtypes.h

    r862371b re374dee  
    2525#define AIM_CB_FAM_CHT 0x000e /* Chat */
    2626#define AIM_CB_FAM_SCH 0x000f /* "New" search */
     27#define AIM_CB_FAM_ICO 0x0010 /* Used for uploading buddy icons */
    2728#define AIM_CB_FAM_SSI 0x0013 /* Server stored information */
    2829#define AIM_CB_FAM_ICQ 0x0015
     
    179180/*
    180181 * SNAC Family: "New" Search
    181  *
    182  * Most of these are actually special.
    183182 */
    184183#define AIM_CB_SCH_ERROR 0x0001
     
    187186
    188187/*
     188 * SNAC Family: Buddy icons
     189 */
     190#define AIM_CB_ICO_ERROR 0x0001
     191#define AIM_CB_ICO_REQUEST 0x0004
     192#define AIM_CB_ICO_RESPONSE 0x0005
     193
     194/*
    189195 * SNAC Family: ICQ
    190196 *
     
    194200#define AIM_CB_ICQ_OFFLINEMSG 0x00f0
    195201#define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1
    196 #define AIM_CB_ICQ_SIMPLEINFO 0x00f2
     202#define AIM_CB_ICQ_INFO 0x00f2
     203#define AIM_CB_ICQ_ALIAS 0x00f3
    197204#define AIM_CB_ICQ_DEFAULT 0xffff
    198205
     
    203210#define AIM_CB_SSI_REQRIGHTS 0x0002
    204211#define AIM_CB_SSI_RIGHTSINFO 0x0003
    205 #define AIM_CB_SSI_REQLIST 0x0005
     212#define AIM_CB_SSI_REQDATA 0x0004
     213#define AIM_CB_SSI_REQIFCHANGED 0x0005
    206214#define AIM_CB_SSI_LIST 0x0006
    207215#define AIM_CB_SSI_ACTIVATE 0x0007
     
    213221#define AIM_CB_SSI_EDITSTART 0x0011
    214222#define AIM_CB_SSI_EDITSTOP 0x0012
     223#define AIM_CB_SSI_SENDAUTH 0x0014
     224#define AIM_CB_SSI_RECVAUTH 0x0015
     225#define AIM_CB_SSI_SENDAUTHREQ 0x0018
     226#define AIM_CB_SSI_RECVAUTHREQ 0x0019
     227#define AIM_CB_SSI_SENDAUTHREP 0x001a
     228#define AIM_CB_SSI_RECVAUTHREP 0x001b
     229#define AIM_CB_SSI_ADDED 0x001c
    215230
    216231/*
     
    241256 * OFT Services
    242257 *
    243  * See non-SNAC note below.
    244  */
    245 #define AIM_CB_OFT_DIRECTIMCONNECTREQ 0x0001/* connect request -- actually an OSCAR CAP*/
     258 * For all of the above #defines, the number is the subtype
     259 * of the SNAC.  For OFT #defines, the number is the
     260 * "hdrtype" which comes after the magic string and OFT
     261 * packet length.
     262 *
     263 * I'm pretty sure the ODC ones are arbitrary right now,
     264 * that should be changed.
     265 */
     266#define AIM_CB_OFT_DIRECTIMCONNECTREQ 0x0001    /* connect request -- actually an OSCAR CAP */
    246267#define AIM_CB_OFT_DIRECTIMINCOMING 0x0002
    247268#define AIM_CB_OFT_DIRECTIMDISCONNECT 0x0003
    248269#define AIM_CB_OFT_DIRECTIMTYPING 0x0004
    249 #define AIM_CB_OFT_DIRECTIMINITIATE 0x0005
    250 
    251 /* had been removed, put back by kretch */
    252 #define AIM_CB_OFT_GETFILECONNECTREQ 0x0006 /* connect request -- actually an OSCAR CAP*/
    253 #define AIM_CB_OFT_GETFILELISTINGREQ 0x0007 /* OFT listing.txt request */
    254 #define AIM_CB_OFT_GETFILEFILEREQ 0x0008    /* received file request */
    255 #define AIM_CB_OFT_GETFILEFILESEND 0x0009   /* received file request confirm -- send data */
    256 #define AIM_CB_OFT_GETFILECOMPLETE 0x000a   /* received file send complete*/
    257 #define AIM_CB_OFT_GETFILEINITIATE 0x000b   /* request for file get acknowledge */
    258 #define AIM_CB_OFT_GETFILEDISCONNECT 0x000c   /* OFT connection disconnected.*/
    259 #define AIM_CB_OFT_GETFILELISTING 0x000d   /* OFT listing.txt received.*/
    260 #define AIM_CB_OFT_GETFILERECEIVE 0x000e   /* OFT file incoming.*/
    261 #define AIM_CB_OFT_GETFILELISTINGRXCONFIRM 0x000f
    262 #define AIM_CB_OFT_GETFILESTATE4 0x0010
    263 
    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 */
    268 
     270#define AIM_CB_OFT_DIRECTIM_ESTABLISHED 0x0005
     271
     272#define AIM_CB_OFT_PROMPT 0x0101                /* "I am going to send you this file, is that ok?" */
     273#define AIM_CB_OFT_RESUMESOMETHING 0x0106       /* I really don't know */
     274#define AIM_CB_OFT_ACK 0x0202                   /* "Yes, it is ok for you to send me that file" */
     275#define AIM_CB_OFT_DONE 0x0204                  /* "I received that file with no problems, thanks a bunch" */
     276#define AIM_CB_OFT_RESUME 0x0205                /* Resume transferring, sent by whoever paused? */
     277#define AIM_CB_OFT_RESUMEACK 0x0207             /* Not really sure */
     278
     279#define AIM_CB_OFT_GETFILE_REQUESTLISTING 0x1108 /* "I have a listing.txt file, do you want it?" */
     280#define AIM_CB_OFT_GETFILE_RECEIVELISTING 0x1209 /* "Yes, please send me your listing.txt file" */
     281#define AIM_CB_OFT_GETFILE_RECEIVEDLISTING 0x120a /* received corrupt listing.txt file? */ /* I'm just guessing about this one... */
     282#define AIM_CB_OFT_GETFILE_ACKLISTING 0x120b    /* "I received the listing.txt file successfully" */
     283#define AIM_CB_OFT_GETFILE_REQUESTFILE 0x120c   /* "Please send me this file" */
     284
     285#define AIM_CB_OFT_ESTABLISHED 0xFFFF           /* connection to buddy initiated */
    269286
    270287/*
     
    282299#define AIM_CB_SPECIAL_FLAPVER 0x0005
    283300#define AIM_CB_SPECIAL_CONNINITDONE 0x0006
    284 #define AIM_CB_SPECIAL_IMAGETRANSFER 0x007
    285 #define AIM_CB_SPECIAL_MSGTIMEOUT 0x008
     301#define AIM_CB_SPECIAL_IMAGETRANSFER 0x0007
     302#define AIM_CB_SPECIAL_MSGTIMEOUT 0x0008
     303#define AIM_CB_SPECIAL_CONNDEAD 0x0009
    286304#define AIM_CB_SPECIAL_UNKNOWN 0xffff
    287305#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN
  • libfaim/aim_internal.h

    r862371b re374dee  
    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);
    2827
    2928        void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod);
     
    3736faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name);
    3837
     38faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod);
    3939faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod);
    40 faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod);
    4140faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod);
    4241faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod);
     
    4948faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod);
    5049faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod);
    51 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);
    5250faim_internal int invite_modfirst(aim_session_t *sess, aim_module_t *mod);
    5351faim_internal int translate_modfirst(aim_session_t *sess, aim_module_t *mod);
    5452faim_internal int popups_modfirst(aim_session_t *sess, aim_module_t *mod);
    5553faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod);
     54faim_internal int odir_modfirst(aim_session_t *sess, aim_module_t *mod);
     55faim_internal int bart_modfirst(aim_session_t *sess, aim_module_t *mod);
     56faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);
    5657faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod);
    5758faim_internal int email_modfirst(aim_session_t *sess, aim_module_t *mod);
    58 faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod);
    5959
    6060faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype);
     
    9797
    9898/* rxhandlers.c */
    99 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type);
     99faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type);
    100100faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_frame_t *ptr);
    101101faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...);
     
    130130} aim_snac_t;
    131131
    132 struct aim_snac_destructor {
    133         aim_conn_t *conn;
    134         void *data;
    135 };
    136 
    137132/* snac.c */
    138133faim_internal void aim_initsnachash(aim_session_t *sess);
     
    140135faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen);
    141136faim_internal aim_snac_t *aim_remsnac(aim_session_t *, aim_snacid_t id);
    142 faim_internal void aim_cleansnacs(aim_session_t *, int maxage);
    143137faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id);
    144138
     
    148142        char name[128];
    149143        fu16_t instance;
    150 };
    151 
    152 /* these are used by aim_*_clientready */
    153 #define AIM_TOOL_JAVA   0x0001
    154 #define AIM_TOOL_MAC    0x0002
    155 #define AIM_TOOL_WIN16  0x0003
    156 #define AIM_TOOL_WIN32  0x0004
    157 #define AIM_TOOL_MAC68K 0x0005
    158 #define AIM_TOOL_MACPPC 0x0006
    159 #define AIM_TOOL_NEWWIN 0x0010
    160 struct aim_tool_version {
    161         fu16_t group;
    162         fu16_t version;
    163         fu16_t tool;
    164         fu16_t toolversion;
    165144};
    166145
     
    221200faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie);
    222201
    223 faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *);
     202faim_internal void aim_info_free(aim_userinfo_t *);
     203faim_internal int aim_info_extract(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *);
    224204faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info);
    225205
     
    227207
    228208faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...);
    229 
    230 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret);
    231 faim_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);
    232 faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn);
    233 faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn);
    234209
    235210faim_internal void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn);
  • libfaim/auth.c

    r862371b re374dee  
    88
    99#define FAIM_INTERNAL
    10 #include <aim.h> 
     10#include <aim.h>
    1111
    1212#include "md5.h"
    1313
    14 static int aim_encode_password(const char *password, unsigned char *encoded);
     14static int aim_encode_password(const char *password, fu8_t *encoded);
    1515
    1616/*
     
    2222 *
    2323 */
    24 faim_export int aim_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu8_t *chipsahoy)
     24faim_export int aim_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu16_t length, const fu8_t *chipsahoy)
    2525{
    2626        aim_frame_t *fr;
    2727        aim_tlvlist_t *tl = NULL;
    2828
    29         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+AIM_COOKIELEN)))
     29        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+length)))
    3030                return -ENOMEM;
    3131
    3232        aimbs_put32(&fr->data, 0x00000001);
    33         aim_addtlvtochain_raw(&tl, 0x0006, AIM_COOKIELEN, chipsahoy);   
     33        aim_addtlvtochain_raw(&tl, 0x0006, length, chipsahoy);
    3434        aim_writetlvchain(&fr->data, &tl);
    3535        aim_freetlvchain(&tl);
     
    157157        aim_frame_t *fr;
    158158        aim_tlvlist_t *tl = NULL;
    159         char *password_encoded;
    160 
    161         if (!(password_encoded = (char *) malloc(strlen(password))))
     159        int passwdlen;
     160        fu8_t *password_encoded;
     161
     162        passwdlen = strlen(password);
     163        if (!(password_encoded = (char *)malloc(passwdlen+1)))
    162164                return -ENOMEM;
     165        if (passwdlen > MAXICQPASSLEN)
     166                passwdlen = MAXICQPASSLEN;
    163167
    164168        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) {
     
    171175        aimbs_put32(&fr->data, 0x00000001); /* FLAP Version */
    172176        aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
    173         aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded);
     177        aim_addtlvtochain_raw(&tl, 0x0002, passwdlen, password_encoded);
    174178
    175179        if (ci->clientstring)
     
    180184        aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point);
    181185        aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build);
    182         aim_addtlvtochain32(&tl, 0x0014, 0x00000055); /* distribution chan */
     186        aim_addtlvtochain32(&tl, 0x0014, (fu32_t)ci->distrib); /* distribution chan */
    183187        aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang);
    184188        aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country);
     
    202206 * then the client information you send here must exactly match the
    203207 * executable that you're pulling the data from.
    204  *
    205  * WinAIM 4.8.2540
    206  *   clientstring = "AOL Instant Messenger (SM), version 4.8.2540/WIN32"
    207  *   clientid = 0x0109
    208  *   major = 0x0004
    209  *   minor = 0x0008
    210  *   point = 0x0000
    211  *   build = 0x09ec
    212  *   t(0x0014) = 0x000000af
    213  *   t(0x004a) = 0x01
    214  *
    215  * WinAIM 4.3.2188:
    216  *   clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"
    217  *   clientid = 0x0109
    218  *   major = 0x0400
    219  *   minor = 0x0003
    220  *   point = 0x0000
    221  *   build = 0x088c
    222  *   unknown = 0x00000086
    223  *   lang = "en"
    224  *   country = "us"
    225  *   unknown4a = 0x01
    226  *
    227  * Latest WinAIM that libfaim can emulate without server-side buddylists:
    228  *   clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32"
    229  *   clientid = 0x0004
    230  *   major  = 0x0004
    231  *   minor  = 0x0001
    232  *   point = 0x0000
    233  *   build  = 0x07da
    234  *   unknown= 0x0000004b
    235  *
    236  * WinAIM 3.5.1670:
    237  *   clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32"
    238  *   clientid = 0x0004
    239  *   major =  0x0003
    240  *   minor =  0x0005
    241  *   point = 0x0000
    242  *   build =  0x0686
    243  *   unknown =0x0000002a
    244208 *
    245209 * Java AIM 1.1.19:
     
    304268        aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point);
    305269        aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build);
     270        aim_addtlvtochain32(&tl, 0x0014, (fu32_t)ci->distrib);
    306271        aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country);
    307272        aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang);
    308273
     274#ifndef NOSSI
    309275        /*
    310276         * If set, old-fashioned buddy lists will not work. You will need
     
    312278         */
    313279        aim_addtlvtochain8(&tl, 0x004a, 0x01);
     280#endif
    314281
    315282        aim_writetlvchain(&fr->data, &tl);
     
    388355        aim_tlvlist_t *tlvlist;
    389356        aim_rxcallback_t userfunc;
    390         struct aim_authresp_info info;
     357        struct aim_authresp_info *info;
    391358        int ret = 0;
    392359
    393         memset(&info, 0, sizeof(info));
     360        info = (struct aim_authresp_info *)malloc(sizeof(struct aim_authresp_info));
     361        memset(info, 0, sizeof(struct aim_authresp_info));
    394362
    395363        /*
     
    404372        memset(sess->sn, 0, sizeof(sess->sn));
    405373        if (aim_gettlv(tlvlist, 0x0001, 1)) {
    406                 info.sn = aim_gettlv_str(tlvlist, 0x0001, 1);
    407                 strncpy(sess->sn, info.sn, sizeof(sess->sn));
     374                info->sn = aim_gettlv_str(tlvlist, 0x0001, 1);
     375                strncpy(sess->sn, info->sn, sizeof(sess->sn));
    408376        }
    409377
     
    413381         */
    414382        if (aim_gettlv(tlvlist, 0x0008, 1))
    415                 info.errorcode = aim_gettlv16(tlvlist, 0x0008, 1);
     383                info->errorcode = aim_gettlv16(tlvlist, 0x0008, 1);
    416384        if (aim_gettlv(tlvlist, 0x0004, 1))
    417                 info.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
     385                info->errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
    418386
    419387        /*
     
    421389         */
    422390        if (aim_gettlv(tlvlist, 0x0005, 1))
    423                 info.bosip = aim_gettlv_str(tlvlist, 0x0005, 1);
     391                info->bosip = aim_gettlv_str(tlvlist, 0x0005, 1);
    424392
    425393        /*
     
    431399                tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
    432400
    433                 info.cookie = tmptlv->value;
     401                info->cookielen = tmptlv->length;
     402                info->cookie = tmptlv->value;
    434403        }
    435404
    436405        /*
    437406         * The email address attached to this account
    438          *   Not available for ICQ logins.
     407         *   Not available for ICQ or @mac.com logins.
     408         *   If you receive this TLV, then you are allowed to use
     409         *   family 0x0018 to check the status of your email.
     410         * XXX - Not really true!
    439411         */
    440412        if (aim_gettlv(tlvlist, 0x0011, 1))
    441                 info.email = aim_gettlv_str(tlvlist, 0x0011, 1);
     413                info->email = aim_gettlv_str(tlvlist, 0x0011, 1);
    442414
    443415        /*
    444416         * The registration status.  (Not real sure what it means.)
    445          *   Not available for ICQ logins.
     417         *   Not available for ICQ or @mac.com logins.
    446418         *
    447419         *   1 = No disclosure
     
    452424         * to other users or not.  AFAIK, this feature is no longer used.
    453425         *
     426         * Means you can use the admin family? (0x0007)
     427         *
    454428         */
    455429        if (aim_gettlv(tlvlist, 0x0013, 1))
    456                 info.regstatus = aim_gettlv16(tlvlist, 0x0013, 1);
     430                info->regstatus = aim_gettlv16(tlvlist, 0x0013, 1);
    457431
    458432        if (aim_gettlv(tlvlist, 0x0040, 1))
    459                 info.latestbeta.build = aim_gettlv32(tlvlist, 0x0040, 1);
     433                info->latestbeta.build = aim_gettlv32(tlvlist, 0x0040, 1);
    460434        if (aim_gettlv(tlvlist, 0x0041, 1))
    461                 info.latestbeta.url = aim_gettlv_str(tlvlist, 0x0041, 1);
     435                info->latestbeta.url = aim_gettlv_str(tlvlist, 0x0041, 1);
    462436        if (aim_gettlv(tlvlist, 0x0042, 1))
    463                 info.latestbeta.info = aim_gettlv_str(tlvlist, 0x0042, 1);
     437                info->latestbeta.info = aim_gettlv_str(tlvlist, 0x0042, 1);
    464438        if (aim_gettlv(tlvlist, 0x0043, 1))
    465                 info.latestbeta.name = aim_gettlv_str(tlvlist, 0x0043, 1);
     439                info->latestbeta.name = aim_gettlv_str(tlvlist, 0x0043, 1);
    466440        if (aim_gettlv(tlvlist, 0x0048, 1))
    467441                ; /* no idea what this is */
    468442
    469443        if (aim_gettlv(tlvlist, 0x0044, 1))
    470                 info.latestrelease.build = aim_gettlv32(tlvlist, 0x0044, 1);
     444                info->latestrelease.build = aim_gettlv32(tlvlist, 0x0044, 1);
    471445        if (aim_gettlv(tlvlist, 0x0045, 1))
    472                 info.latestrelease.url = aim_gettlv_str(tlvlist, 0x0045, 1);
     446                info->latestrelease.url = aim_gettlv_str(tlvlist, 0x0045, 1);
    473447        if (aim_gettlv(tlvlist, 0x0046, 1))
    474                 info.latestrelease.info = aim_gettlv_str(tlvlist, 0x0046, 1);
     448                info->latestrelease.info = aim_gettlv_str(tlvlist, 0x0046, 1);
    475449        if (aim_gettlv(tlvlist, 0x0047, 1))
    476                 info.latestrelease.name = aim_gettlv_str(tlvlist, 0x0047, 1);
     450                info->latestrelease.name = aim_gettlv_str(tlvlist, 0x0047, 1);
    477451        if (aim_gettlv(tlvlist, 0x0049, 1))
    478452                ; /* no idea what this is */
     
    482456         */
    483457        if (aim_gettlv(tlvlist, 0x0054, 1))
    484                 info.chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1);
     458                info->chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1);
     459
     460        /*
     461         * Unknown.  Seen on an @mac.com screen name with value of 0x003f
     462         */
     463        if (aim_gettlv(tlvlist, 0x0055, 1))
     464                ;
     465
     466        sess->authinfo = info;
    485467
    486468        if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003)))
    487                 ret = userfunc(sess, rx, &info);
    488 
    489         free(info.sn);
    490         free(info.bosip);
    491         free(info.errorurl);
    492         free(info.email);
    493         free(info.chpassurl);
    494         free(info.latestrelease.name);
    495         free(info.latestrelease.url);
    496         free(info.latestrelease.info);
    497         free(info.latestbeta.name);
    498         free(info.latestbeta.url);
    499         free(info.latestbeta.info);
     469                ret = userfunc(sess, rx, info);
    500470
    501471        aim_freetlvchain(&tlvlist);
     
    520490        keystr = aimbs_getstr(bs, keylen);
    521491
     492        /* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register
     493         * for the netscape network.  This SNAC had a type 0x0058 TLV with length 10. 
     494         * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */
     495
    522496        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    523497                ret = userfunc(sess, rx, keystr);
     
    526500
    527501        return ret;
     502}
     503
     504static void auth_shutdown(aim_session_t *sess, aim_module_t *mod)
     505{
     506        if (sess->authinfo) {
     507                free(sess->authinfo->sn);
     508                free(sess->authinfo->bosip);
     509                free(sess->authinfo->errorurl);
     510                free(sess->authinfo->email);
     511                free(sess->authinfo->chpassurl);
     512                free(sess->authinfo->latestrelease.name);
     513                free(sess->authinfo->latestrelease.url);
     514                free(sess->authinfo->latestrelease.info);
     515                free(sess->authinfo->latestbeta.name);
     516                free(sess->authinfo->latestbeta.url);
     517                free(sess->authinfo->latestbeta.info);
     518                free(sess->authinfo);
     519        }
    528520}
    529521
     
    547539        strncpy(mod->name, "auth", sizeof(mod->name));
    548540        mod->snachandler = snachandler;
    549 
    550         return 0;
    551 }
     541        mod->shutdown = auth_shutdown;
     542
     543        return 0;
     544}
  • libfaim/bos.c

    r862371b re374dee  
    22 * Family 0x0009 - Basic Oscar Service.
    33 *
     4 * The functionality of this family has been replaced by SSI.
    45 */
    56
    67#define FAIM_INTERNAL
    78#include <aim.h>
     9
     10#include <string.h>
    811
    912/* Subtype 0x0002 - Request BOS rights. */
     
    127130
    128131        for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
    129                 tmpptr = aimutil_itemidx(localcpy, i, '&');
     132                tmpptr = aimutil_itemindex(localcpy, i, '&');
    130133
    131134                aimbs_put8(&fr->data, strlen(tmpptr));
     
    156159        mod->version = 0x0001;
    157160        mod->toolid = 0x0110;
    158         mod->toolversion = 0x047b;
     161        mod->toolversion = 0x0629;
    159162        mod->flags = 0;
    160163        strncpy(mod->name, "bos", sizeof(mod->name));
  • libfaim/bstream.c

    r862371b re374dee  
    231231                return NULL;
    232232        }
    233        
     233
    234234        ob[len] = '\0';
    235235
  • libfaim/buddylist.c

    r862371b re374dee  
    66#define FAIM_INTERNAL
    77#include <aim.h>
     8
     9#include <string.h>
    810
    911/*
     
    233235 *
    234236 * Oncoming Buddy notifications contain a subset of the
    235  * user information structure.  Its close enough to run
    236  * through aim_extractuserinfo() however.
     237 * user information structure.  It's close enough to run
     238 * through aim_info_extract() however.
    237239 *
    238240 * Although the offgoing notification contains no information,
    239  * it is still in a format parsable by extractuserinfo.
     241 * it is still in a format parsable by aim_info_extract().
    240242 *
    241243 */
    242244static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    243245{
     246        int ret = 0;
    244247        aim_userinfo_t userinfo;
    245248        aim_rxcallback_t userfunc;
    246249
    247         aim_extractuserinfo(sess, bs, &userinfo);
     250        aim_info_extract(sess, bs, &userinfo);
    248251
    249252        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    250                 return userfunc(sess, rx, &userinfo);
    251 
    252         return 0;
     253                ret = userfunc(sess, rx, &userinfo);
     254
     255        aim_info_free(&userinfo);
     256
     257        return ret;
    253258}
    254259
     
    270275        mod->version = 0x0001;
    271276        mod->toolid = 0x0110;
    272         mod->toolversion = 0x047b;
     277        mod->toolversion = 0x0629;
    273278        mod->flags = 0;
    274279        strncpy(mod->name, "buddylist", sizeof(mod->name));
  • libfaim/chat.c

    r862371b re374dee  
    66#define FAIM_INTERNAL
    77#include <aim.h>
     8
     9#include <string.h>
    810
    911/* Stored in the ->priv of chat connections */
     
    205207        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    206208
    207 
    208209        /*
    209210         * Cookie
    210211         */
    211         for (i = 0; i < sizeof(ckstr); i++)
    212                 aimutil_put8(ckstr, (fu8_t) rand());
     212        for (i = 0; i < 8; i++)
     213                ckstr[i] = (fu8_t)rand();
    213214
    214215        /* XXX should be uncached by an unwritten 'invite accept' handler */
     
    225226                free(priv);
    226227
    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));
     228        /* ICBM Header */
     229        aimbs_putraw(&fr->data, ckstr, 8); /* Cookie */
     230        aimbs_put16(&fr->data, 0x0002); /* Channel */
     231        aimbs_put8(&fr->data, strlen(sn)); /* Screename length */
     232        aimbs_putraw(&fr->data, sn, strlen(sn)); /* Screenname */
    241233
    242234        /*
     
    346338
    347339                while (curoccupant < usercount)
    348                         aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);
     340                        aim_info_extract(sess, &occbs, &userinfo[curoccupant++]);
    349341        }
    350342
     
    424416        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
    425417                ret = userfunc(sess,
    426                                 rx, 
     418                                rx,
    427419                                &roominfo,
    428420                                roomname,
    429421                                usercount,
    430                                 userinfo,       
     422                                userinfo,
    431423                                roomdesc,
    432424                                flags,
     
    439431
    440432        free(roominfo.name);
     433
     434        while (usercount > 0)
     435                aim_info_free(&userinfo[--usercount]);
     436
    441437        free(userinfo);
    442438        free(roomname);
     
    457453                curcount++;
    458454                userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t));
    459                 aim_extractuserinfo(sess, bs, &userinfo[curcount-1]);
     455                aim_info_extract(sess, bs, &userinfo[curcount-1]);
    460456        }
    461457
     
    463459                ret = userfunc(sess, rx, curcount, userinfo);
    464460
     461        aim_info_free(userinfo);
    465462        free(userinfo);
    466463
     
    498495        aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid);
    499496
    500 
    501         /*
    502          * Generate a random message cookie.
     497        /*
     498         * Cookie
    503499         *
    504500         * XXX mkcookie should generate the cookie and cache it in one
    505501         * operation to preserve uniqueness.
    506          *
    507          */
    508         for (i = 0; i < sizeof(ckstr); i++)
    509                 aimutil_put8(ckstr+i, (fu8_t) rand());
     502         */
     503        for (i = 0; i < 8; i++)
     504                ckstr[i] = (fu8_t)rand();
    510505
    511506        cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
     
    514509        aim_cachecookie(sess, cookie);
    515510
    516         for (i = 0; i < sizeof(ckstr); i++)
    517                 aimbs_put8(&fr->data, ckstr[i]);
    518 
    519 
    520         /*
    521          * Channel ID.
    522          */
    523         aimbs_put16(&fr->data, 0x0003);
    524 
     511        /* ICBM Header */
     512        aimbs_putraw(&fr->data, ckstr, 8); /* Cookie */
     513        aimbs_put16(&fr->data, 0x0003); /* Channel */
    525514
    526515        /*
     
    544533         * SubTLV: Type 1: Message
    545534         */
    546         aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg);
     535        aim_addtlvtochain_raw(&itl, 0x0001, msglen, msg);
    547536
    548537        /*
     
    644633
    645634                aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length);
    646                 aim_extractuserinfo(sess, &tbs, &userinfo);
     635                aim_info_extract(sess, &tbs, &userinfo);
    647636        }
    648637
     
    678667                ret = userfunc(sess, rx, &userinfo, msg);
    679668
     669        aim_info_free(&userinfo);
    680670        free(cookie);
    681671        free(msg);
     
    703693        mod->family = 0x000e;
    704694        mod->version = 0x0001;
    705         mod->toolid = 0x0004; /* XXX this doesn't look right */
    706         mod->toolversion = 0x0001; /* nor does this */
     695        mod->toolid = 0x0010;
     696        mod->toolversion = 0x0629;
    707697        mod->flags = 0;
    708698        strncpy(mod->name, "chat", sizeof(mod->name));
  • libfaim/chatnav.c

    r862371b re374dee  
    424424
    425425        mod->family = 0x000d;
    426         mod->version = 0x0003;
     426        mod->version = 0x0001;
    427427        mod->toolid = 0x0010;
    428         mod->toolversion = 0x047c;
     428        mod->toolversion = 0x0629;
    429429        mod->flags = 0;
    430430        strncpy(mod->name, "chatnav", sizeof(mod->name));
  • libfaim/configure

    r5e53c4a re374dee  
    747747
    748748if test "$GCC" = yes; then
    749    CFLAGS="$CFLAGS -Wall";
     749   CFLAGS="$CFLAGS -Wall -g";
    750750fi
    751751# Extract the first word of "ranlib", so it can be a program name with args.
  • libfaim/configure.in

    r5e53c4a re374dee  
    66dnl we're using GCC, enable all warnings
    77if test "$GCC" = yes; then
    8    CFLAGS="$CFLAGS -Wall";
     8   CFLAGS="$CFLAGS -Wall -g";
    99fi
    1010AC_PROG_RANLIB
  • libfaim/conn.c

    r862371b re374dee  
    173173         * This will free ->internal if it necessary...
    174174         */
    175         if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS)
    176                 aim_conn_kill_rend(sess, *deadconn);
    177         else if ((*deadconn)->type == AIM_CONN_TYPE_CHAT)
     175        if ((*deadconn)->type == AIM_CONN_TYPE_CHAT)
    178176                aim_conn_kill_chat(sess, *deadconn);
    179177
     
    319317faim_export void aim_conn_close(aim_conn_t *deadconn)
    320318{
     319        aim_rxcallback_t userfunc;
    321320
    322321        if (deadconn->fd >= 3)
    323322                close(deadconn->fd);
     323
    324324        deadconn->fd = -1;
     325
     326        if ((userfunc = aim_callhandler(deadconn->sessv, deadconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNDEAD)))
     327                userfunc(deadconn->sessv, NULL, deadconn);
     328
    325329        if (deadconn->handlerlist)
    326330                aim_clearhandlers(deadconn);
    327         if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS)
    328                 aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn);
    329331
    330332        return;
     
    871873        aim_initsnachash(sess);
    872874        sess->msgcookies = NULL;
     875        sess->icq_info = NULL;
     876        sess->oft_info = NULL;
    873877        sess->snacid_next = 0x00000001;
    874878
     
    880884
    881885        sess->ssi.received_data = 0;
     886        sess->ssi.numitems = 0;
     887        sess->ssi.official = NULL;
     888        sess->ssi.local = NULL;
     889        sess->ssi.pending = NULL;
     890        sess->ssi.timestamp = (time_t)0;
    882891        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 
     892
     893        sess->authinfo = NULL;
    888894        sess->emailinfo = NULL;
    889895
     
    920926        aim__registermodule(sess, chatnav_modfirst);
    921927        aim__registermodule(sess, chat_modfirst);
    922         aim__registermodule(sess, newsearch_modfirst);
    923         /* missing 0x10 - 0x12 */
     928        /*      aim__registermodule(sess, odir_modfirst); */ /* kretch */
     929        /*      aim__registermodule(sess, bart_modfirst); */ /* kretch */
     930        /* missing 0x11 - 0x12 */
    924931        aim__registermodule(sess, ssi_modfirst);
    925932        /* missing 0x14 */
     
    992999faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn)
    9931000{
    994         fd_set fds, wfds;
    995         struct timeval tv;
    996         int res;
    997         int error = ETIMEDOUT;
    998 
    9991001        aim_rxcallback_t userfunc;
    10001002
     
    10051007                return -1;
    10061008
    1007         FD_ZERO(&fds);
    1008         FD_SET(conn->fd, &fds);
    1009         FD_ZERO(&wfds);
    1010         FD_SET(conn->fd, &wfds);
    1011         tv.tv_sec = 0;
    1012         tv.tv_usec = 0;
    1013 
    1014         if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) {
    1015                 error = errno;
    1016                 aim_conn_close(conn);
    1017                 errno = error;
    1018                 return -1;
    1019         } else if (res == 0) {
    1020                 faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd);
    1021                 return 0; /* hasn't really completed yet... */
    1022         }
    1023 
    1024         if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
    1025                 int len = sizeof(error);
    1026                 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
    1027                         error = errno;
    1028         }
    1029 
    1030         if (error) {
    1031                 aim_conn_close(conn);
    1032                 errno = error;
    1033                 return -1;
    1034         }
    1035         fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
     1009        fcntl(conn->fd, F_SETFL, 0);
    10361010
    10371011        conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
  • libfaim/email.c

    r862371b re374dee  
    6363/**
    6464 * Subtype 0x0007 - Receive information about your email account
     65 *
    6566 * So I don't even know if you can have multiple 16 byte keys,
    6667 * but this is coded so it will handle that, and handle it well.
     
    7475static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    7576{
     77        int ret = 0;
    7678        aim_rxcallback_t userfunc;
    7779        struct aim_emailinfo *new;
     
    125127
    126128        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    127                 return userfunc(sess, rx, new, havenewmail);
    128 
    129         return 0;
     129                ret = userfunc(sess, rx, new, havenewmail);
     130
     131        aim_freetlvchain(&tlvlist);
     132
     133        return ret;
    130134}
    131135
  • libfaim/ft.c

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

    r862371b re374dee  
    7171}
    7272
     73faim_export int aim_icq_hideip(aim_session_t *sess)
     74{
     75        aim_conn_t *conn;
     76        aim_frame_t *fr;
     77        aim_snacid_t snacid;
     78        int bslen;
     79
     80        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
     81                return -EINVAL;
     82
     83        bslen = 2+4+2+2+2+4;
     84
     85        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
     86                return -ENOMEM;
     87
     88        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
     89        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
     90
     91        /* For simplicity, don't bother using a tlvlist */
     92        aimbs_put16(&fr->data, 0x0001);
     93        aimbs_put16(&fr->data, bslen);
     94
     95        aimbs_putle16(&fr->data, bslen - 2);
     96        aimbs_putle32(&fr->data, atoi(sess->sn));
     97        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
     98        aimbs_putle16(&fr->data, snacid); /* eh. */
     99        aimbs_putle16(&fr->data, 0x0424); /* shrug. */
     100        aimbs_putle16(&fr->data, 0x0001);
     101        aimbs_putle16(&fr->data, 0x0001);
     102
     103        aim_tx_enqueue(sess, fr);
     104
     105        return 0;
     106}
     107
     108/**
     109 * Change your ICQ password.
     110 *
     111 * @param sess The oscar session
     112 * @param passwd The new password.  If this is longer than 8 characters it
     113 *        will be truncated.
     114 * @return Return 0 if no errors, otherwise return the error number.
     115 */
     116faim_export int aim_icq_changepasswd(aim_session_t *sess, const char *passwd)
     117{
     118        aim_conn_t *conn;
     119        aim_frame_t *fr;
     120        aim_snacid_t snacid;
     121        int bslen, passwdlen;
     122
     123        if (!passwd)
     124                return -EINVAL;
     125
     126        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
     127                return -EINVAL;
     128
     129        passwdlen = strlen(passwd);
     130        if (passwdlen > MAXICQPASSLEN)
     131                passwdlen = MAXICQPASSLEN;
     132        bslen = 2+4+2+2+2+2+passwdlen+1;
     133
     134        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
     135                return -ENOMEM;
     136
     137        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
     138        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
     139
     140        /* For simplicity, don't bother using a tlvlist */
     141        aimbs_put16(&fr->data, 0x0001);
     142        aimbs_put16(&fr->data, bslen);
     143
     144        aimbs_putle16(&fr->data, bslen - 2);
     145        aimbs_putle32(&fr->data, atoi(sess->sn));
     146        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
     147        aimbs_putle16(&fr->data, snacid); /* eh. */
     148        aimbs_putle16(&fr->data, 0x042e); /* shrug. */
     149        aimbs_putle16(&fr->data, passwdlen+1);
     150        aimbs_putraw(&fr->data, passwd, passwdlen);
     151        aimbs_putle8(&fr->data, '\0');
     152
     153        aim_tx_enqueue(sess, fr);
     154
     155        return 0;
     156}
     157
     158faim_export int aim_icq_getallinfo(aim_session_t *sess, const char *uin)
     159{
     160        aim_conn_t *conn;
     161        aim_frame_t *fr;
     162        aim_snacid_t snacid;
     163        int bslen;
     164        struct aim_icq_info *info;
     165
     166        if (!uin || uin[0] < '0' || uin[0] > '9')
     167                return -EINVAL;
     168
     169        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
     170                return -EINVAL;
     171
     172        bslen = 2 + 4 + 2 + 2 + 2 + 4;
     173
     174        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
     175                return -ENOMEM;
     176
     177        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
     178        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
     179
     180        /* For simplicity, don't bother using a tlvlist */
     181        aimbs_put16(&fr->data, 0x0001);
     182        aimbs_put16(&fr->data, bslen);
     183
     184        aimbs_putle16(&fr->data, bslen - 2);
     185        aimbs_putle32(&fr->data, atoi(sess->sn));
     186        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
     187        aimbs_putle16(&fr->data, snacid); /* eh. */
     188        aimbs_putle16(&fr->data, 0x04b2); /* shrug. */
     189        aimbs_putle32(&fr->data, atoi(uin));
     190
     191        aim_tx_enqueue(sess, fr);
     192
     193        /* Keep track of this request and the ICQ number and request ID */
     194        info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
     195        info->reqid = snacid;
     196        info->uin = atoi(uin);
     197        info->next = sess->icq_info;
     198        sess->icq_info = info;
     199
     200        return 0;
     201}
     202
     203faim_export int aim_icq_getalias(aim_session_t *sess, const char *uin)
     204{
     205        aim_conn_t *conn;
     206        aim_frame_t *fr;
     207        aim_snacid_t snacid;
     208        int bslen;
     209        struct aim_icq_info *info;
     210
     211        if (!uin || uin[0] < '0' || uin[0] > '9')
     212                return -EINVAL;
     213
     214        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
     215                return -EINVAL;
     216
     217        bslen = 2 + 4 + 2 + 2 + 2 + 4;
     218
     219        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
     220                return -ENOMEM;
     221
     222        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
     223        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
     224
     225        /* For simplicity, don't bother using a tlvlist */
     226        aimbs_put16(&fr->data, 0x0001);
     227        aimbs_put16(&fr->data, bslen);
     228
     229        aimbs_putle16(&fr->data, bslen - 2);
     230        aimbs_putle32(&fr->data, atoi(sess->sn));
     231        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
     232        aimbs_putle16(&fr->data, snacid); /* eh. */
     233        aimbs_putle16(&fr->data, 0x04ba); /* shrug. */
     234        aimbs_putle32(&fr->data, atoi(uin));
     235
     236        aim_tx_enqueue(sess, fr);
     237
     238        /* Keep track of this request and the ICQ number and request ID */
     239        info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
     240        info->reqid = snacid;
     241        info->uin = atoi(uin);
     242        info->next = sess->icq_info;
     243        sess->icq_info = info;
     244
     245        return 0;
     246}
     247
     248faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin)
     249{
     250        aim_conn_t *conn;
     251        aim_frame_t *fr;
     252        aim_snacid_t snacid;
     253        int bslen;
     254
     255        if (!uin || uin[0] < '0' || uin[0] > '9')
     256                return -EINVAL;
     257
     258        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
     259                return -EINVAL;
     260
     261        bslen = 2 + 4 + 2 + 2 + 2 + 4;
     262
     263        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
     264                return -ENOMEM;
     265
     266        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
     267        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
     268
     269        /* For simplicity, don't bother using a tlvlist */
     270        aimbs_put16(&fr->data, 0x0001);
     271        aimbs_put16(&fr->data, bslen);
     272
     273        aimbs_putle16(&fr->data, bslen - 2);
     274        aimbs_putle32(&fr->data, atoi(sess->sn));
     275        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
     276        aimbs_putle16(&fr->data, snacid); /* eh. */
     277        aimbs_putle16(&fr->data, 0x051f); /* shrug. */
     278        aimbs_putle32(&fr->data, atoi(uin));
     279
     280        aim_tx_enqueue(sess, fr);
     281
     282        return 0;
     283}
     284
    73285faim_export int aim_icq_sendxmlreq(aim_session_t *sess, const char *xml)
    74286{
     
    109321}
    110322
    111 faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin)
    112 {
    113         aim_conn_t *conn;
    114         aim_frame_t *fr;
    115         aim_snacid_t snacid;
    116         int bslen;
    117 
    118         if (!uin || uin[0] < '0' || uin[0] > '9')
    119                 return -EINVAL;
    120 
    121         if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
    122                 return -EINVAL;
    123 
    124         bslen = 2 + 4 + 2 + 2 + 2 + 4;
    125 
    126         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
    127                 return -ENOMEM;
    128 
    129         snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
    130         aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
    131 
    132         /* For simplicity, don't bother using a tlvlist */
    133         aimbs_put16(&fr->data, 0x0001);
    134         aimbs_put16(&fr->data, bslen);
    135 
    136         aimbs_putle16(&fr->data, bslen - 2);
    137         aimbs_putle32(&fr->data, atoi(sess->sn));
    138         aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
    139         aimbs_putle16(&fr->data, snacid); /* eh. */
    140         aimbs_putle16(&fr->data, 0x051f); /* shrug. */
    141         aimbs_putle32(&fr->data, atoi(uin));
    142 
    143         aim_tx_enqueue(sess, fr);
    144 
    145         return 0;
    146 }
    147 
    148 /*
    149  * Response to 15/2, contains an ICQ packet.
     323static void aim_icq_freeinfo(struct aim_icq_info *info) {
     324        int i;
     325
     326        if (!info)
     327                return;
     328        free(info->nick);
     329        free(info->first);
     330        free(info->last);
     331        free(info->email);
     332        free(info->homecity);
     333        free(info->homestate);
     334        free(info->homephone);
     335        free(info->homefax);
     336        free(info->homeaddr);
     337        free(info->mobile);
     338        free(info->homezip);
     339        free(info->personalwebpage);
     340        if (info->email2)
     341                for (i = 0; i < info->numaddresses; i++)
     342                        free(info->email2[i]);
     343        free(info->email2);
     344        free(info->workcity);
     345        free(info->workstate);
     346        free(info->workphone);
     347        free(info->workfax);
     348        free(info->workaddr);
     349        free(info->workzip);
     350        free(info->workcompany);
     351        free(info->workdivision);
     352        free(info->workposition);
     353        free(info->workwebpage);
     354        free(info->info);
     355        free(info);
     356}
     357
     358/**
     359 * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet.
    150360 */
    151361static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     
    173383        faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
    174384
    175         if (cmd == 0x0041) {
    176                 fu16_t msglen;
     385        if (cmd == 0x0041) { /* offline message */
    177386                struct aim_icq_offlinemsg msg;
    178387                aim_rxcallback_t userfunc;
     
    186395                msg.hour = aimbs_getle8(&qbs);
    187396                msg.minute = aimbs_getle8(&qbs);
    188                 msg.type = aimbs_getle16(&qbs);
    189                 msglen = aimbs_getle16(&qbs);
    190                 msg.msg = aimbs_getstr(&qbs, msglen);
     397                msg.type = aimbs_getle8(&qbs);
     398                msg.flags = aimbs_getle8(&qbs);
     399                msg.msglen = aimbs_getle16(&qbs);
     400                msg.msg = aimbs_getstr(&qbs, msg.msglen);
    191401
    192402                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG)))
     
    200410                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE)))
    201411                        ret = userfunc(sess, rx);
    202         } else if (cmd == 0x07da) {
     412
     413        } else if (cmd == 0x07da) { /* information */
    203414                fu16_t subtype;
     415                struct aim_icq_info *info;
     416                aim_rxcallback_t userfunc;
    204417
    205418                subtype = aimbs_getle16(&qbs);
    206 
    207                 if (subtype == 0x019a) {
    208                         fu16_t tlen;
    209                         struct aim_icq_simpleinfo info;
    210                         aim_rxcallback_t userfunc;
    211 
    212                         memset(&info, 0, sizeof(info));
    213 
    214                         aimbs_getle8(&qbs); /* no clue */
    215                         aimbs_getle16(&qbs); /* no clue */
    216                         info.uin = aimbs_getle32(&qbs);
    217                         tlen = aimbs_getle16(&qbs);
    218                         info.nick = aimbs_getstr(&qbs, tlen);
    219                         tlen = aimbs_getle16(&qbs);
    220                         info.first = aimbs_getstr(&qbs, tlen);
    221                         tlen = aimbs_getle16(&qbs);
    222                         info.last = aimbs_getstr(&qbs, tlen);
    223                         tlen = aimbs_getle16(&qbs);
    224                         info.email = aimbs_getstr(&qbs, tlen);
    225                         /* no clue what the rest of it is */
    226 
    227                         if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO)))
    228                                 ret = userfunc(sess, rx, &info);
    229 
    230                         free(info.nick);
    231                         free(info.first);
    232                         free(info.last);
    233                         free(info.email);
     419                aim_bstream_advance(&qbs, 1); /* 0x0a */
     420
     421                /* find other data from the same request */
     422                for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next);
     423                if (!info) {
     424                        info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
     425                        info->reqid = reqid;
     426                        info->next = sess->icq_info;
     427                        sess->icq_info = info;
    234428                }
    235429
     430                switch (subtype) {
     431                case 0x00a0: { /* hide ip status */
     432                        /* nothing */
     433                } break;
     434
     435                case 0x00aa: { /* password change status */
     436                        /* nothing */
     437                } break;
     438
     439                case 0x00c8: { /* general and "home" information */
     440                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     441                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     442                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     443                        info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     444                        info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     445                        info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     446                        info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     447                        info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     448                        info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     449                        info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     450                        info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     451                        info->homecountry = aimbs_getle16(&qbs);
     452                        /* 0x0a 00 02 00 */
     453                        /* 1 byte timezone? */
     454                        /* 1 byte hide email flag? */
     455                } break;
     456
     457                case 0x00dc: { /* personal information */
     458                        info->age = aimbs_getle8(&qbs);
     459                        info->unknown = aimbs_getle8(&qbs);
     460                        info->gender = aimbs_getle8(&qbs);
     461                        info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     462                        info->birthyear = aimbs_getle16(&qbs);
     463                        info->birthmonth = aimbs_getle8(&qbs);
     464                        info->birthday = aimbs_getle8(&qbs);
     465                        info->language1 = aimbs_getle8(&qbs);
     466                        info->language2 = aimbs_getle8(&qbs);
     467                        info->language3 = aimbs_getle8(&qbs);
     468                        /* 0x00 00 01 00 00 01 00 00 00 00 00 */
     469                } break;
     470
     471                case 0x00d2: { /* work information */
     472                        info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     473                        info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     474                        info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     475                        info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     476                        info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     477                        info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     478                        info->workcountry = aimbs_getle16(&qbs);
     479                        info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     480                        info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     481                        info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     482                        aim_bstream_advance(&qbs, 2); /* 0x01 00 */
     483                        info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     484                } break;
     485
     486                case 0x00e6: { /* additional personal information */
     487                        info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)-1);
     488                } break;
     489
     490                case 0x00eb: { /* email address(es) */
     491                        int i;
     492                        info->numaddresses = aimbs_getle16(&qbs);
     493                        info->email2 = (char **)calloc(info->numaddresses, sizeof(char *));
     494                        for (i = 0; i < info->numaddresses; i++) {
     495                                info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     496                                if (i+1 != info->numaddresses)
     497                                        aim_bstream_advance(&qbs, 1); /* 0x00 */
     498                        }
     499                } break;
     500
     501                case 0x00f0: { /* personal interests */
     502                } break;
     503
     504                case 0x00fa: { /* past background and current organizations */
     505                } break;
     506
     507                case 0x0104: { /* alias info */
     508                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     509                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     510                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     511                        aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); /* email address? */
     512                        /* Then 0x00 02 00 */
     513                } break;
     514
     515                case 0x010e: { /* unknown */
     516                        /* 0x00 00 */
     517                } break;
     518
     519                case 0x019a: { /* simple info */
     520                        aim_bstream_advance(&qbs, 2);
     521                        info->uin = aimbs_getle32(&qbs);
     522                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     523                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     524                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     525                        info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
     526                        /* Then 0x00 02 00 00 00 00 00 */
     527                } break;
     528                } /* End switch statement */
     529
     530                if (!(snac->flags & 0x0001)) {
     531                        if (subtype != 0x0104)
     532                                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO)))
     533                                        ret = userfunc(sess, rx, info);
     534
     535                        if (info->uin && info->nick)
     536                                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALIAS)))
     537                                        ret = userfunc(sess, rx, info);
     538
     539                        if (sess->icq_info == info) {
     540                                sess->icq_info = info->next;
     541                        } else {
     542                                struct aim_icq_info *cur;
     543                                for (cur=sess->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
     544                                if (cur->next)
     545                                        cur->next = cur->next->next;
     546                        }
     547                        aim_icq_freeinfo(info);
     548                }
    236549        }
    237550
     
    248561
    249562        return 0;
     563}
     564
     565static void icq_shutdown(aim_session_t *sess, aim_module_t *mod)
     566{
     567        struct aim_icq_info *del;
     568
     569        while (sess->icq_info) {
     570                del = sess->icq_info;
     571                sess->icq_info = sess->icq_info->next;
     572                aim_icq_freeinfo(del);
     573        }
     574
     575        return;
    250576}
    251577
     
    256582        mod->version = 0x0001;
    257583        mod->toolid = 0x0110;
    258         mod->toolversion = 0x047b;
     584        mod->toolversion = 0x047c;
    259585        mod->flags = 0;
    260586        strncpy(mod->name, "icq", sizeof(mod->name));
    261587        mod->snachandler = snachandler;
    262 
    263         return 0;
    264 }
     588        mod->shutdown = icq_shutdown;
     589
     590        return 0;
     591}
  • libfaim/im.c

    r862371b re374dee  
    11/*
    2  *  Family 0x0004 - Routines for sending/receiving Instant Messages.
    3  *
    4  *  Note the term ICBM (Inter-Client Basic Message) which blankets
    5  *  all types of genericly routed through-server messages.  Within
    6  *  the ICBM types (family 4), a channel is defined.  Each channel
    7  *  represents a different type of message.  Channel 1 is used for
    8  *  what would commonly be called an "instant message".  Channel 2
    9  *  is used for negotiating "rendezvous".  These transactions end in
    10  *  something more complex happening, such as a chat invitation, or
    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.
    15  *
    16  *  In addition to the channel, every ICBM contains a cookie.  For
    17  *  standard IMs, these are only used for error messages.  However,
    18  *  the more complex rendezvous messages make suitably more complex
    19  *  use of this field.
    20  *
     2 * Family 0x0004 - Routines for sending/receiving Instant Messages.
     3 *
     4 * Note the term ICBM (Inter-Client Basic Message) which blankets
     5 * all types of genericly routed through-server messages.  Within
     6 * the ICBM types (family 4), a channel is defined.  Each channel
     7 * represents a different type of message.  Channel 1 is used for
     8 * what would commonly be called an "instant message".  Channel 2
     9 * is used for negotiating "rendezvous".  These transactions end in
     10 * something more complex happening, such as a chat invitation, or
     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.
     15 *
     16 * In addition to the channel, every ICBM contains a cookie.  For
     17 * standard IMs, these are only used for error messages.  However,
     18 * the more complex rendezvous messages make suitably more complex
     19 * use of this field.
     20 *
     21 * TODO: Split this up into an im.c file an an icbm.c file.  It
     22 *       will be beautiful, you'll see.
     23 *
     24 *       Need to rename all the mpmsg messages to aim_im_bleh.
     25 *
     26 *       Make sure aim_conn_findbygroup is used by all functions.
    2127 */
    2228
     
    2733#include "win32dep.h"
    2834#endif
     35
     36/**
     37 * Add a standard ICBM header to the given bstream with the given
     38 * information.
     39 *
     40 * @param bs The bstream to write the ICBM header to.
     41 * @param c c is for cookie, and cookie is for me.
     42 * @param ch The ICBM channel (1 through 4).
     43 * @param sn Null-terminated scrizeen nizame.
     44 * @return The number of bytes written.  It's really not useful.
     45 */
     46static int aim_im_puticbm(aim_bstream_t *bs, const fu8_t *c, fu16_t ch, const char *sn)
     47{
     48        aimbs_putraw(bs, c, 8);
     49        aimbs_put16(bs, ch);
     50        aimbs_put8(bs, strlen(sn));
     51        aimbs_putraw(bs, sn, strlen(sn));
     52        return 8+2+1+strlen(sn);
     53}
    2954
    3055/*
     
    3863 *
    3964 * Heres the current collection:
    40  *  0501 0003 0101 0101 01       AOL Mobile Communicator, WinAIM 1.0.414
    41  *  0501 0003 0101 0201 01       WinAIM 2.0.847, 2.1.1187, 3.0.1464,
    42  *                                      4.3.2229, 4.4.2286
    43  *  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
    46  *  0501 0001 0101 01            AOL v6.0, CompuServe 2000 v6.0, any
    47  *                                      TOC client
     65 *  0501 0003 0101 0101 01              AOL Mobile Communicator, WinAIM 1.0.414
     66 *  0501 0003 0101 0201 01              WinAIM 2.0.847, 2.1.1187, 3.0.1464,
     67 *                                      4.3.2229, 4.4.2286
     68 *  0501 0004 0101 0102 0101            WinAIM 4.1.2010, libfaim (right here)
     69 *  0501 0003 0101 02                   WinAIM 5
     70 *  0501 0001 01                        iChat x.x, mobile buddies
     71 *  0501 0001 0101 01                   AOL v6.0, CompuServe 2000 v6.0, any TOC client
     72 *  0501 0002 0106                      WinICQ 5.45.1.3777.85
    4873 *
    4974 * Note that in this function, only the feature bytes are tested, since
     
    5176 *
    5277 */
    53 faim_export fu16_t aim_fingerprintclient(fu8_t *msghdr, int len)
     78faim_export fu16_t aim_im_fingerprint(const fu8_t *msghdr, int len)
    5479{
    5580        static const struct {
     
    91116}
    92117
    93 /*
    94  * Subtype 0x0002
     118/**
     119 * Subtype 0x0002 - Set ICBM parameters.
    95120 *
    96121 * 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.
     122 * with the rather unreasonable defaults.
    98123 *
    99124 */
    100 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)
     125faim_export int aim_im_setparams(aim_session_t *sess, struct aim_icbmparameters *params)
    101126{
    102127        aim_conn_t *conn;
     
    131156}
    132157
    133 /* Subtype 0x0004 - Request ICBM parameter information. */
    134 faim_export int aim_reqicbmparams(aim_session_t *sess)
     158/**
     159 * Subtype 0x0004 - Request ICBM parameter information.
     160 *
     161 */
     162faim_export int aim_im_reqparams(aim_session_t *sess)
    135163{
    136164        aim_conn_t *conn;
     
    142170}
    143171
    144 /* Subtype 0x0005 */
    145 static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    146 {
     172/**
     173 * Subtype 0x0005 - Receive parameter information.
     174 *
     175 */
     176static int aim_im_paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     177{
     178        aim_rxcallback_t userfunc;
    147179        struct aim_icbmparameters params;
    148         aim_rxcallback_t userfunc;
    149180
    150181        params.maxchan = aimbs_get16(bs);
     
    161192}
    162193
    163 /* This should be endian-safe now... but who knows... */
    164 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen)
    165 {
    166         fu32_t sum;
    167         int i;
    168 
    169         for (i = 0, sum = 0; i + 1 < buflen; i += 2)
    170                 sum += (buf[i+1] << 8) + buf[i];
    171         if (i < buflen)
    172                 sum += buf[i];
    173 
    174         sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
    175 
    176         return (fu16_t)sum;
    177 }
    178 
    179 /*
     194/**
    180195 * Subtype 0x0006 - Send an ICBM (instant message). 
    181196 *
     
    220235 * instead of writing out the bytes manually.
    221236 *
    222  * XXX more precise verification that we never send SNACs larger than 8192
    223  * XXX check SNAC size for multipart
    224  *
    225  */
    226 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args)
    227 {
    228         static const fu8_t deffeatures[] = {
    229                 0x01, 0x01, 0x01, 0x02
    230         };
     237 * XXX - more precise verification that we never send SNACs larger than 8192
     238 * XXX - check SNAC size for multipart
     239 *
     240 */
     241faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args)
     242{
    231243        aim_conn_t *conn;
    232         int i, msgtlvlen;
    233244        aim_frame_t *fr;
    234245        aim_snacid_t snacid;
     246        fu8_t ck[8];
     247        int i, msgtlvlen;
     248        static const fu8_t deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };
    235249
    236250        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     
    275289                return -ENOMEM;
    276290
    277         /* XXX should be optional */   
     291        /* XXX - should be optional */ 
    278292        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
    279293        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    280294
    281295        /*
    282          * Generate a random message cookie 
     296         * Generate a random message cookie
    283297         *
    284298         * We could cache these like we do SNAC IDs.  (In fact, it
     
    289303         */
    290304        for (i = 0; i < 8; i++)
    291                 aimbs_put8(&fr->data, (fu8_t) rand());
    292 
    293         /*
    294          * Channel ID
    295          */
    296         aimbs_put16(&fr->data, 0x0001);
    297 
    298         /*
    299          * Destination SN (prepended with byte length)
    300          */
    301         aimbs_put8(&fr->data, strlen(args->destsn));
    302         aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn));
    303 
    304         /*
    305          * Message TLV (type 2).
    306          */
     305                ck[i] = (fu8_t)rand();
     306
     307        /* ICBM header */
     308        aim_im_puticbm(&fr->data, ck, 0x0001, args->destsn);
     309
     310        /* Message TLV (type 0x0002) */
    307311        aimbs_put16(&fr->data, 0x0002);
    308312        aimbs_put16(&fr->data, msgtlvlen);
    309313
    310         /*
    311          * Features
    312          *
    313          */
    314         aimbs_put8(&fr->data, 0x05);
    315         aimbs_put8(&fr->data, 0x01);
    316 
     314        /* Features TLV (type 0x0501) */
     315        aimbs_put16(&fr->data, 0x0501);
    317316        if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
    318317                aimbs_put16(&fr->data, args->featureslen);
     
    326325                aim_mpmsg_section_t *sec;
    327326
     327                /* Insert each message part in a TLV (type 0x0101) */
    328328                for (sec = args->mpmsg->parts; sec; sec = sec->next) {
    329329                        aimbs_put16(&fr->data, 0x0101);
     
    336336        } else {
    337337
     338                /* Insert message text in a TLV (type 0x0101) */
    338339                aimbs_put16(&fr->data, 0x0101);
    339340
    340                 /*
    341                  * Message block length.
    342                  */
     341                /* Message block length */
    343342                aimbs_put16(&fr->data, args->msglen + 0x04);
    344343
    345                 /*
    346                  * Character set.
    347                  */
    348                 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) {
    349 
    350                         aimbs_put16(&fr->data, args->charset);
    351                         aimbs_put16(&fr->data, args->charsubset);
    352 
    353                 } else {
    354                         if (args->flags & AIM_IMFLAGS_UNICODE)
    355                                 aimbs_put16(&fr->data, 0x0002);
    356                         else if (args->flags & AIM_IMFLAGS_ISO_8859_1)
    357                                 aimbs_put16(&fr->data, 0x0003);
    358                         else
    359                                 aimbs_put16(&fr->data, 0x0000);
    360 
    361                         aimbs_put16(&fr->data, 0x0000);
    362                 }
    363 
    364                 /*
    365                  * Message.  Not terminated.
    366                  */
     344                /* Character set */
     345                aimbs_put16(&fr->data, args->charset);
     346                aimbs_put16(&fr->data, args->charsubset);
     347
     348                /* Message.  Not terminated */
    367349                aimbs_putraw(&fr->data, args->msg, args->msglen);
    368350        }
    369351
    370         /*
    371          * Set the Request Acknowledge flag. 
    372          */
    373         if (args->flags & AIM_IMFLAGS_ACK) {
    374                 aimbs_put16(&fr->data, 0x0003);
    375                 aimbs_put16(&fr->data, 0x0000);
    376         }
    377 
    378         /*
    379          * Set the Autoresponse flag.
    380          */
     352        /* Set the Autoresponse flag */
    381353        if (args->flags & AIM_IMFLAGS_AWAY) {
    382354                aimbs_put16(&fr->data, 0x0004);
     355                aimbs_put16(&fr->data, 0x0000);
     356        } else if (args->flags & AIM_IMFLAGS_ACK) {
     357                /* Set the Request Acknowledge flag */
     358                aimbs_put16(&fr->data, 0x0003);
    383359                aimbs_put16(&fr->data, 0x0000);
    384360        }
     
    414390        aim_tx_enqueue(sess, fr);
    415391
     392        /* Move this to receive aim_flap_nop and send aim_flap_nop */
    416393        if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM))
    417394                aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */
     
    421398
    422399/*
    423  * Simple wrapper for aim_send_im_ext()
     400 * Simple wrapper for aim_im_sendch1_ext()
    424401 *
    425402 * You cannot use aim_send_im if you need the HASICON flag.  You must
    426  * use aim_send_im_ext directly for that.
     403 * use aim_im_sendch1_ext directly for that.
    427404 *
    428405 * aim_send_im also cannot be used if you require UNICODE messages, because
    429  * that requires an explicit message length.  Use aim_send_im_ext().
    430  *
    431  */
    432 faim_export int aim_send_im(aim_session_t *sess, const char *destsn, fu16_t flags, const char *msg)
     406 * that requires an explicit message length.  Use aim_im_sendch1_ext().
     407 *
     408 */
     409faim_export int aim_im_sendch1(aim_session_t *sess, const char *sn, fu16_t flags, const char *msg)
    433410{
    434411        struct aim_sendimext_args args;
    435412
    436         args.destsn = destsn;
     413        args.destsn = sn;
    437414        args.flags = flags;
    438415        args.msg = msg;
    439416        args.msglen = strlen(msg);
    440 
    441         /* Make these don't get set by accident -- they need aim_send_im_ext */
     417        args.charset = 0x0000;
     418        args.charsubset = 0x0000;
     419
     420        /* Make these don't get set by accident -- they need aim_im_sendch1_ext */
    442421        args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART);
    443422
    444         return aim_send_im_ext(sess, &args);
    445 }
    446 
    447 /*
    448  * Subtype 0x0006
     423        return aim_im_sendch1_ext(sess, &args);
     424}
     425
     426/**
     427 * Subtype 0x0006 - Send your icon to a given user.
    449428 *
    450429 * This is also performance sensitive. (If you can believe it...)
    451430 *
    452431 */
    453 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum)
     432faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum)
    454433{
    455434        aim_conn_t *conn;
    456         int i;
    457         fu8_t ck[8];
    458435        aim_frame_t *fr;
    459436        aim_snacid_t snacid;
     437        fu8_t ck[8];
     438        int i;
    460439
    461440        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     
    466445
    467446        for (i = 0; i < 8; i++)
    468                 aimutil_put8(ck+i, (fu8_t) rand());
     447                ck[i] = (fu8_t)rand();
    469448
    470449        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2)))
     
    474453        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    475454
    476         /*
    477          * Cookie
    478          */
    479         aimbs_putraw(&fr->data, ck, 8);
    480 
    481         /*
    482          * Channel (2)
    483          */
    484         aimbs_put16(&fr->data, 0x0002);
    485 
    486         /*
    487          * Dest sn
    488          */
    489         aimbs_put8(&fr->data, strlen(sn));
    490         aimbs_putraw(&fr->data, sn, strlen(sn));
     455        /* ICBM header */
     456        aim_im_puticbm(&fr->data, ck, 0x0002, sn);
    491457
    492458        /*
     
    531497
    532498/*
    533  * Subtype 0x0006
     499 * Subtype 0x0006 - Send a rich text message.
    534500 *
    535501 * This only works for ICQ 2001b (thats 2001 not 2000).  Better, only
     
    545511 *
    546512 */
    547 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args)
    548 {
    549         const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */
     513faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args)
     514{
    550515        aim_conn_t *conn;
    551         int i;
    552         fu8_t ck[8];
    553516        aim_frame_t *fr;
    554517        aim_snacid_t snacid;
    555         int servdatalen;
     518        fu8_t ck[8];
     519        const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */
     520        int i, servdatalen;
    556521
    557522        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     
    564529
    565530        for (i = 0; i < 8; i++)
    566                 aimutil_put8(ck+i, (fu8_t) rand());
     531                ck[i] = (fu8_t)rand();
    567532
    568533        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen)))
     
    572537        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    573538
    574         /*
    575          * Cookie
    576          */
    577         aimbs_putraw(&fr->data, ck, 8);
    578 
    579         /*
    580          * Channel (2)
    581          */
    582         aimbs_put16(&fr->data, 0x0002);
    583 
    584         /*
    585          * Dest sn
    586          */
    587         aimbs_put8(&fr->data, strlen(args->destsn));
    588         aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn));
    589 
    590         /*
    591          * TLV t(0005)
    592          *
    593          * Encompasses everything below.
    594          */
     539        /* ICBM header */
     540        aim_im_puticbm(&fr->data, ck, 0x0002, args->destsn);
     541
     542        /* TLV t(0005) - Encompasses everything below. */
    595543        aimbs_put16(&fr->data, 0x0005);
    596544        aimbs_put16(&fr->data, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
     
    600548        aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY);
    601549
    602         /*
    603          * t(000a) l(0002) v(0001)
    604          */
     550        /* t(000a) l(0002) v(0001) */
    605551        aimbs_put16(&fr->data, 0x000a);
    606552        aimbs_put16(&fr->data, 0x0002);
    607553        aimbs_put16(&fr->data, 0x0001);
    608554
    609         /*
    610          * t(000f) l(0000) v()
    611          */
     555        /* t(000f) l(0000) v() */
    612556        aimbs_put16(&fr->data, 0x000f);
    613557        aimbs_put16(&fr->data, 0x0000);
    614558
    615         /*
    616          * Service Data TLV
    617          */
     559        /* Service Data TLV */
    618560        aimbs_put16(&fr->data, 0x2711);
    619561        aimbs_put16(&fr->data, servdatalen);
     
    648590}
    649591
    650 /* Subtype 0x0006 */
    651 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret)
     592/**
     593 * Subtype 0x0006 - Send an "I want to directly connect to you" message
     594 *
     595 */
     596faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port)
    652597{
    653598        aim_conn_t *conn;
    654         fu8_t ck[8];
    655599        aim_frame_t *fr;
    656600        aim_snacid_t snacid;
     601        fu8_t ck[8];
    657602        aim_tlvlist_t *tl = NULL, *itl = NULL;
    658603        int hdrlen, i;
     
    663608                return -EINVAL;
    664609
    665         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(destsn))))
     610        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(sn))))
    666611                return -ENOMEM;
    667612
     
    675620         * TOC-compatible.
    676621         *
    677          * XXX have I mentioned these should be generated in msgcookie.c?
     622         * XXX - have I mentioned these should be generated in msgcookie.c?
    678623         *
    679624         */
     
    682627        ck[7] = '\0';
    683628
    684         if (ckret)
    685                 memcpy(ckret, ck, 8);
    686 
    687         /* Cookie */
    688         aimbs_putraw(&fr->data, ck, 8);
    689 
    690         /* Channel */
    691         aimbs_put16(&fr->data, 0x0002);
    692 
    693         /* Destination SN */
    694         aimbs_put8(&fr->data, strlen(destsn));
    695         aimbs_putraw(&fr->data, destsn, strlen(destsn));
     629        if (cookie)
     630                memcpy(cookie, ck, 8);
     631
     632        /* ICBM header */
     633        aim_im_puticbm(&fr->data, ck, 0x0002, sn);
    696634
    697635        aim_addtlvtochain_noval(&tl, 0x0003);
     
    703641        aimbs_put16(&hdrbs, 0x0000);
    704642        aimbs_putraw(&hdrbs, ck, 8);
    705         aim_putcap(&hdrbs, AIM_CAPS_IMIMAGE);
     643        aim_putcap(&hdrbs, AIM_CAPS_DIRECTIM);
    706644
    707645        aim_addtlvtochain16(&itl, 0x000a, 0x0001);
     
    725663}
    726664
    727 /* Subtype 0x0006 */
    728 faim_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)
     665/**
     666 * Subtype 0x0006 - Send an "I want to send you this file" message
     667 *
     668 */
     669faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info)
    729670{
    730671        aim_conn_t *conn;
    731         int i;
    732         fu8_t ck[8];
    733672        aim_frame_t *fr;
    734673        aim_snacid_t snacid;
    735         struct aim_snac_destructor snacdest;
    736 
    737         if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     674        aim_tlvlist_t *tl=NULL, *subtl=NULL;
     675        int i;
     676
     677        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
    738678                return -EINVAL;
    739679
    740         if (!sn || !filename)
     680        /* XXX - Should be like "21CBF95" and null terminated */
     681        for (i = 0; i < 7; i++)
     682                oft_info->cookie[i] = 0x30 + ((fu8_t)rand() % 10);
     683        oft_info->cookie[7] = '\0';
     684
     685        { /* Create the subTLV chain */
     686                fu8_t *buf;
     687                int buflen;
     688                aim_bstream_t bs;
     689
     690                aim_addtlvtochain16(&subtl, 0x000a, 0x0001);
     691                aim_addtlvtochain_noval(&subtl, 0x000f);
     692/*              aim_addtlvtochain_raw(&subtl, 0x000e, 2, "en");
     693                aim_addtlvtochain_raw(&subtl, 0x000d, 8, "us-ascii");
     694                aim_addtlvtochain_raw(&subtl, 0x000c, 24, "Please accept this file."); */
     695                if (oft_info->clientip) {
     696                        fu8_t ip[4];
     697                        char *nexttoken;
     698                        int i = 0;
     699                        nexttoken = strtok(oft_info->clientip, ".");
     700                        while (nexttoken && i<4) {
     701                                ip[i] = atoi(nexttoken);
     702                                nexttoken = strtok(NULL, ".");
     703                                i++;
     704                        }
     705                        aim_addtlvtochain_raw(&subtl, 0x0003, 4, ip);
     706                }
     707                aim_addtlvtochain16(&subtl, 0x0005, oft_info->port);
     708
     709                /* TLV t(2711) */
     710                buflen = 2+2+4+strlen(oft_info->fh.name)+1;
     711                buf = malloc(buflen);
     712                aim_bstream_init(&bs, buf, buflen);
     713                aimbs_put16(&bs, (oft_info->fh.totfiles > 1) ? 0x0002 : 0x0001);
     714                aimbs_put16(&bs, oft_info->fh.totfiles);
     715                aimbs_put32(&bs, oft_info->fh.totsize);
     716
     717                /* Filename - NULL terminated, for some odd reason */
     718                aimbs_putraw(&bs, oft_info->fh.name, strlen(oft_info->fh.name));
     719                aimbs_put8(&bs, 0x00);
     720
     721                aim_addtlvtochain_raw(&subtl, 0x2711, bs.len, bs.data);
     722                free(buf);
     723        }
     724
     725        { /* Create the main TLV chain */
     726                fu8_t *buf;
     727                int buflen;
     728                aim_bstream_t bs;
     729
     730                /* TLV t(0005) - Encompasses everything from above. Gee. */
     731                buflen = 2+8+16+aim_sizetlvchain(&subtl);
     732                buf = malloc(buflen);
     733                aim_bstream_init(&bs, buf, buflen);
     734                aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE);
     735                aimbs_putraw(&bs, oft_info->cookie, 8);
     736                aim_putcap(&bs, AIM_CAPS_SENDFILE);
     737                aim_writetlvchain(&bs, &subtl);
     738                aim_freetlvchain(&subtl);
     739                aim_addtlvtochain_raw(&tl, 0x0005, bs.len, bs.data);
     740                free(buf);
     741
     742                /* TLV t(0003) - Request an ack */
     743                aim_addtlvtochain_noval(&tl, 0x0003);
     744        }
     745
     746        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + aim_sizetlvchain(&tl))))
     747                return -ENOMEM;
     748
     749        snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, oft_info->cookie, sizeof(oft_info->cookie));
     750        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
     751
     752        /* ICBM header */
     753        aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
     754
     755        /* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */
     756        aim_writetlvchain(&fr->data, &tl);
     757        aim_freetlvchain(&tl);
     758
     759        aim_tx_enqueue(sess, fr);
     760
     761        return 0;
     762}
     763
     764/**
     765 * Subtype 0x0006 - Send an "I will accept this file" message?
     766 *
     767 * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE)
     768 */
     769faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *oft_info)
     770{
     771        aim_conn_t *conn;
     772        aim_frame_t *fr;
     773        aim_snacid_t snacid;
     774
     775        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
    741776                return -EINVAL;
    742777
    743         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)))
     778        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16)))
    744779                return -ENOMEM;
    745780
    746         for (i = 0; i < 7; i++)
    747                 aimutil_put8(ck+i, 0x30 + ((fu8_t) rand() % 10));
    748         ck[7] = '\0';
    749 
    750         if (ckret)
    751                 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));
     781        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
    761782        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    762783
    763         /*
    764          * Cookie
    765          */
    766         aimbs_putraw(&fr->data, ck, 8);
    767 
    768         /*
    769          * Channel (2)
    770          */
    771         aimbs_put16(&fr->data, 0x0002);
    772 
    773         /*
    774          * Dest sn
    775          */
    776         aimbs_put8(&fr->data, strlen(sn));
    777         aimbs_putraw(&fr->data, sn, strlen(sn));
    778 
    779         /*
    780          * TLV t(0005)
    781          *
    782          * Encompasses everything below. Gee.
    783          */
     784        /* ICBM header */
     785        aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
     786
    784787        aimbs_put16(&fr->data, 0x0005);
    785         aimbs_put16(&fr->data, 2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4);
    786 
    787         aimbs_put16(&fr->data, 0x0000);
    788         aimbs_putraw(&fr->data, ck, 8);
     788        aimbs_put16(&fr->data, 0x001a);
     789        aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT);
     790        aimbs_putraw(&fr->data, oft_info->cookie, 8);
    789791        aim_putcap(&fr->data, AIM_CAPS_SENDFILE);
    790792
    791         /* TLV t(000a) */
    792         aimbs_put16(&fr->data, 0x000a);
    793         aimbs_put16(&fr->data, 0x0002);
    794         aimbs_put16(&fr->data, 0x0001);
    795 
    796         /* TLV t(0003) (IP) */
    797         aimbs_put16(&fr->data, 0x0003);
    798         aimbs_put16(&fr->data, 0x0004);
    799         aimbs_putraw(&fr->data, ip, 4);
    800 
    801         /* TLV t(0005) (port) */
     793        aim_tx_enqueue(sess, fr);
     794
     795        return 0;
     796}
     797
     798/**
     799 * Subtype 0x0006 - Send a "cancel this file transfer" message?
     800 *
     801 */
     802faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info)
     803{
     804        aim_conn_t *conn;
     805        aim_frame_t *fr;
     806        aim_snacid_t snacid;
     807
     808        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
     809                return -EINVAL;
     810
     811        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16)))
     812                return -ENOMEM;
     813
     814        snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
     815        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
     816
     817        /* ICBM header */
     818        aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
     819
    802820        aimbs_put16(&fr->data, 0x0005);
    803         aimbs_put16(&fr->data, 0x0002);
    804         aimbs_put16(&fr->data, port);
    805 
    806         /* TLV t(000f) */
    807         aimbs_put16(&fr->data, 0x000f);
    808         aimbs_put16(&fr->data, 0x0000);
    809 
    810         /* TLV t(2711) */
    811         aimbs_put16(&fr->data, 0x2711);
    812         aimbs_put16(&fr->data, 2+2+4+strlen(filename)+4);
    813 
    814         /* ? */
    815         aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001);
    816         aimbs_put16(&fr->data, numfiles);
    817         aimbs_put32(&fr->data, totsize);
    818         aimbs_putraw(&fr->data, filename, strlen(filename));
    819 
    820         /* ? */
    821         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
     821        aimbs_put16(&fr->data, 0x001a);
     822        aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL);
     823        aimbs_putraw(&fr->data, oft_info->cookie, 8);
     824        aim_putcap(&fr->data, AIM_CAPS_SENDFILE);
    827825
    828826        aim_tx_enqueue(sess, fr);
     
    840838 * @return Return 0 if no errors, otherwise return the error number.
    841839 */
    842 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type)
     840faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type)
    843841{
    844842        aim_conn_t *conn;
     843        aim_frame_t *fr;
     844        aim_snacid_t snacid;
    845845        int i;
    846846        fu8_t ck[8];
    847         aim_frame_t *fr;
    848         aim_snacid_t snacid;
    849847
    850848        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn)
     
    852850
    853851        for (i = 0; i < 8; i++)
    854                 aimutil_put8(ck+i, (fu8_t) rand());
     852                ck[i] = (fu8_t)rand();
    855853
    856854        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4)))
     
    860858        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    861859
    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));
     860        /* ICBM header */
     861        aim_im_puticbm(&fr->data, ck, 0x0002, sn);
    871862
    872863        /* TLV t(0005) - Encompasses almost everything below. */
     
    897888                        aimbs_putle16(&fr->data, 0x001b); /* L */
    898889                        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 */
     890                        aim_putcap(&fr->data, AIM_CAPS_EMPTY);
    903891                        aimbs_putle16(&fr->data, 0x0000); /* Unknown */
    904892                        aimbs_putle16(&fr->data, 0x0003); /* Client features? */
     
    927915                        aimbs_putle16(&fr->data, 0x0000); /* Status? */
    928916                        aimbs_putle16(&fr->data, 0x0001); /* Priority of this message? */
    929                         aimbs_putle16(&fr->data, 0x0001); /* L? */
    930                         aimbs_putle8(&fr->data, 0x00); /* Null termination? */
     917                        aimbs_putle16(&fr->data, 0x0001); /* L */
     918                        aimbs_putle8(&fr->data, 0x00); /* String of length L */
    931919                } /* End TLV t(2711) */
    932920        } /* End TLV t(0005) */
     
    942930
    943931/**
    944  * Subtype 0x0006
     932 * Subtype 0x0006 - Send an ICQ-esque ICBM.
    945933 *
    946934 * This can be used to send an ICQ authorization reply (deny or grant).  It is the "old way." 
     
    955943 * @return Return 0 if no errors, otherwise return the error number.
    956944 */
    957 faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)
     945faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)
    958946{
    959947        aim_conn_t *conn;
     
    961949        aim_snacid_t snacid;
    962950        int i;
     951        char ck[8];
    963952
    964953        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
     
    974963        aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
    975964
    976         /*
    977          * Cookie
    978          */
     965        /* Cookie */
    979966        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));
     967                ck[i] = (fu8_t)rand();
     968
     969        /* ICBM header */
     970        aim_im_puticbm(&fr->data, ck, 0x0004, sn);
    992971
    993972        /*
     
    10221001}
    10231002
     1003/*
     1004 * XXX - I don't see when this would ever get called...
     1005 */
    10241006static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    10251007{
     
    11771159}
    11781160
    1179 /* XXX should provide a way of saying ISO-8859-1 specifically */
     1161/* XXX - should provide a way of saying ISO-8859-1 specifically */
    11801162faim_export int aim_mpmsg_addascii(aim_session_t *sess, aim_mpmsg_t *mpm, const char *ascii)
    11811163{
     
    12801262                 * the specified data length, which will not include the pad.
    12811263                 *
    1282                  * XXX There's an API bug here.  For sending, the UNICODE is
     1264                 * XXX - There's an API bug here.  For sending, the UNICODE is
    12831265                 * given in host byte order (aim_mpmsg_addunicode), but here
    12841266                 * the received messages are given in network byte order.
     
    13131295                        args->charset = sec->charset;
    13141296                        args->charsubset = sec->charsubset;
    1315                         args->icbmflags |= AIM_IMFLAGS_CUSTOMCHARSET;
    13161297
    13171298                        /* Set up the simple flags */
     
    13311312                        else if (args->charsubset == 0xffff)
    13321313                                ; /* no subencoding */
    1333 #if 0
    1334                         /* XXX this isn't really necesary... */
    1335                         if (    ((args.flag1 != 0x0000) &&
    1336                                  (args.flag1 != 0x0002) &&
    1337                                  (args.flag1 != 0x0003) &&
    1338                                  (args.flag1 != 0xffff)) ||
    1339                                 ((args.flag2 != 0x0000) &&
    1340                                  (args.flag2 != 0x000b) &&
    1341                                  (args.flag2 != 0xffff))) {
    1342                                 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2);
    1343                         }
    1344 #endif
    13451314
    13461315                        args->msg = sec->data;
     
    14191388                } else if (type == 0x0006) { /* Message was received offline. */
    14201389
    1421                         /* XXX not sure if this actually gets sent. */
     1390                        /* XXX - not sure if this actually gets sent. */
    14221391                        args.icbmflags |= AIM_IMFLAGS_OFFLINE;
    14231392
     
    15551524{
    15561525
    1557         /* XXX aim_chat_roominfo_free() */
     1526        /* XXX - aim_chat_roominfo_free() */
    15581527        free(args->info.chat.roominfo.name);
    15591528
     
    16161585        aim_bstream_advance(servdata, hdrlen);
    16171586
    1618         /* XXX This is such a hack. */
     1587        /* XXX - This is such a hack. */
    16191588        args->reqclass = AIM_CAPS_ICQRTF;
    16201589
     
    16341603        args->destructor = (void *)incomingim_ch2_sendfile_free;
    16351604
    1636         if (servdata) {
     1605        /* Maybe there is a better way to tell what kind of sendfile
     1606         * this is?  Maybe TLV t(000a)? */
     1607        if (servdata) { /* Someone is sending us a file */
    16371608                int flen;
    16381609
     
    16421613                args->info.sendfile.totsize = aimbs_get32(servdata);
    16431614
    1644                 /* XXX - create an aimbs_getnullstr function */
     1615                /*
     1616                 * I hope to God I'm right when I guess that there is a
     1617                 * 32 char max filename length for single files.  I think
     1618                 * OFT tends to do that.  Gotta love inconsistency.  I saw
     1619                 * a 26 byte filename?
     1620                 */
     1621                /* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */
    16451622                /* Use an inelegant way of getting the null-terminated filename,
    16461623                 * since there's no easy bstream routine. */
     
    16511628                /* There is sometimes more after the null-terminated filename,
    16521629                 * but I'm unsure of its format. */
     1630                /* I don't believe him. */
    16531631        }
    16541632
     
    16681646        int ret = 0;
    16691647
    1670         char clientip1[30] = {""};
    1671         char clientip2[30] = {""};
     1648        char proxyip[30] = {""};
     1649        char clientip[30] = {""};
    16721650        char verifiedip[30] = {""};
    16731651
     
    17111689
    17121690        /*
    1713          * IP address from the perspective of the client.
     1691         * IP address to proxy the file transfer through.
     1692         *
     1693         * XXX - I don't like this.  Maybe just read in an int?  Or inet_ntoa...
    17141694         */
    17151695        if (aim_gettlv(list2, 0x0002, 1)) {
     
    17171697
    17181698                iptlv = aim_gettlv(list2, 0x0002, 1);
    1719 
    1720                 snprintf(clientip1, sizeof(clientip1), "%d.%d.%d.%d",
    1721                                 aimutil_get8(iptlv->value+0),
    1722                                 aimutil_get8(iptlv->value+1),
    1723                                 aimutil_get8(iptlv->value+2),
    1724                                 aimutil_get8(iptlv->value+3));
    1725         }
    1726 
    1727         /*
    1728          * Secondary IP address from the perspective of the client.
     1699                if (iptlv->length == 4)
     1700                        snprintf(proxyip, sizeof(proxyip), "%hhd.%hhd.%hhd.%hhd",
     1701                                iptlv->value[0], iptlv->value[1],
     1702                                iptlv->value[2], iptlv->value[3]);
     1703        }
     1704
     1705        /*
     1706         * IP address from the perspective of the client.
    17291707         */
    17301708        if (aim_gettlv(list2, 0x0003, 1)) {
     
    17321710
    17331711                iptlv = aim_gettlv(list2, 0x0003, 1);
    1734 
    1735                 snprintf(clientip2, sizeof(clientip2), "%d.%d.%d.%d",
    1736                                 aimutil_get8(iptlv->value+0),
    1737                                 aimutil_get8(iptlv->value+1),
    1738                                 aimutil_get8(iptlv->value+2),
    1739                                 aimutil_get8(iptlv->value+3));
     1712                if (iptlv->length == 4)
     1713                        snprintf(clientip, sizeof(clientip), "%hhd.%hhd.%hhd.%hhd",
     1714                                iptlv->value[0], iptlv->value[1],
     1715                                iptlv->value[2], iptlv->value[3]);
    17401716        }
    17411717
     
    17491725
    17501726                iptlv = aim_gettlv(list2, 0x0004, 1);
    1751 
    1752                 snprintf(verifiedip, sizeof(verifiedip), "%d.%d.%d.%d",
    1753                                 aimutil_get8(iptlv->value+0),
    1754                                 aimutil_get8(iptlv->value+1),
    1755                                 aimutil_get8(iptlv->value+2),
    1756                                 aimutil_get8(iptlv->value+3));
     1727                if (iptlv->length == 4)
     1728                        snprintf(verifiedip, sizeof(verifiedip), "%hhd.%hhd.%hhd.%hhd",
     1729                                iptlv->value[0], iptlv->value[1],
     1730                                iptlv->value[2], iptlv->value[3]);
    17571731        }
    17581732
     
    17621736        if (aim_gettlv(list2, 0x0005, 1))
    17631737                args.port = aim_gettlv16(list2, 0x0005, 1);
     1738
     1739        /*
     1740         * Something to do with ft -- two bytes
     1741         * 0x0001 - "I want to send you this file"
     1742         * 0x0002 - "I will accept this file from you"
     1743         */
     1744        if (aim_gettlv(list2, 0x000a, 1))
     1745                ;
    17641746
    17651747        /*
     
    17871769                args.language = aim_gettlv_str(list2, 0x000e, 1);
    17881770
    1789         /* Unknown -- two bytes = 0x0001 */
    1790         if (aim_gettlv(list2, 0x000a, 1))
    1791                 ;
    1792 
    1793         /* Unknown -- no value */
     1771        /*
     1772         * Unknown -- no value
     1773         *
     1774         * Maybe means we should connect directly to transfer the file?
     1775        */
    17941776        if (aim_gettlv(list2, 0x000f, 1))
    17951777                ;
    17961778
    1797         if (strlen(clientip1))
    1798                 args.clientip = (char *)clientip1;
    1799         if (strlen(clientip2))
    1800                 args.clientip2 = (char *)clientip2;
     1779        /*
     1780         * Unknown -- no value
     1781         *
     1782         * Maybe means we should proxy the file transfer through an AIM server?
     1783         */
     1784        if (aim_gettlv(list2, 0x0010, 1))
     1785                ;
     1786
     1787        if (strlen(proxyip))
     1788                args.proxyip = (char *)proxyip;
     1789        if (strlen(clientip))
     1790                args.clientip = (char *)clientip;
    18011791        if (strlen(verifiedip))
    18021792                args.verifiedip = (char *)verifiedip;
    18031793
    18041794        /*
    1805          * This is must be present in PROPOSALs, but will probably not
     1795         * This must be present in PROPOSALs, but will probably not
    18061796         * exist in CANCELs and ACCEPTs.
    18071797         *
     
    18631853
    18641854        args.uin = aimbs_getle32(&meat);
    1865         args.type = aimbs_getle16(&meat);
    1866         args.msg = aimbs_getraw(&meat, aimbs_getle16(&meat));
     1855        args.type = aimbs_getle8(&meat);
     1856        args.flags = aimbs_getle8(&meat);
     1857        args.msglen = aimbs_getle16(&meat);
     1858        args.msg = aimbs_getraw(&meat, args.msglen);
    18671859
    18681860        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     
    19051897         * Channel ID.
    19061898         *
    1907          * Channel 0x0001 is the message channel.  There are
    1908          * other channels for things called "rendevous"
    1909          * which represent chat and some of the other new
    1910          * features of AIM2/3/3.5.
     1899         * Channel 0x0001 is the message channel.  It is
     1900         * used to send basic ICBMs.
    19111901         *
    19121902         * Channel 0x0002 is the Rendevous channel, which
    19131903         * is where Chat Invitiations and various client-client
    19141904         * connection negotiations come from.
     1905         *
     1906         * Channel 0x0003 is used for chat messages.
    19151907         *
    19161908         * Channel 0x0004 is used for ICQ authorization, or
     
    19271919         * userinfo block contains the number of TLVs that contain user
    19281920         * information, the rest are not even though there is no seperation.
    1929          * aim_extractuserinfo() returns the number of bytes used by the
    1930          * userinfo tlvs, so you can start reading the rest of them right
    1931          * afterward. 
     1921         * You can start reading the message TLVs after aim_info_extract()
     1922         * parses out the standard userinfo block.
    19321923         *
    19331924         * That also means that TLV types can be duplicated between the
     
    19361927         *
    19371928         */
    1938         aim_extractuserinfo(sess, bs, &userinfo);
     1929        aim_info_extract(sess, bs, &userinfo);
    19391930
    19401931        /*
     
    19701961
    19711962        } else {
    1972 
    1973                 faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel.  Ignoring.\n (chan = %04x)", channel);
    1974 
    1975                 return 0;
    1976         }
     1963                faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel.  Ignoring.  (chan = %04x)\n", channel);
     1964        }
     1965
     1966        aim_info_free(&userinfo);
    19771967
    19781968        return ret;
     
    19801970
    19811971/*
    1982  * Subtype 0x0008 - Send a warning to destsn.
     1972 * Subtype 0x0008 - Send a warning to sn.
    19831973 *
    19841974 * Flags:
     
    19881978 *
    19891979 */
    1990 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags)
     1980faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu32_t flags)
    19911981{
    19921982        aim_frame_t *fr;
    19931983        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)))
     1984
     1985        if (!sess || !conn || !sn)
     1986                return -EINVAL;
     1987
     1988        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13)))
    19971989                return -ENOMEM;
    19981990
    1999         snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1);
    2000 
     1991        snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
    20011992        aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
    20021993
    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));
     1994        aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
     1995        aimbs_put8(&fr->data, strlen(sn));
     1996        aimbs_putraw(&fr->data, sn, strlen(sn));
    20091997
    20101998        aim_tx_enqueue(sess, fr);
     
    20242012
    20252013                channel = aimbs_get16(bs);
    2026                 aim_extractuserinfo(sess, bs, &userinfo);
     2014                aim_info_extract(sess, bs, &userinfo);
    20272015                nummissed = aimbs_get16(bs);
    20282016                reason = aimbs_get16(bs);
     
    20302018                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    20312019                         ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
     2020
     2021                aim_info_free(&userinfo);
    20322022        }
    20332023
     
    20442034 *
    20452035 */
    2046 faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code)
     2036faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code)
    20472037{
    20482038        aim_conn_t *conn;
     
    20962086
    20972087        if (channel == 0x0002) { /* File transfer declined */
     2088                aimbs_get16(bs); /* Unknown */
     2089                aimbs_get16(bs); /* Unknown */
    20982090                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    20992091                        ret = userfunc(sess, rx, channel, sn, reason, ck);
     
    21592151}
    21602152
    2161 /* Subtype 0x000c */
     2153/*
     2154 * Subtype 0x000c - Receive an ack after sending an ICBM.
     2155 *
     2156 * You have to have send the message with the AIM_IMFLAGS_ACK flag set
     2157 * (TLV t(0003)).  The ack contains the ICBM header of the message you
     2158 * sent.
     2159 *
     2160 */
    21622161static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    21632162{
    21642163        aim_rxcallback_t userfunc;
    2165         fu16_t type;
    2166         fu8_t snlen, *ck;
     2164        fu16_t ch;
     2165        fu8_t *ck;
    21672166        char *sn;
    21682167        int ret = 0;
    21692168
    21702169        ck = aimbs_getraw(bs, 8);
    2171         type = aimbs_get16(bs);
    2172         snlen = aimbs_get8(bs);
    2173         sn = aimbs_getstr(bs, snlen);
     2170        ch = aimbs_get16(bs);
     2171        sn = aimbs_getstr(bs, aimbs_get8(bs));
    21742172
    21752173        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    2176                 ret = userfunc(sess, rx, type, sn);
     2174                ret = userfunc(sess, rx, ch, sn);
    21772175
    21782176        free(sn);
     
    21892187 *
    21902188 */
    2191 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2)
     2189faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2)
    21922190{
    21932191        aim_conn_t *conn;
     
    22702268
    22712269        if (snac->subtype == 0x0005)
    2272                 return paraminfo(sess, mod, rx, snac, bs);
     2270                return aim_im_paraminfo(sess, mod, rx, snac, bs);
    22732271        else if (snac->subtype == 0x0006)
    22742272                return outgoingim(sess, mod, rx, snac, bs);
     
    22872285}
    22882286
    2289 static 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;
    2300 }
    2301 
    23022287faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod)
    23032288{
     
    23062291        mod->version = 0x0001;
    23072292        mod->toolid = 0x0110;
    2308         mod->toolversion = 0x047b;
     2293        mod->toolversion = 0x0629;
    23092294        mod->flags = 0;
    23102295        strncpy(mod->name, "messaging", sizeof(mod->name));
    23112296        mod->snachandler = snachandler;
    2312         mod->snacdestructor = snacdestructor;
    23132297
    23142298        return 0;
  • libfaim/info.c

    r862371b re374dee  
    99#define FAIM_INTERNAL
    1010#include <aim.h>
     11#ifdef _WIN32
     12#include "win32dep.h"
     13#endif
    1114
    1215struct aim_priv_inforeq {
     
    3033 *
    3134 * Gives BOS your profile.
     35 *
     36 * profile_encoding and awaymsg_encoding MUST be set if profile or
     37 * away are set, respectively, and their value may or may not be
     38 * restricted to a few choices.  I am currently aware of:
    3239 *
    33  */
    34 faim_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\""};
     40 * us-ascii             Just that
     41 * unicode-2-0          UCS2-BE
     42 *
     43 * profile_len and awaymsg_len MUST be set similarly, and they MUST
     44 * be the length of their respective strings in bytes.
     45 *
     46 * To get the previous behavior of awaymsg == "" un-setting the away
     47 * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the
     48 * obvious equivalent).
     49 *
     50 */
     51faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn,
     52                                  const char *profile_encoding, const char *profile, const int profile_len,
     53                                  const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len,
     54                                  fu32_t caps)
     55{
     56        static const char defencoding[] = {"text/aolrtf; charset=\"%s\""};
    3757        aim_frame_t *fr;
    3858        aim_tlvlist_t *tl = NULL;
    3959        aim_snacid_t snacid;
     60        char *encoding;
     61
     62        if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) {
     63                return -EINVAL;
     64        }
    4065
    4166        /* Build to packet first to get real length */
    4267        if (profile) {
    43                 aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding);
    44                 aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile);
     68                /* no + 1 here because of %s */
     69                encoding = malloc(strlen(defencoding) + strlen(profile_encoding));
     70                if (encoding == NULL) {
     71                        return -ENOMEM;
     72                }
     73                snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding);
     74                aim_addtlvtochain_raw(&tl, 0x0001, strlen(encoding), encoding);
     75                aim_addtlvtochain_raw(&tl, 0x0002, profile_len, profile);
     76                free(encoding);
    4577        }
    4678
     
    5486         */
    5587        if (awaymsg) {
    56                 if (strlen(awaymsg)) {
    57                         aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding);
    58                         aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg);
     88                if (awaymsg_len) {
     89                        encoding = malloc(strlen(defencoding) + strlen(awaymsg_encoding));
     90                        if (encoding == NULL) {
     91                                return -ENOMEM;
     92                        }
     93                        snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding);
     94                        aim_addtlvtochain_raw(&tl, 0x0003, strlen(encoding), encoding);
     95                        aim_addtlvtochain_raw(&tl, 0x0004, awaymsg_len, awaymsg);
     96                        free(encoding);
    5997                } else
    6098                        aim_addtlvtochain_noval(&tl, 0x0004);
     
    205243
    206244        /*
    207          * Chat is oddball.
    208          */
    209         {AIM_CAPS_CHAT,
    210          {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
    211           0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
    212 
    213         /*
    214          * These are mostly in order.
    215          */
     245         * These are in ascending numerical order.
     246         */
     247        {AIM_CAPS_ICHAT,
     248         {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
     249          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     250
     251        {AIM_CAPS_SECUREIM,
     252         {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
     253          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     254
     255        {AIM_CAPS_HIPTOP,
     256         {0x09, 0x46, 0x13, 0x23, 0x4c, 0x7f, 0x11, 0xd1,
     257          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     258
    216259        {AIM_CAPS_VOICE,
    217260         {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
     
    229272          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
    230273
    231         {AIM_CAPS_IMIMAGE,
     274        {AIM_CAPS_DIRECTIM,
    232275         {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
    233276          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     
    237280          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
    238281
     282        /*
     283         * Windows AIM calls this "Add-ins," which is probably more accurate
     284         */
    239285        {AIM_CAPS_SAVESTOCKS,
    240286         {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
     
    266312          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
    267313
    268         /* from ICQ2002a
    269         {AIM_CAPS_ICQUNKNOWN2,
     314        /*
     315         * Setting this lets AIM users receive messages from ICQ users, and ICQ
     316         * users receive messages from AIM users.  It also lets ICQ users show
     317         * up in buddy lists for AIM users, and AIM users show up in buddy lists
     318         * for ICQ users.  And ICQ privacy/invisibility acts like AIM privacy,
     319         * in that if you add a user to your deny list, you will not be able to
     320         * see them as online (previous you could still see them, but they
     321         * couldn't see you.
     322         */
     323        {AIM_CAPS_INTEROPERATE,
     324         {0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1,
     325          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     326
     327        {AIM_CAPS_ICQUTF8,
    270328         {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1,
    271           0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, */
     329          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     330
     331        {AIM_CAPS_ICQUTF8OLD,
     332         {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
     333          0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
     334
     335        /*
     336         * Chat is oddball.
     337         */
     338        {AIM_CAPS_CHAT,
     339         {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
     340          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
     341
     342        /*
     343        {AIM_CAPS_ICQ2GO,
     344         {0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd,
     345          0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3}},
     346        */
    272347
    273348        {AIM_CAPS_ICQRTF,
    274          {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 
     349         {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
    275350          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}},
    276351
     
    280355          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}}, */
    281356
    282         {AIM_CAPS_ICQUNKNOWN,
    283          {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
    284           0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
     357        {AIM_CAPS_APINFO,
     358         {0xaa, 0x4a, 0x32, 0xb5, 0xf8, 0x84, 0x48, 0xc6,
     359          0xa3, 0xd7, 0x8c, 0x50, 0x97, 0x19, 0xfd, 0x5b}},
     360
     361        {AIM_CAPS_TRILLIANCRYPT,
     362         {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
     363          0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},
    285364
    286365        {AIM_CAPS_EMPTY,
    287366         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    288367          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
    289 
    290         {AIM_CAPS_TRILLIANCRYPT,
    291          {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
    292           0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},
    293 
    294         {AIM_CAPS_APINFO,
    295          {0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6,
    296           0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}},
    297368
    298369        {AIM_CAPS_LAST}
     
    385456}
    386457
     458faim_internal void aim_info_free(aim_userinfo_t *info)
     459{
     460        free(info->iconcsum);
     461        free(info->availmsg_encoding);
     462        free(info->availmsg);
     463}
     464
    387465/*
    388466 * AIM is fairly regular about providing user info.  This is a generic
    389467 * routine to extract it in its standard form.
    390468 */
    391 faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
     469faim_internal int aim_info_extract(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
    392470{
    393471        int curtlv, tlvcnt;
     
    478556                         * Type = 0x0004: Idle time.
    479557                         *
    480                          * Number of seconds since the user actively used the
     558                         * Number of minutes since the user actively used the
    481559                         * service.
    482560                         *
     
    530608                         * apparently a port number, and some Other Stuff.
    531609                         *
     610                         * Format is:
     611                         * 4 bytes - Our IP address, 0xc0 a8 01 2b for 192.168.1.43
     612                         *
     613                         *
    532614                         */
    533615                        aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
     
    570652                        outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;
    571653
     654                } else if (type == 0x0019) {
     655/*                      faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV type 0x0019: from %s\n", outinfo->sn); */
     656
     657                } else if (type == 0x001b) {
     658/*                      faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV type 0x001b: from %s\n", outinfo->sn); */
     659
    572660                } else if (type == 0x001d) {
    573661                        /*
    574                          * Type 29: Unknown.
    575                          *
    576                          * Currently very rare. Always 18 bytes of mostly zero.
    577                          */
     662                         * Type = 0x001d
     663                         *
     664                         * Buddy icon information and available messages.
     665                         *
     666                         * This almost seems like the AIM protocol guys gave
     667                         * the iChat guys a Type, and the iChat guys tried to
     668                         * cram as much cool shit into it as possible.  Then
     669                         * the Windows AIM guys were like, "hey, that's
     670                         * pretty neat, let's copy those prawns."
     671                         *
     672                         * In that spirit, this can contain a custom message,
     673                         * kind of like an away message, but you're not away
     674                         * (it's called an "available" message).  Or it can
     675                         * contain information about the buddy icon the user
     676                         * has stored on the server.
     677                         */
     678                        int type2, number, length2;
     679
     680                        while (aim_bstream_curpos(bs) < endpos) {
     681                                type2 = aimbs_get16(bs);
     682                                number = aimbs_get8(bs);
     683                                length2 = aimbs_get8(bs);
     684
     685                                switch (type2) {
     686                                        case 0x0000: { /* This is an official buddy icon? */
     687                                                /* This is always 5 bytes of "0x02 01 d2 04 72"? */
     688                                                aim_bstream_advance(bs, length2);
     689                                        } break;
     690
     691                                        case 0x0001: { /* A buddy icon checksum */
     692                                                if ((length2 > 0) && (number == 0x01)) {
     693                                                        free(outinfo->iconcsum);
     694                                                        outinfo->iconcsum = aimbs_getraw(bs, length2);
     695                                                        outinfo->iconcsumlen = length2;
     696                                                } else
     697                                                        aim_bstream_advance(bs, length2);
     698                                        } break;
     699
     700                                        case 0x0002: { /* An available message */
     701                                                if (length2 > 4) {
     702                                                        free(outinfo->availmsg);
     703                                                        outinfo->availmsg_len = aimbs_get16(bs);
     704                                                        outinfo->availmsg = aimbs_getstr(bs, outinfo->availmsg_len);
     705                                                        if (aimbs_get16(bs) == 0x0001) { /* We have an encoding */
     706                                                                aimbs_get16(bs);
     707                                                                outinfo->availmsg_encoding = aimbs_getstr(bs, aimbs_get16(bs));
     708                                                        } else {
     709                                                                /* No explicit encoding, client should use UTF-8 */
     710                                                                outinfo->availmsg_encoding = NULL;
     711                                                        }
     712                                                } else
     713                                                        aim_bstream_advance(bs, length2);
     714                                        } break;
     715
     716                                        default: {
     717                                                aim_bstream_advance(bs, length2);
     718                                        } break;
     719                                }
     720                        }
    578721
    579722                } else if (type == 0x001e) {
     
    607750
    608751/*
    609  * Inverse of aim_extractuserinfo()
     752 * Inverse of aim_info_extract()
    610753 */
    611754faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info)
     
    713856        aim_userinfo_t userinfo;
    714857        char *text_encoding = NULL, *text = NULL;
     858        int textlen = 0;
    715859        aim_rxcallback_t userfunc;
    716860        aim_tlvlist_t *tlvlist;
     861        aim_tlv_t *text_tlv = NULL;
    717862        aim_snac_t *origsnac = NULL;
    718863        struct aim_priv_inforeq *inforeq;
     
    735880        }
    736881
    737         aim_extractuserinfo(sess, bs, &userinfo);
     882        aim_info_extract(sess, bs, &userinfo);
    738883
    739884        tlvlist = aim_readtlvchain(bs);
     
    748893        if (inforeq->infotype == AIM_GETINFO_GENERALINFO) {
    749894                text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
    750                 text = aim_gettlv_str(tlvlist, 0x0002, 1);
     895                text_tlv = aim_gettlv(tlvlist, 0x0002, 1);
    751896        } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) {
    752897                text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
    753                 text = aim_gettlv_str(tlvlist, 0x0004, 1);
     898                text_tlv = aim_gettlv(tlvlist, 0x0004, 1);
    754899        } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) {
    755900                aim_tlv_t *ct;
     
    765910        }
    766911
     912        if (text_tlv) {
     913                text = text_tlv->value;
     914                textlen = text_tlv->length;
     915        }
     916
    767917        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    768                 ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text);
    769 
     918                ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, textlen);
     919
     920        aim_info_free(&userinfo);
    770921        free(text_encoding);
    771         free(text);
    772 
    773922        aim_freetlvchain(&tlvlist);
    774 
    775923        if (origsnac)
    776924                free(origsnac->data);
     
    8871035        mod->family = 0x0002;
    8881036        mod->version = 0x0001;
    889         mod->toolid = 0x0101;
    890         mod->toolversion = 0x047b;
     1037        mod->toolid = 0x0110;
     1038        mod->toolversion = 0x0629;
    8911039        mod->flags = 0;
    8921040        strncpy(mod->name, "locate", sizeof(mod->name));
  • libfaim/invite.c

    r862371b re374dee  
    2626        mod->version = 0x0001;
    2727        mod->toolid = 0x0110;
    28         mod->toolversion = 0x047b;
     28        mod->toolversion = 0x0629;
    2929        mod->flags = 0;
    3030        strncpy(mod->name, "invite", sizeof(mod->name));
  • libfaim/meta.c

    r862371b re374dee  
    3535}
    3636
     37#if 0
    3738faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...)
    3839{
     
    5556}
    5657
     58#endif
  • libfaim/msgcookie.c

    r862371b re374dee  
    132132
    133133#if 0 /* debugging feature */
    134 faim_internal int aim_dumpcookie(aim_msgcookie_t *cookie)
     134faim_internal int aim_dumpcookie(aim_session_t *sess, aim_msgcookie_t *cookie)
    135135{
    136136
     
    138138                return -EINVAL;
    139139
    140         printf("\tCookie at %p: %d/%s with %p, next %p\n",
    141                         cookie, cookie->type, cookie->cookie,
    142                         cookie->data, cookie->next);
     140        faimdprintf(sess, 0, "\tCookie at %p: %d/%s with %p, next %p\n", cookie,
     141                        cookie->type, cookie->cookie, cookie->data, cookie->next);
    143142
    144143        return 0;
     
    186185        case AIM_CAPS_BUDDYICON: return AIM_COOKIETYPE_OFTICON;
    187186        case AIM_CAPS_VOICE: return AIM_COOKIETYPE_OFTVOICE;
    188         case AIM_CAPS_IMIMAGE: return AIM_COOKIETYPE_OFTIMAGE;
     187        case AIM_CAPS_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE;
    189188        case AIM_CAPS_CHAT: return AIM_COOKIETYPE_CHAT;
    190189        case AIM_CAPS_GETFILE: return AIM_COOKIETYPE_OFTGET;
  • libfaim/newsearch.c

    r862371b re374dee  
    160160static int parseresults(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    161161{
     162#if 0
    162163        aim_rxcallback_t userfunc;
    163164        fu16_t tmp, numresults;
     
    217218                free(del);
    218219        }
    219 
     220#endif
    220221        return 0;
    221222}
  • libfaim/rxhandlers.c

    r862371b re374dee  
    1515        fu16_t type;
    1616        aim_rxcallback_t handler;
    17         u_short flags;
     17        fu16_t flags;
    1818        struct aim_rxcblist_s *next;
    1919};
     
    108108        snac.flags = aimbs_get16(&rx->data);
    109109        snac.id = aimbs_get32(&rx->data);
     110
     111        /* SNAC flags are apparently uniform across all SNACs, so we handle them here */
     112        if (snac.flags & 0x0001) {
     113                /*
     114                 * This means the SNAC will be followed by another SNAC with
     115                 * related information.  We don't need to do anything about
     116                 * this here.
     117                 */
     118        }
     119        if (snac.flags & 0x8000) {
     120                /*
     121                 * This packet contains the version of the family that this SNAC is
     122                 * in.  You get this when your SSI module is version 2 or higher. 
     123                 * For now we have no need for this, but you could always save
     124                 * it as a part of aim_modnsac_t, or something.  The format is...
     125                 * 2 byte length of total mini-header (which is 6 bytes), then TLV
     126                 * of  type 0x0001, length 0x0002, value is the 2 byte version
     127                 * number
     128                 */
     129                aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
     130        }
    110131
    111132        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
     
    371392}
    372393
    373 /*
    374  * Some SNACs we do not allow to be hooked, for good reason.
    375  */
    376 static int checkdisallowed(fu16_t group, fu16_t type)
    377 {
    378         static const struct {
    379                 fu16_t group;
    380                 fu16_t type;
    381         } dontuse[] = {
    382                 {0x0001, 0x0002},
    383                 {0x0001, 0x0003},
    384                 {0x0001, 0x0006},
    385                 {0x0001, 0x0007},
    386                 {0x0001, 0x0008},
    387                 {0x0001, 0x0017},
    388                 {0x0001, 0x0018},
    389                 {0x0000, 0x0000}
    390         };
    391         int i;
    392 
    393         for (i = 0; dontuse[i].group != 0x0000; i++) {
    394                 if ((dontuse[i].group == group) && (dontuse[i].type == type))
    395                         return 1;
    396         }
    397 
    398         return 0;
    399 }
    400 
    401394faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags)
    402395{
     
    407400
    408401        faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
    409 
    410         if (checkdisallowed(family, type)) {
    411                 faimdprintf(sess, 0, "aim_conn_addhandler: client tried to hook %x/%x -- BUG!!!\n", family, type);
    412                 return -1;
    413         }
    414402
    415403        if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
     
    529517                        continue;
    530518
    531                 /*
    532                  * This is a debugging/sanity check only and probably
    533                  * could/should be removed for stable code.
    534                  */
    535                 if (((cur->hdrtype == AIM_FRAMETYPE_OFT) &&
    536                    (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
    537                   ((cur->hdrtype == AIM_FRAMETYPE_FLAP) &&
    538                    (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
    539                         faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type);
    540                         cur->handled = 1;
    541                         continue;
    542                 }
    543 
    544                 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
    545                         if (cur->hdrtype != AIM_FRAMETYPE_OFT) {
    546                                 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
    547                                 cur->handled = 1; /* get rid of it */
    548                         } else {
     519                if (cur->hdrtype == AIM_FRAMETYPE_FLAP) {
     520                        if (cur->hdr.flap.type == 0x01) {
     521                                cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
     522                                continue;
     523
     524                        } else if (cur->hdr.flap.type == 0x02) {
     525                                if ((cur->handled = consumesnac(sess, cur)))
     526                                        continue;
     527
     528                        } else if (cur->hdr.flap.type == 0x04) {
     529                                cur->handled = negchan_middle(sess, cur);
     530                                continue;
     531
     532                        } else if (cur->hdr.flap.type == 0x05) {
     533
     534                        }
     535
     536                } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
     537                        if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
    549538                                aim_rxdispatch_rendezvous(sess, cur);
    550539                                cur->handled = 1;
     540                                continue;
     541
     542                        } else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) {
     543                                /* not possible */
     544                                faimdprintf(sess, 0, "rxdispatch called on LISTENER connection!\n");
     545                                cur->handled = 1;
     546                                continue;
    551547                        }
    552                         continue;
    553548                }
    554549
    555                 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
    556                         /* not possible */
    557                         faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
    558                         cur->handled = 1;
    559                         continue;
    560                 }
    561 
    562                 if (cur->hdr.flap.type == 0x01) {
    563                        
    564                         cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
    565                        
    566                         continue;
    567                        
    568                 } else if (cur->hdr.flap.type == 0x02) {
    569 
    570                         if ((cur->handled = consumesnac(sess, cur)))
    571                                 continue;
    572 
    573                 } else if (cur->hdr.flap.type == 0x04) {
    574 
    575                         cur->handled = negchan_middle(sess, cur);
    576                         continue;
    577 
    578                 } else if (cur->hdr.flap.type == 0x05)
    579                         ;
    580                
    581550                if (!cur->handled) {
    582551                        consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
  • libfaim/rxqueue.c

    r862371b re374dee  
    8383 * Read a FLAP header from conn into fr, and return the number of bytes in the payload.
    8484 */
    85 static faim_shortfunc int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
     85static int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
    8686{
    8787        fu8_t flaphdr_raw[6];
     
    165165
    166166        if (!sess || !conn)
    167                 return -1;
     167                return -EINVAL;
    168168
    169169        if (conn->fd == -1)
     
    177177
    178178        if (!(newrx = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1)))
    179                 return -1;
     179                return -ENOMEM;
    180180
    181181        /*
     
    183183         * function will break on them.
    184184         */
    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);
     185        if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
     186                int ret = aim_get_command_rendezvous(sess, conn, newrx);
     187
     188                if (ret < 0) {
     189                        free(newrx);
     190                        return -1;
     191                }
     192
     193                payloadlen = ret;
     194        } else if (conn->type == AIM_CONN_TYPE_LISTENER) {
     195                faimdprintf(sess, 0, "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd);
    189196                free(newrx);
    190197                return -1;
  • libfaim/search.c

    r862371b re374dee  
    4141 *
    4242 */
    43 faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address)
     43faim_export int aim_search_address(aim_session_t *sess, aim_conn_t *conn, const char *address)
    4444{
    4545        aim_frame_t *fr;
     
    123123        mod->version = 0x0001;
    124124        mod->toolid = 0x0110;
    125         mod->toolversion = 0x047b;
     125        mod->toolversion = 0x0629;
    126126        mod->flags = 0;
    127127        strncpy(mod->name, "search", sizeof(mod->name));
  • libfaim/service.c

    r862371b re374dee  
    120120        redir.group = aim_gettlv16(tlvlist, 0x000d, 1);
    121121        redir.ip = aim_gettlv_str(tlvlist, 0x0005, 1);
     122        redir.cookielen = aim_gettlv(tlvlist, 0x0006, 1)->length;
    122123        redir.cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
    123124
     
    392393static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    393394{
     395        int ret = 0;
    394396        aim_rxcallback_t userfunc;
    395397        fu16_t code, rateclass;
     
    408410
    409411        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    410                 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
    411 
    412         return 0;
     412                ret = userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
     413
     414        return ret;
    413415}
    414416
     
    429431static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    430432{
     433        int ret = 0;
    431434        aim_rxcallback_t userfunc;
    432435
    433436        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    434                 return userfunc(sess, rx);
    435 
    436         return 0;
     437                ret = userfunc(sess, rx);
     438
     439        return ret;
    437440}
    438441
     
    477480static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    478481{
     482        int ret = 0;
    479483        aim_rxcallback_t userfunc;
    480484
    481485        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    482                 return userfunc(sess, rx);
    483 
    484         return 0;
     486                ret = userfunc(sess, rx);
     487
     488        return ret;
    485489}
    486490
     
    494498static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    495499{
     500        int ret = 0;
    496501        aim_rxcallback_t userfunc;
    497502        aim_userinfo_t userinfo;
    498503
    499         aim_extractuserinfo(sess, bs, &userinfo);
     504        aim_info_extract(sess, bs, &userinfo);
    500505
    501506        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    502                 return userfunc(sess, rx, &userinfo);
    503 
    504         return 0;
     507                ret = userfunc(sess, rx, &userinfo);
     508
     509        aim_info_free(&userinfo);
     510
     511        return ret;
    505512}
    506513
     
    508515static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    509516{
     517        int ret = 0;
    510518        aim_rxcallback_t userfunc;
    511519        fu16_t newevil;
     
    517525
    518526        if (aim_bstream_empty(bs))
    519                 aim_extractuserinfo(sess, bs, &userinfo);
     527                aim_info_extract(sess, bs, &userinfo);
    520528
    521529        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    522                 return userfunc(sess, rx, newevil, &userinfo);
    523 
    524         return 0;
     530                ret = userfunc(sess, rx, newevil, &userinfo);
     531
     532        aim_info_free(&userinfo);
     533
     534        return ret;
    525535}
    526536
     
    725735
    726736/*
    727  * Subtype 0x001e - Set Extended Status
    728  *
    729  * Currently only works if using ICQ.
    730  *
    731  */
    732 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status)
    733 {
     737 * Subtype 0x001e - Extended Status
     738 *
     739 * Sets your ICQ status (available, away, do not disturb, etc.)
     740 *
     741 * These are the same TLVs seen in user info.  You can
     742 * also set 0x0008 and 0x000c.
     743 */
     744faim_export int aim_setextstatus(aim_session_t *sess, fu32_t status)
     745{
     746        aim_conn_t *conn;
    734747        aim_frame_t *fr;
    735748        aim_snacid_t snacid;
     
    737750        fu32_t data;
    738751
    739         data = 0x00030000 | status; /* yay for error checking ;^) */
     752        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
     753                return -EINVAL;
     754
     755        data = AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_WEBAWARE | status; /* yay for error checking ;^) */
    740756
    741757        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8)))
     
    749765        aim_freetlvchain(&tl);
    750766       
     767        aim_tx_enqueue(sess, fr);
     768
     769        return 0;
     770}
     771
     772/*
     773 * Subtype 0x001e - Extended Status.
     774 *
     775 * Sets your "available" message.  This is currently only supported by iChat
     776 * and Gaim.
     777 *
     778 * These are the same TLVs seen in user info.  You can
     779 * also set 0x0008 and 0x000c.
     780 */
     781faim_export int aim_srv_setavailmsg(aim_session_t *sess, char *msg)
     782{
     783        aim_conn_t *conn;
     784        aim_frame_t *fr;
     785        aim_snacid_t snacid;
     786
     787        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0001)))
     788                return -EINVAL;
     789
     790        if (msg) {
     791                if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + strlen(msg) + 8)))
     792                        return -ENOMEM;
     793
     794                snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
     795                aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
     796
     797                aimbs_put16(&fr->data, 0x001d);
     798                aimbs_put16(&fr->data, strlen(msg)+8);
     799                aimbs_put16(&fr->data, 0x0002);
     800                aimbs_put8(&fr->data, 0x04);
     801                aimbs_put8(&fr->data, strlen(msg)+4);
     802                aimbs_put16(&fr->data, strlen(msg));
     803                aimbs_putraw(&fr->data, msg, strlen(msg));
     804                aimbs_put16(&fr->data, 0x0000);
     805        } else {
     806                if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + 8)))
     807                        return -ENOMEM;
     808
     809                snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
     810                aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
     811
     812                aimbs_put16(&fr->data, 0x001d);
     813                aimbs_put16(&fr->data, 0x0008);
     814                aimbs_put16(&fr->data, 0x0002);
     815                aimbs_put16(&fr->data, 0x0404);
     816                aimbs_put16(&fr->data, 0x0000);
     817                aimbs_put16(&fr->data, 0x0000);
     818        }
     819
    751820        aim_tx_enqueue(sess, fr);
    752821
     
    794863static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    795864{
     865        int ret = 0;
    796866        aim_rxcallback_t userfunc;
    797867        fu32_t offset, len;
     
    808878
    809879        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    810                 return userfunc(sess, rx, offset, len, modname);
     880                ret = userfunc(sess, rx, offset, len, modname);
    811881
    812882        free(modname);
    813883        aim_freetlvchain(&list);
    814884
    815         return 0;
     885        return ret;
    816886}
    817887
     
    924994
    925995        return 0;
     996}
     997
     998/*
     999 * Subtype 0x0021 - Receive our extended status
     1000 *
     1001 * This is used for iChat's "available" messages, and maybe ICQ extended
     1002 * status messages?  It's also used to tell the client whether or not it
     1003 * needs to upload an SSI buddy icon... who engineers this stuff, anyway?
     1004 */
     1005static int aim_parse_extstatus(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1006{
     1007        int ret = 0;
     1008        aim_rxcallback_t userfunc;
     1009        fu16_t type;
     1010        fu8_t flags, length;
     1011
     1012        type = aimbs_get16(bs);
     1013        flags = aimbs_get8(bs);
     1014        length = aimbs_get8(bs);
     1015
     1016        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
     1017                switch (type) {
     1018                case 0x0000:
     1019                case 0x0001: { /* buddy icon checksum */
     1020                        /* not sure what the difference between 1 and 0 is */
     1021                        fu8_t *md5 = aimbs_getraw(bs, length);
     1022                        ret = userfunc(sess, rx, type, flags, length, md5);
     1023                        free(md5);
     1024                        } break;
     1025                case 0x0002: { /* available message */
     1026                        /* there is a second length that is just for the message */
     1027                        char *msg = aimbs_getstr(bs, aimbs_get16(bs));
     1028                        ret = userfunc(sess, rx, msg);
     1029                        free(msg);
     1030                        } break;
     1031                }
     1032        }
     1033
     1034        return ret;
    9261035}
    9271036
     
    9531062        else if (snac->subtype == 0x001f)
    9541063                return memrequest(sess, mod, rx, snac, bs);
     1064        else if (snac->subtype == 0x0021)
     1065                return aim_parse_extstatus(sess, mod, rx, snac, bs);
    9551066
    9561067        return 0;
     
    9631074        mod->version = 0x0003;
    9641075        mod->toolid = 0x0110;
    965         mod->toolversion = 0x047b;
     1076        mod->toolversion = 0x0629;
    9661077        mod->flags = 0;
    9671078        strncpy(mod->name, "general", sizeof(mod->name));
  • libfaim/snac.c

    r862371b re374dee  
    9191                        *prev = cur->next;
    9292                        if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) {
    93                                 struct aim_snac_destructor *asd = cur->data;
    94                                 cur->data = asd->data;
    95                                 free(asd);
     93                                free(cur->data);
     94                                cur->data = NULL;
    9695                        }
    9796                        return cur;
     
    103102}
    104103
    105 /* Free a SNAC, and call the appropriate destructor if necessary.
    106  */
    107 faim_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 
    138 
    139104/*
    140105 * This is for cleaning up old SNACs that either don't get replies or
     
    144109 *
    145110 */
    146 faim_internal void aim_cleansnacs(aim_session_t *sess, int maxage)
     111faim_export void aim_cleansnacs(aim_session_t *sess, int maxage)
    147112{
    148113        int i;
     
    162127                                *prev = cur->next;
    163128
    164                                 aim_cleansnac(sess, cur);
     129                                free(cur->data);
     130                                free(cur);
    165131                        } else
    166132                                prev = &cur->next;
  • libfaim/ssi.c

    r862371b re374dee  
    11/*
    2  * Server-Side/Stored Information.
    3  *
    4  * Relatively new facility that allows storing of certain types of information,
    5  * such as a users buddy list, permit/deny list, and permit/deny preferences,
    6  * to be stored on the server, so that they can be accessed from any client.
    7  *
    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.
     2 * Family 0x0013 - Server-Side/Stored Information.
     3 *
     4 * Relatively new facility that allows certain types of information, such as
     5 * a user's buddy list, permit/deny list, and permit/deny preferences, to be
     6 * stored on the server, so that they can be accessed from any client.
     7 *
     8 * We keep 2 copies of SSI data:
     9 * 1) An exact copy of what is stored on the AIM servers.
     10 * 2) A local copy that we make changes to, and then send diffs
     11 *    between this and the exact copy to keep them in sync.
     12 *
     13 * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list
     14 * that is given to them (i.e. they don't send SNACs).
    1115 *
    1216 * The SNAC sending and receiving functions are lower down in the file, and
     
    1822 * You don't know the half of it.
    1923 *
    20  * XXX - Test for memory leaks
    21  * XXX - Better parsing of rights, and use the rights info to limit adds
     24 * XXX - Preserve unknown data in TLV lists
    2225 *
    2326 */
     
    2730
    2831/**
     32 * Locally rebuild the 0x00c8 TLV in the additional data of the given group.
     33 *
     34 * @param list A pointer to a pointer to the current list of items.
     35 * @param name A null terminated string containing the group name, or NULL
     36 *        if you want to modify the master group.
     37 * @return Return a pointer to the modified item.
     38 */
     39static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name)
     40{
     41        int newlen;
     42        struct aim_ssi_item *cur, *group;
     43
     44        if (!list)
     45                return NULL;
     46
     47        /* Find the group */
     48        if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP)))
     49                return NULL;
     50
     51        /* Free the old data */
     52        aim_freetlvchain(&group->data);
     53        group->data = NULL;
     54
     55        /* Find the length for the new additional data */
     56        newlen = 0;
     57        if (group->gid == 0x0000) {
     58                for (cur=list; cur; cur=cur->next)
     59                        if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
     60                                newlen += 2;
     61        } else {
     62                for (cur=list; cur; cur=cur->next)
     63                        if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     64                                newlen += 2;
     65        }
     66
     67        /* Build the new TLV list */
     68        if (newlen > 0) {
     69                fu8_t *newdata;
     70
     71                if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t))))
     72                        return NULL;
     73                newlen = 0;
     74                if (group->gid == 0x0000) {
     75                        for (cur=list; cur; cur=cur->next)
     76                                if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
     77                                                newlen += aimutil_put16(newdata+newlen, cur->gid);
     78                } else {
     79                        for (cur=list; cur; cur=cur->next)
     80                                if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     81                                                newlen += aimutil_put16(newdata+newlen, cur->bid);
     82                }
     83                aim_addtlvtochain_raw(&group->data, 0x00c8, newlen, newdata);
     84
     85                free(newdata);
     86        }
     87
     88        return group;
     89}
     90
     91/**
    2992 * Locally add a new item to the given item list.
    3093 *
    3194 * @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).
    3495 * @param name A null terminated string of the name of the new item, or NULL if the
    3596 *        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  */
    39 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, const char *name, fu16_t type)
     97 * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something.
     98 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something.
     99 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc.
     100 * @param data The additional data for the new item.
     101 * @return A pointer to the newly created item.
     102 */
     103static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, fu16_t gid, fu16_t bid, fu16_t type, aim_tlvlist_t *data)
    40104{
    41105        int i;
    42         struct aim_ssi_item *cur, *newitem;
    43 
    44         if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
     106        struct aim_ssi_item *cur, *new;
     107
     108        if (!list)
     109                return NULL;
     110
     111        if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
    45112                return NULL;
    46113
    47114        /* Set the name */
    48115        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);
     116                new->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     117                strcpy(new->name, name);
    54118        } else
    55                 newitem->name = NULL;
    56 
    57         /* Set the group ID# and the buddy ID# */
    58         newitem->gid = 0x0000;
    59         newitem->bid = 0x0000;
     119                new->name = NULL;
     120
     121        /* Set the group ID# and buddy ID# */
     122        new->gid = gid;
     123        new->bid = bid;
    60124        if (type == AIM_SSI_TYPE_GROUP) {
    61                 if (name)
     125                if ((new->gid == 0xFFFF) && name) {
    62126                        do {
    63                                 newitem->gid += 0x0001;
     127                                new->gid += 0x0001;
    64128                                for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
    65                                         if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid))
     129                                        if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid))
    66130                                                i=1;
    67131                        } while (i);
     132                }
    68133        } 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.
     134                if (new->bid == 0xFFFF) {
     135                        do {
     136                                new->bid += 0x0001;
     137                                for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
     138                                        if ((cur->bid == new->bid) && (cur->gid == new->gid))
     139                                                i=1;
     140                        } while (i);
     141                }
     142        }
     143
     144        /* Set the type */
     145        new->type = type;
     146
     147        /* Set the TLV list */
     148        new->data = aim_tlvlist_copy(data);
     149
     150        /* Add the item to the list in the correct numerical position.  Fancy, eh? */
     151        if (*list) {
     152                if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) {
     153                        new->next = *list;
     154                        *list = new;
     155                } else {
     156                        struct aim_ssi_item *prev;
     157                        for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next);
     158                        new->next = prev->next;
     159                        prev->next = new;
     160                }
     161        } else {
     162                new->next = *list;
     163                *list = new;
     164        }
     165
     166        return new;
     167}
     168
     169/**
     170 * Locally delete an item from the given item list.
    90171 *
    91172 * @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.
     173 * @param del A pointer to the item you want to remove from the list.
    93174 * @return Return 0 if no errors, otherwise return the error number.
    94175 */
    95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup)
    96 {
    97         int newlen;
     176static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del)
     177{
     178        if (!list || !(*list) || !del)
     179                return -EINVAL;
     180
     181        /* Remove the item from the list */
     182        if (*list == del) {
     183                *list = (*list)->next;
     184        } else {
     185                struct aim_ssi_item *cur;
     186                for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next);
     187                if (cur->next)
     188                        cur->next = cur->next->next;
     189        }
     190
     191        /* Free the deleted item */
     192        free(del->name);
     193        aim_freetlvchain(&del->data);
     194        free(del);
     195
     196        return 0;
     197}
     198
     199/**
     200 * Compare two items to see if they have the same data.
     201 *
     202 * @param cur1 A pointer to a pointer to the first item.
     203 * @param cur2 A pointer to a pointer to the second item.
     204 * @return Return 0 if no differences, or a number if there are differences.
     205 */
     206static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2)
     207{
     208        if (!cur1 || !cur2)
     209                return 1;
     210
     211        if (cur1->data && !cur2->data)
     212                return 2;
     213
     214        if (!cur1->data && cur2->data)
     215                return 3;
     216
     217        if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data)))
     218                        return 4;
     219
     220        if (cur1->name && !cur2->name)
     221                return 5;
     222
     223        if (!cur1->name && cur2->name)
     224                return 6;
     225
     226        if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name))
     227                return 7;
     228
     229        if (cur1->gid != cur2->gid)
     230                return 8;
     231
     232        if (cur1->bid != cur2->bid)
     233                return 9;
     234
     235        if (cur1->type != cur2->type)
     236                return 10;
     237
     238        return 0;
     239}
     240
     241faim_export int aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item)
     242{
    98243        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  */
    148 static 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 
     244        for (cur=list; cur; cur=cur->next)
     245                if (cur == item)
     246                        return 1;
    165247        return 0;
    166248}
     
    208290                        }
    209291
    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)))
     292        } else if (gn) { /* For finding groups */
     293                for (cur=list; cur; cur=cur->next) {
     294                        if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) {
    213295                                return cur;
     296                        }
     297                }
     298
     299        } else if (sn) { /* For finding permits, denies, and ignores */
     300                for (cur=list; cur; cur=cur->next) {
     301                        if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
     302                                return cur;
     303                        }
     304                }
    214305
    215306        /* For stuff without names--permit deny setting, visibility mask, etc. */
    216307        } else for (cur=list; cur; cur=cur->next) {
    217                 if (cur->type == type)
     308                if ((cur->type == type) && (!cur->name))
    218309                        return cur;
    219310        }
    220311
     312        return NULL;
     313}
     314
     315/**
     316 * Check if the given buddy exists in any group in the buddy list.
     317 *
     318 * @param list A pointer to the current list of items.
     319 * @param sn The group name of the desired item.
     320 * @return Return a pointer to the name of the item if found, else return NULL;
     321 */
     322faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn)
     323{
     324        struct aim_ssi_item *cur;
     325        if (!list || !sn)
     326                return NULL;
     327        for (cur=list; cur; cur=cur->next)
     328                if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn)))
     329                        return cur;
    221330        return NULL;
    222331}
     
    227336 * @param list A pointer to the current list of items.
    228337 * @param bn The buddy name of the desired item.
    229  * @return Return a pointer to the item if found, else return NULL;
    230  */
    231 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn)
     338 * @return Return a pointer to the name of the item if found, else return NULL;
     339 */
     340faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn)
    232341{
    233342        struct aim_ssi_item *cur, *curg;
    234343        if (!list || !sn)
    235344                return NULL;
    236         if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY)))
     345        if (!(cur = aim_ssi_itemlist_exists(list, sn)))
    237346                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;
     347        if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
     348                return NULL;
     349        return curg->name;
    242350}
    243351
     
    285393
    286394/**
    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.
     395 * Locally find the alias of the given buddy.
     396 *
     397 * @param list A pointer to the current list of items.
     398 * @param gn The group of the buddy.
     399 * @param sn The name of the buddy.
     400 * @return A pointer to a NULL terminated string that is the buddies
     401 *         alias, or NULL if the buddy has no alias.  You should free
     402 *         this returned value!
     403 */
     404faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
     405{
     406        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
     407        if (cur) {
     408                aim_tlvlist_t *tlvlist = cur->data;
     409                if (tlvlist) {
     410                        aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x0131, 1);
     411                        if (tlv && tlv->length) {
     412                                char *alias = (char *)malloc((tlv->length+1)*sizeof(char));
     413                                strncpy(alias, tlv->value, tlv->length);
     414                                alias[tlv->length] = 0;
     415                                return alias;
     416                        }
     417                }
     418        }
     419        return NULL;
     420}
     421
     422/**
     423 * Locally find if you are waiting for authorization for a buddy.
     424 *
     425 * @param list A pointer to the current list of items.
     426 * @param gn The group of the buddy.
     427 * @param sn The name of the buddy.
     428 * @return A pointer to a NULL terminated string that is the buddies
     429 *         alias, or NULL if the buddy has no alias.  You should free
     430 *         this returned value!
     431 */
     432faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn)
     433{
     434        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
     435        if (cur) {
     436                aim_tlvlist_t *tlvlist = cur->data;
     437                if (tlvlist)
     438                        if (aim_gettlv(tlvlist, 0x0066, 1))
     439                                return 1;
     440        }
     441        return 0;
     442}
     443
     444/**
     445 * If there are changes, then create temporary items and
     446 * call addmoddel.
    290447 *
    291448 * @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.
    294449 * @return Return 0 if no errors, otherwise return the error number.
    295450 */
    296 static 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.
     451static int aim_ssi_sync(aim_session_t *sess)
     452{
     453        struct aim_ssi_item *cur1, *cur2;
     454        struct aim_ssi_tmp *cur, *new;
     455
     456        if (!sess)
     457                return -EINVAL;
     458
     459        /* If we're waiting for an ack, we shouldn't do anything else */
     460        if (sess->ssi.waiting_for_ack)
     461                return 0;
     462
     463        /*
     464         * Compare the 2 lists and create an aim_ssi_tmp for each difference. 
     465         * We should only send either additions, modifications, or deletions
     466         * before waiting for an acknowledgement.  So first do deletions, then
     467         * additions, then modifications.  Also, both the official and the local
     468         * list should be in ascending numerical order for the group ID#s and the
     469         * buddy ID#s, which makes things more efficient.  I think.
     470         */
     471
     472        /* Additions */
     473        if (!sess->ssi.pending) {
     474                for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
     475                        if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) {
     476                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     477                                new->action = AIM_CB_SSI_ADD;
     478                                new->ack = 0xffff;
     479                                new->name = NULL;
     480                                new->item = cur1;
     481                                new->next = NULL;
     482                                if (sess->ssi.pending) {
     483                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     484                                        cur->next = new;
     485                                } else
     486                                        sess->ssi.pending = new;
     487                        }
     488                }
     489        }
     490
     491        /* Deletions */
     492        if (!sess->ssi.pending) {
     493                for (cur1=sess->ssi.official; cur1; cur1=cur1->next) {
     494                        if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) {
     495                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     496                                new->action = AIM_CB_SSI_DEL;
     497                                new->ack = 0xffff;
     498                                new->name = NULL;
     499                                new->item = cur1;
     500                                new->next = NULL;
     501                                if (sess->ssi.pending) {
     502                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     503                                        cur->next = new;
     504                                } else
     505                                        sess->ssi.pending = new;
     506                        }
     507                }
     508        }
     509
     510        /* Modifications */
     511        if (!sess->ssi.pending) {
     512                for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
     513                        cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid);
     514                        if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
     515                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     516                                new->action = AIM_CB_SSI_MOD;
     517                                new->ack = 0xffff;
     518                                new->name = NULL;
     519                                new->item = cur1;
     520                                new->next = NULL;
     521                                if (sess->ssi.pending) {
     522                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     523                                        cur->next = new;
     524                                } else
     525                                        sess->ssi.pending = new;
     526                        }
     527                }
     528        }
     529
     530        /* We're out of stuff to do, so tell the AIM servers we're done and exit */
     531        if (!sess->ssi.pending) {
     532                aim_ssi_modend(sess);
     533                return 0;
     534        }
     535
     536        /* Make sure we don't send anything else between now
     537         * and when we receive the ack for the following operation */
     538        sess->ssi.waiting_for_ack = 1;
     539
     540        /* Now go mail off our data and wait 4 to 6 weeks */
     541        aim_ssi_addmoddel(sess);
     542
     543        return 0;
     544}
     545
     546/**
     547 * Free all SSI data.
     548 *
     549 * This doesn't remove it from the server, that's different.
    320550 *
    321551 * @param sess The oscar session.
    322  * @param conn The bos connection for this session.
    323552 * @return Return 0 if no errors, otherwise return the error number.
    324553 */
    325 static 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.
     554static int aim_ssi_freelist(aim_session_t *sess)
     555{
     556        struct aim_ssi_item *cur, *del;
     557        struct aim_ssi_tmp *curtmp, *deltmp;
     558
     559        cur = sess->ssi.official;
     560        while (cur) {
     561                del = cur;
     562                cur = cur->next;
     563                free(del->name);
     564                aim_freetlvchain(&del->data);
     565                free(del);
     566        }
     567
     568        cur = sess->ssi.local;
     569        while (cur) {
     570                del = cur;
     571                cur = cur->next;
     572                free(del->name);
     573                aim_freetlvchain(&del->data);
     574                free(del);
     575        }
     576
     577        curtmp = sess->ssi.pending;
     578        while (curtmp) {
     579                deltmp = curtmp;
     580                curtmp = curtmp->next;
     581                free(deltmp);
     582        }
     583
     584        sess->ssi.numitems = 0;
     585        sess->ssi.official = NULL;
     586        sess->ssi.local = NULL;
     587        sess->ssi.pending = NULL;
     588        sess->ssi.timestamp = (time_t)0;
     589
     590        return 0;
     591}
     592
     593/**
     594 * Delete all SSI data.
    349595 *
    350596 * @param sess The oscar session.
    351  * @param conn The bos connection for this session.
    352597 * @return Return 0 if no errors, otherwise return the error number.
    353598 */
    354 faim_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.
     599faim_export int aim_ssi_deletelist(aim_session_t *sess)
     600{
     601        struct aim_ssi_item *cur, *del;
     602
     603        if (!sess)
     604                return -EINVAL;
     605
     606        /* Free the local list */
     607        cur = sess->ssi.local;
     608        while (cur) {
     609                del = cur;
     610                cur = cur->next;
     611                free(del->name);
     612                aim_freetlvchain(&del->data);
     613                free(del);
     614        }
     615        sess->ssi.local = NULL;
     616
     617        /* Sync our local list with the server list */
     618        aim_ssi_sync(sess);
     619
     620        return 0;
     621}
     622
     623/**
     624 * This "cleans" the ssi list.  It does the following:
     625 * 1) Makes sure all buddies, permits, and denies have names.
     626 * 2) Makes sure that all buddies are in a group that exist.
     627 * 3) Deletes any empty groups
    385628 *
    386629 * @param sess The oscar session.
    387  * @param conn The bos connection for this session.
    388630 * @return Return 0 if no errors, otherwise return the error number.
    389631 */
    390 faim_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;
     632faim_export int aim_ssi_cleanlist(aim_session_t *sess)
     633{
     634        struct aim_ssi_item *cur, *next;
     635
     636        if (!sess)
     637                return -EINVAL;
     638
     639        /* Delete any buddies, permits, or denies with empty names. */
     640        /* If there are any buddies directly in the master group, add them to a real group. */
     641        /* DESTROY any buddies that are directly in the master group. */
     642        /* Do the same for buddies that are in a non-existant group. */
     643        /* This will kind of mess up if you hit the item limit, but this function isn't too critical */
     644        cur = sess->ssi.local;
     645        while (cur) {
     646                next = cur->next;
     647                if (!cur->name) {
     648                        if (cur->type == AIM_SSI_TYPE_BUDDY)
     649                                aim_ssi_delbuddy(sess, NULL, NULL);
     650                        else if (cur->type == AIM_SSI_TYPE_PERMIT)
     651                                aim_ssi_delpermit(sess, NULL);
     652                        else if (cur->type == AIM_SSI_TYPE_DENY)
     653                                aim_ssi_deldeny(sess, NULL);
     654                } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) {
     655                        aim_ssi_addbuddy(sess, cur->name, "orphans", NULL, NULL, NULL, 0);
     656                        aim_ssi_delbuddy(sess, cur->name, NULL);
    408657                }
    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);
     658                cur = next;
     659        }
     660
     661        /* Check if there are empty groups and delete them */
     662        cur = sess->ssi.local;
     663        while (cur) {
     664                next = cur->next;
     665                if (cur->type == AIM_SSI_TYPE_GROUP) {
     666                        aim_tlv_t *tlv = aim_gettlv(cur->data, 0x00c8, 1);
     667                        if (!tlv || !tlv->length)
     668                                aim_ssi_itemlist_del(&sess->ssi.local, cur);
    420669                }
    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);
     670                cur = next;
     671        }
     672
     673        /* Check if the master group is empty */
     674        if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data))
     675                aim_ssi_itemlist_del(&sess->ssi.local, cur);
     676
     677        return 0;
     678}
     679
     680/**
     681 * Add a buddy to the list.
     682 *
     683 * @param sess The oscar session.
     684 * @param name The name of the item.
     685 * @param group The group of the item.
     686 * @param alias The alias/nickname of the item, or NULL.
     687 * @param comment The buddy comment for the item, or NULL.
     688 * @param smsnum The locally assigned SMS number, or NULL.
     689 * @return Return 0 if no errors, otherwise return the error number.
     690 */
     691faim_export int aim_ssi_addbuddy(aim_session_t *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth)
     692{
     693        struct aim_ssi_item *parent;
     694        aim_tlvlist_t *data = NULL;
     695
     696        if (!sess || !name || !group)
     697                return -EINVAL;
     698
     699        /* Find the parent */
     700        if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
     701                /* Find the parent's parent (the master group) */
     702                if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)))
     703                        if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
     704                                return -ENOMEM;
     705                /* Add the parent */
     706                if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
     707                        return -ENOMEM;
     708
     709                /* Modify the parent's parent (the master group) */
     710                aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
     711        }
     712
     713        /* Create a TLV list for the new buddy */
     714        if (needauth)
     715                aim_addtlvtochain_noval(&data, 0x0066);
     716        if (alias)
     717                aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias);
     718        if (smsnum)
     719                aim_addtlvtochain_raw(&data, 0x013a, strlen(smsnum), smsnum);
     720        if (comment)
     721                aim_addtlvtochain_raw(&data, 0x013c, strlen(comment), comment);
     722
     723        /* Add that bad boy */
     724        aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
     725        aim_freetlvchain(&data);
     726
     727        /* Modify the parent group */
     728        aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
     729
     730        /* Sync our local list with the server list */
     731        aim_ssi_sync(sess);
     732
     733        return 0;
     734}
     735
     736/**
     737 * Add a permit buddy to the list.
     738 *
     739 * @param sess The oscar session.
     740 * @param name The name of the item..
     741 * @return Return 0 if no errors, otherwise return the error number.
     742 */
     743faim_export int aim_ssi_addpermit(aim_session_t *sess, const char *name)
     744{
     745
     746        if (!sess || !name)
     747                return -EINVAL;
     748
     749        /* Add that bad boy */
     750        aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
     751
     752        /* Sync our local list with the server list */
     753        aim_ssi_sync(sess);
     754
     755        return 0;
     756}
     757
     758/**
     759 * Add a deny buddy to the list.
     760 *
     761 * @param sess The oscar session.
     762 * @param name The name of the item..
     763 * @return Return 0 if no errors, otherwise return the error number.
     764 */
     765faim_export int aim_ssi_adddeny(aim_session_t *sess, const char *name)
     766{
     767
     768        if (!sess || !name)
     769                return -EINVAL;
     770
     771        /* Add that bad boy */
     772        aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
     773
     774        /* Sync our local list with the server list */
     775        aim_ssi_sync(sess);
     776
     777        return 0;
     778}
     779
     780/**
     781 * Deletes a buddy from the list.
     782 *
     783 * @param sess The oscar session.
     784 * @param name The name of the item, or NULL.
     785 * @param group The group of the item, or NULL.
     786 * @return Return 0 if no errors, otherwise return the error number.
     787 */
     788faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group)
     789{
     790        struct aim_ssi_item *del;
     791
     792        if (!sess)
     793                return -EINVAL;
     794
     795        /* Find the buddy */
     796        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
     797                return -EINVAL;
     798
     799        /* Remove the item from the list */
     800        aim_ssi_itemlist_del(&sess->ssi.local, del);
     801
     802        /* Modify the parent group */
     803        aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
     804
     805        /* Check if we should delete the parent group */
     806        if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) {
     807                aim_ssi_itemlist_del(&sess->ssi.local, del);
     808
     809                /* Modify the parent group */
     810                aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
     811
     812                /* Check if we should delete the parent's parent (the master group) */
     813                if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) {
     814                        aim_ssi_itemlist_del(&sess->ssi.local, del);
    432815                }
    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.
     816        }
     817
     818        /* Sync our local list with the server list */
     819        aim_ssi_sync(sess);
     820
     821        return 0;
     822}
     823
     824/**
     825 * Deletes a permit buddy from the list.
    485826 *
    486827 * @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).
     828 * @param name The name of the item, or NULL.
    491829 * @return Return 0 if no errors, otherwise return the error number.
    492830 */
    493 faim_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.
     831faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name)
     832{
     833        struct aim_ssi_item *del;
     834
     835        if (!sess)
     836                return -EINVAL;
     837
     838        /* Find the item */
     839        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
     840                return -EINVAL;
     841
     842        /* Remove the item from the list */
     843        aim_ssi_itemlist_del(&sess->ssi.local, del);
     844
     845        /* Sync our local list with the server list */
     846        aim_ssi_sync(sess);
     847
     848        return 0;
     849}
     850
     851/**
     852 * Deletes a deny buddy from the list.
    546853 *
    547854 * @param sess The oscar session.
    548  * @param conn The bos connection for this session.
     855 * @param name The name of the item, or NULL.
    549856 * @return Return 0 if no errors, otherwise return the error number.
    550857 */
    551 faim_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  */
    584 faim_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  */
    647 faim_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;
     858faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name)
     859{
     860        struct aim_ssi_item *del;
     861
     862        if (!sess)
     863                return -EINVAL;
     864
     865        /* Find the item */
     866        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
     867                return -EINVAL;
     868
     869        /* Remove the item from the list */
     870        aim_ssi_itemlist_del(&sess->ssi.local, del);
     871
     872        /* Sync our local list with the server list */
     873        aim_ssi_sync(sess);
    678874
    679875        return 0;
     
    685881 *
    686882 * @param sess The oscar session.
    687  * @param conn The bos connection for this session.
    688883 * @param oldgn The group that the buddy is currently in.
    689884 * @param newgn The group that the buddy should be moved in to.
     
    691886 * @return Return 0 if no errors, otherwise return the error number.
    692887 */
    693 faim_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?...
     888faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn)
     889{
     890        aim_ssi_addbuddy(sess, sn, newgn, aim_ssi_getalias(sess->ssi.local, oldgn, sn), NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn));
     891        aim_ssi_delbuddy(sess, sn, oldgn);
     892        return 0;
     893}
     894
     895/**
     896 * Change the alias stored on the server for a given buddy.
    762897 *
    763898 * @param sess The oscar session.
    764  * @param conn The bos connection for this session.
     899 * @param gn The group that the buddy is currently in.
     900 * @param sn The screen name of the buddy.
     901 * @param alias The new alias for the buddy.
     902 * @return Return 0 if no errors, otherwise return the error number.
     903 */
     904faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias)
     905{
     906        struct aim_ssi_item *tmp;
     907        aim_tlvlist_t *data = NULL;
     908
     909        if (!sess || !gn || !sn)
     910                return -EINVAL;
     911
     912        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
     913                return -EINVAL;
     914
     915        if (alias && !strlen(alias))
     916                alias = NULL;
     917
     918        /* Need to add the x0131 TLV to the TLV chain */
     919        if (alias)
     920                aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias);
     921
     922        aim_freetlvchain(&tmp->data);
     923        tmp->data = data;
     924
     925        /* Sync our local list with the server list */
     926        aim_ssi_sync(sess);
     927
     928        return 0;
     929}
     930
     931/**
     932 * Rename a group.
     933 *
     934 * @param sess The oscar session.
    765935 * @param oldgn The old group name.
    766936 * @param newgn The new group name.
    767937 * @return Return 0 if no errors, otherwise return the error number.
    768938 */
    769 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn)
     939faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn)
    770940{
    771941        struct aim_ssi_item *group;
    772942
    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         }
     943        if (!sess || !oldgn || !newgn)
     944                return -EINVAL;
     945
     946        if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
     947                return -EINVAL;
     948
     949        free(group->name);
     950        group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char));
    787951        strcpy(group->name, newgn);
    788952
    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.
     953        /* Sync our local list with the server list */
     954        aim_ssi_sync(sess);
     955
     956        return 0;
     957}
     958
     959/**
     960 * Stores your permit/deny setting on the server, and starts using it.
    800961 *
    801962 * @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  */
    808 faim_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  */
    878 faim_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  */
    923 faim_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  */
    995 faim_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.
    1047963 * @param permdeny Your permit/deny setting.  Can be one of the following:
    1048964 *        1 - Allow all users
     
    1055971 * @return Return 0 if no errors, otherwise return the error number.
    1056972 */
    1057 faim_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);
     973faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask)
     974{
     975        struct aim_ssi_item *tmp;
     976        aim_tlvlist_t *data = NULL;
     977
     978        if (!sess)
     979                return -EINVAL;
     980
     981        /* Need to add the x00ca TLV to the TLV chain */
     982        aim_addtlvtochain8(&data, 0x00ca, permdeny);
     983
     984        /* Need to add the x00cb TLV to the TLV chain */
     985        aim_addtlvtochain32(&data, 0x00cb, vismask);
     986
     987        if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) {
     988                aim_freetlvchain(&tmp->data);
     989                tmp->data = data;
     990        } else {
     991                tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, data);
     992                aim_freetlvchain(&data);
     993        }
     994
     995        /* Sync our local list with the server list */
     996        aim_ssi_sync(sess);
     997
     998        return 0;
     999}
     1000
     1001/**
     1002 * Set buddy icon information
     1003 *
     1004 * @param sess The oscar session.
     1005 * @param iconcsum The MD5 checksum of the icon you are using.
     1006 * @param iconcsumlen Length of the MD5 checksum given above.  Should be 0x10 bytes.
     1007 * @return Return 0 if no errors, otherwise return the error number.
     1008 */
     1009faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen)
     1010{
     1011        struct aim_ssi_item *tmp;
     1012        aim_tlvlist_t *data = NULL;
     1013        fu8_t *csumdata;
     1014
     1015        if (!sess || !iconsum || !iconsumlen)
     1016                return -EINVAL;
     1017
     1018        if (!(csumdata = (fu8_t *)malloc((iconsumlen+2)*sizeof(fu8_t))))
     1019                return -ENOMEM;
     1020        csumdata[0] = 0x00;
     1021        csumdata[1] = 0x10;
     1022        memcpy(&csumdata[2], iconsum, iconsumlen);
     1023
     1024        /* Need to add the x00d5 TLV to the TLV chain */
     1025        aim_addtlvtochain_raw(&data, 0x00d5, (iconsumlen+2) * sizeof(fu8_t), csumdata);
     1026
     1027        /* This TLV is added to cache the icon. */
     1028        aim_addtlvtochain_noval(&data, 0x0131);
     1029
     1030        if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
     1031                /* If the new tlvchain and oldtlvchain are the same, then do nothing */
     1032                if (!aim_tlvlist_cmp(tmp->data, data)) {
     1033                        /* The new tlvlist is the identical to the old one */
     1034                        aim_freetlvchain(&data);
     1035                        free(csumdata);
     1036                        return 0;
    10801037                }
    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);
     1038                aim_freetlvchain(&tmp->data);
     1039                tmp->data = data;
    10971040        } 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 
     1041                tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, data);
     1042                aim_freetlvchain(&data);
     1043        }
     1044
     1045        /* Sync our local list with the server list */
     1046        aim_ssi_sync(sess);
     1047        free(csumdata);
    11091048        return 0;
    11101049}
     
    11141053 *
    11151054 * @param sess The oscar session.
    1116  * @param conn The bos connection for this session.
    11171055 * @param presence I think it's a bitmask, but I only know what one of the bits is:
    11181056 *        0x00000400 - Allow others to see your idle time
    11191057 * @return Return 0 if no errors, otherwise return the error number.
    11201058 */
    1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) {
    1122         struct aim_ssi_item *cur;
     1059faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence) {
     1060        struct aim_ssi_item *tmp;
     1061        aim_tlvlist_t *data = NULL;
     1062
     1063        if (!sess)
     1064                return -EINVAL;
     1065
     1066        /* Need to add the x00c9 TLV to the TLV chain */
     1067        aim_addtlvtochain32(&data, 0x00c9, presence);
     1068
     1069        if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) {
     1070                aim_freetlvchain(&tmp->data);
     1071                tmp->data = data;
     1072        } else {
     1073                tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, data);
     1074                aim_freetlvchain(&data);
     1075        }
     1076
     1077        /* Sync our local list with the server list */
     1078        aim_ssi_sync(sess);
     1079
     1080        return 0;
     1081}
     1082
     1083/*
     1084 * Subtype 0x0002 - Request SSI Rights.
     1085 */
     1086faim_export int aim_ssi_reqrights(aim_session_t *sess)
     1087{
     1088        aim_conn_t *conn;
     1089
     1090        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1091                return -EINVAL;
     1092
     1093        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
     1094}
     1095
     1096/*
     1097 * Subtype 0x0003 - SSI Rights Information.
     1098 */
     1099static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1100{
     1101        int ret = 0, i;
     1102        aim_rxcallback_t userfunc;
     1103        aim_tlvlist_t *tlvlist;
    11231104        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 
    1162 /*
    1163  * Request SSI Rights.
    1164  */
    1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn)
    1166 {
    1167         return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
    1168 }
    1169 
    1170 /*
    1171  * SSI Rights Information.
    1172  */
    1173 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    1174 {
    1175         int ret = 0;
    1176         aim_rxcallback_t userfunc;
     1105        aim_bstream_t bstream;
     1106        fu16_t *maxitems;
     1107
     1108        /* This SNAC is made up of a bunch of TLVs */
     1109        tlvlist = aim_readtlvchain(bs);
     1110
     1111        /* TLV 0x0004 contains the maximum number of each item */
     1112        if (!(tlv = aim_gettlv(tlvlist, 0x0004, 1))) {
     1113                aim_freetlvchain(&tlvlist);
     1114                return 0;
     1115        }
     1116
     1117        aim_bstream_init(&bstream, tlv->value, tlv->length);
     1118
     1119        if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) {
     1120                aim_freetlvchain(&tlvlist);
     1121                return 0;
     1122        }
     1123
     1124        for (i=0; i<(tlv->length/2); i++)
     1125                maxitems[i] = aimbs_get16(&bstream);
    11771126
    11781127        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1179                 ret = userfunc(sess, rx);
     1128                ret = userfunc(sess, rx, tlv->length/2, maxitems);
     1129
     1130        aim_freetlvchain(&tlvlist);
     1131        free(maxitems);
    11801132
    11811133        return ret;
     
    11831135
    11841136/*
    1185  * Request SSI Data.
     1137 * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and
     1138 * revision number.
     1139 *
     1140 */
     1141faim_export int aim_ssi_reqdata(aim_session_t *sess)
     1142{
     1143        aim_conn_t *conn;
     1144
     1145        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1146                return -EINVAL;
     1147
     1148        /* Free any current data, just in case */
     1149        aim_ssi_freelist(sess);
     1150
     1151        return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQDATA);
     1152}
     1153
     1154/*
     1155 * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision
     1156 * number.
    11861157 *
    11871158 * The data will only be sent if it is newer than the posted local
     
    11911162 *
    11921163 */
    1193 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev)
    1194 {
     1164faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t timestamp, fu16_t numitems)
     1165{
     1166        aim_conn_t *conn;
    11951167        aim_frame_t *fr;
    11961168        aim_snacid_t snacid;
    11971169
    1198         if (!sess || !conn)
     1170        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    11991171                return -EINVAL;
    12001172
     
    12021174                return -ENOMEM;
    12031175
    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);
    1207         aimbs_put32(&fr->data, localstamp);
    1208         aimbs_put16(&fr->data, localrev);
     1176        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, NULL, 0);
     1177
     1178        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, snacid);
     1179        aimbs_put32(&fr->data, timestamp);
     1180        aimbs_put16(&fr->data, numitems);
    12091181
    12101182        aim_tx_enqueue(sess, fr);
    12111183
    1212         return 0;
    1213 }
    1214 
    1215 /*
    1216  * SSI Data.
     1184        /* Free any current data, just in case */
     1185        aim_ssi_freelist(sess);
     1186
     1187        return 0;
     1188}
     1189
     1190/*
     1191 * Subtype 0x0006 - SSI Data.
    12171192 */
    12181193static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     
    12201195        int ret = 0;
    12211196        aim_rxcallback_t userfunc;
    1222         struct aim_ssi_item *cur = NULL;
    12231197        fu8_t fmtver; /* guess */
    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          */
     1198        fu16_t namelen, gid, bid, type;
     1199        char *name;
     1200        aim_tlvlist_t *data;
    12341201
    12351202        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) ;
    1241 
    1242         while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */
    1243                 fu16_t namelen, tbslen;
    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));
    1255 
     1203        sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */
     1204
     1205        /* Read in the list */
     1206        while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */
    12561207                if ((namelen = 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);
    1261 
    1262                 if ((tbslen = aimbs_get16(bs))) {
    1263                         aim_bstream_t tbs;
    1264 
    1265                         aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen);
    1266                         cur->data = (void *)aim_readtlvchain(&tbs);
    1267                         aim_bstream_advance(bs, tbslen);
    1268                 }
    1269         }
    1270 
    1271         timestamp = aimbs_get32(bs);
    1272         if (timestamp != 0)
    1273                 sess->ssi.timestamp = timestamp;
    1274         sess->ssi.received_data = 1;
    1275 
    1276         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1277                 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items);
     1208                        name = aimbs_getstr(bs, namelen);
     1209                else
     1210                        name = NULL;
     1211                gid = aimbs_get16(bs);
     1212                bid = aimbs_get16(bs);
     1213                type = aimbs_get16(bs);
     1214                data = aim_readtlvchain_len(bs, aimbs_get16(bs));
     1215                aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
     1216                free(name);
     1217                aim_freetlvchain(&data);
     1218        }
     1219
     1220        /* Read in the timestamp */
     1221        sess->ssi.timestamp = aimbs_get32(bs);
     1222
     1223        if (!(snac->flags & 0x0001)) {
     1224                /* Make a copy of the list */
     1225                struct aim_ssi_item *cur;
     1226                for (cur=sess->ssi.official; cur; cur=cur->next)
     1227                        aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
     1228
     1229                sess->ssi.received_data = 1;
     1230
     1231                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1232                        ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp);
     1233        }
    12781234
    12791235        return ret;
     
    12811237
    12821238/*
    1283  * SSI Data Enable Presence.
     1239 * Subtype 0x0007 - SSI Activate Data.
    12841240 *
    12851241 * Should be sent after receiving 13/6 or 13/f to tell the server you
     
    12891245 *
    12901246 */
    1291 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn)
    1292 {
     1247faim_export int aim_ssi_enable(aim_session_t *sess)
     1248{
     1249        aim_conn_t *conn;
     1250
     1251        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1252                return -EINVAL;
     1253
    12931254        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
    12941255}
    12951256
    12961257/*
    1297  * SSI Add/Mod/Del Item(s).
     1258 * Subtype 0x0008/0x0009/0x000a - SSI Add/Mod/Del Item(s).
    12981259 *
    12991260 * Sends the SNAC to add, modify, or delete an item from the server-stored
     
    13021263 *
    13031264 */
    1304 faim_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 {
     1265faim_export int aim_ssi_addmoddel(aim_session_t *sess)
     1266{
     1267        aim_conn_t *conn;
    13061268        aim_frame_t *fr;
    13071269        aim_snacid_t snacid;
    1308         int i, snaclen;
    1309 
    1310         if (!sess || !conn || !items || !num)
    1311                 return -EINVAL;
    1312 
     1270        int snaclen;
     1271        struct aim_ssi_tmp *cur;
     1272
     1273        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sess->ssi.pending || !sess->ssi.pending->item)
     1274                return -EINVAL;
     1275
     1276        /* Calculate total SNAC size */
    13131277        snaclen = 10; /* For family, subtype, flags, and SNAC ID */
    1314         for (i=0; i<num; i++) {
     1278        for (cur=sess->ssi.pending; cur; cur=cur->next) {
    13151279                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);
     1280                if (cur->item->name)
     1281                        snaclen += strlen(cur->item->name);
     1282                if (cur->item->data)
     1283                        snaclen += aim_sizetlvchain(&cur->item->data);
    13201284        }
    13211285
     
    13231287                return -ENOMEM;
    13241288
    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  */
    1351 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1289        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0);
     1290        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid);
     1291
     1292        for (cur=sess->ssi.pending; cur; cur=cur->next) {
     1293                aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0);
     1294                if (cur->item->name)
     1295                        aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name));
     1296                aimbs_put16(&fr->data, cur->item->gid);
     1297                aimbs_put16(&fr->data, cur->item->bid);
     1298                aimbs_put16(&fr->data, cur->item->type);
     1299                aimbs_put16(&fr->data, cur->item->data ? aim_sizetlvchain(&cur->item->data) : 0);
     1300                if (cur->item->data)
     1301                        aim_writetlvchain(&fr->data, &cur->item->data);
     1302        }
     1303
     1304        aim_tx_enqueue(sess, fr);
     1305
     1306        return 0;
     1307}
     1308
     1309/*
     1310 * Subtype 0x0008 - Incoming SSI add.
     1311 *
     1312 * XXX - It would probably be good for the client to actually do something when it gets this.
     1313 */
     1314static int parseadd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    13521315{
    13531316        int ret = 0;
    13541317        aim_rxcallback_t userfunc;
    1355 
    1356         sess->ssi.waiting_for_ack = 0;
    1357         aim_ssi_dispatch(sess, rx->conn);
     1318        char *name;
     1319        fu16_t len, gid, bid, type;
     1320        aim_tlvlist_t *data;
     1321
     1322        while (aim_bstream_empty(bs)) {
     1323                if ((len = aimbs_get16(bs)))
     1324                        name = aimbs_getstr(bs, len);
     1325                else
     1326                        name = NULL;
     1327                gid = aimbs_get16(bs);
     1328                bid = aimbs_get16(bs);
     1329                type = aimbs_get16(bs);
     1330                if ((len = aimbs_get16(bs)))
     1331                        data = aim_readtlvchain_len(bs, len);
     1332                else
     1333                        data = NULL;
     1334
     1335                aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data);
     1336                aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
     1337                free(name);
     1338                aim_freetlvchain(&data);
     1339
     1340                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1341                        ret = userfunc(sess, rx);
     1342
     1343                free(name);
     1344        }
     1345
     1346        return ret;
     1347}
     1348
     1349/*
     1350 * Subtype 0x0009 - Incoming SSI mod.
     1351 *
     1352 * XXX - It would probably be good for the client to actually do something when it gets this.
     1353 */
     1354static int parsemod(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1355{
     1356        int ret = 0;
     1357        aim_rxcallback_t userfunc;
     1358        char *name;
     1359        fu16_t len, gid, bid, type;
     1360        aim_tlvlist_t *data;
     1361        struct aim_ssi_item *item;
     1362
     1363        while (aim_bstream_empty(bs)) {
     1364                if ((len = aimbs_get16(bs)))
     1365                        name = aimbs_getstr(bs, len);
     1366                else
     1367                        name = NULL;
     1368                gid = aimbs_get16(bs);
     1369                bid = aimbs_get16(bs);
     1370                type = aimbs_get16(bs);
     1371                if ((len = aimbs_get16(bs)))
     1372                        data = aim_readtlvchain_len(bs, len);
     1373                else
     1374                        data = NULL;
     1375
     1376                /* Replace the 2 local items with the given one */
     1377                if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) {
     1378                        item->type = type;
     1379                        free(item->name);
     1380                        if (name) {
     1381                                item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     1382                                strcpy(item->name, name);
     1383                        } else
     1384                                item->name = NULL;
     1385                        aim_freetlvchain(&item->data);
     1386                        item->data = aim_tlvlist_copy(data);
     1387                }
     1388
     1389                if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) {
     1390                        item->type = type;
     1391                        free(item->name);
     1392                        if (name) {
     1393                                item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     1394                                strcpy(item->name, name);
     1395                        } else
     1396                                item->name = NULL;
     1397                        aim_freetlvchain(&item->data);
     1398                        item->data = aim_tlvlist_copy(data);
     1399                }
     1400
     1401                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1402                        ret = userfunc(sess, rx);
     1403
     1404                free(name);
     1405                aim_freetlvchain(&data);
     1406        }
     1407
     1408        return ret;
     1409}
     1410
     1411/*
     1412 * Subtype 0x000a - Incoming SSI del.
     1413 *
     1414 * XXX - It would probably be good for the client to actually do something when it gets this.
     1415 */
     1416static int parsedel(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1417{
     1418        int ret = 0;
     1419        aim_rxcallback_t userfunc;
     1420        fu16_t gid, bid;
     1421        struct aim_ssi_item *del;
     1422
     1423        while (aim_bstream_empty(bs)) {
     1424                aim_bstream_advance(bs, aimbs_get16(bs));
     1425                gid = aimbs_get16(bs);
     1426                bid = aimbs_get16(bs);
     1427                aimbs_get16(bs);
     1428                aim_bstream_advance(bs, aimbs_get16(bs));
     1429
     1430                if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid)))
     1431                        aim_ssi_itemlist_del(&sess->ssi.local, del);
     1432                if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid)))
     1433                        aim_ssi_itemlist_del(&sess->ssi.official, del);
     1434
     1435                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1436                        ret = userfunc(sess, rx);
     1437        }
     1438
     1439        return ret;
     1440}
     1441
     1442/*
     1443 * Subtype 0x000e - SSI Add/Mod/Del Ack.
     1444 *
     1445 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
     1446 *
     1447 */
     1448static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1449{
     1450        int ret = 0;
     1451        aim_rxcallback_t userfunc;
     1452        struct aim_ssi_tmp *cur, *del;
     1453
     1454        /* Read in the success/failure flags from the ack SNAC */
     1455        cur = sess->ssi.pending;
     1456        while (cur && (aim_bstream_empty(bs)>0)) {
     1457                cur->ack = aimbs_get16(bs);
     1458                cur = cur->next;
     1459        }
     1460
     1461        /*
     1462         * If outcome is 0, then add the item to the item list, or replace the other item,
     1463         * or remove the old item.  If outcome is non-zero, then remove the item from the
     1464         * local list, or unmodify it, or add it.
     1465         */
     1466        for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
     1467        if (cur->item) {
     1468                if (cur->ack) {
     1469                        /* Our action was unsuccessful, so change the local list back to how it was */
     1470                        if (cur->action == AIM_CB_SSI_ADD) {
     1471                                /* Remove the item from the local list */
     1472                                /* Make sure cur->item is still valid memory */
     1473                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1474                                        if (cur->item->name) {
     1475                                                cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
     1476                                                strcpy(cur->name, cur->item->name);
     1477                                        }
     1478                                        aim_ssi_itemlist_del(&sess->ssi.local, cur->item);
     1479                                }
     1480                                cur->item = NULL;
     1481
     1482                        } else if (cur->action == AIM_CB_SSI_MOD) {
     1483                                /* Replace the local item with the item from the official list */
     1484                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1485                                        struct aim_ssi_item *cur1;
     1486                                        if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
     1487                                                free(cur->item->name);
     1488                                                if (cur1->name) {
     1489                                                        cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char));
     1490                                                        strcpy(cur->item->name, cur1->name);
     1491                                                } else
     1492                                                        cur->item->name = NULL;
     1493                                                aim_freetlvchain(&cur->item->data);
     1494                                                cur->item->data = aim_tlvlist_copy(cur1->data);
     1495                                        }
     1496                                } else
     1497                                        cur->item = NULL;
     1498
     1499                        } else if (cur->action == AIM_CB_SSI_DEL) {
     1500                                /* Add the item back into the local list */
     1501                                if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) {
     1502                                        aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
     1503                                } else
     1504                                        cur->item = NULL;
     1505                        }
     1506
     1507                } else {
     1508                        /* Do the exact opposite */
     1509                        if (cur->action == AIM_CB_SSI_ADD) {
     1510                        /* Add the local item to the official list */
     1511                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1512                                        aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
     1513                                } else
     1514                                        cur->item = NULL;
     1515
     1516                        } else if (cur->action == AIM_CB_SSI_MOD) {
     1517                                /* Replace the official item with the item from the local list */
     1518                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1519                                        struct aim_ssi_item *cur1;
     1520                                        if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
     1521                                                free(cur1->name);
     1522                                                if (cur->item->name) {
     1523                                                        cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
     1524                                                        strcpy(cur1->name, cur->item->name);
     1525                                                } else
     1526                                                        cur1->name = NULL;
     1527                                                aim_freetlvchain(&cur1->data);
     1528                                                cur1->data = aim_tlvlist_copy(cur->item->data);
     1529                                        }
     1530                                } else
     1531                                        cur->item = NULL;
     1532
     1533                        } else if (cur->action == AIM_CB_SSI_DEL) {
     1534                                /* Remove the item from the official list */
     1535                                if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item))
     1536                                        aim_ssi_itemlist_del(&sess->ssi.official, cur->item);
     1537                                cur->item = NULL;
     1538                        }
     1539
     1540                }
     1541        } /* End if (cur->item) */
     1542        } /* End for loop */
     1543
     1544        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1545                ret = userfunc(sess, rx, sess->ssi.pending);
     1546
     1547        /* Free all aim_ssi_tmp's with an outcome */
     1548        cur = sess->ssi.pending;
     1549        while (cur && (cur->ack != 0xffff)) {
     1550                del = cur;
     1551                cur = cur->next;
     1552                free(del->name);
     1553                free(del);
     1554        }
     1555        sess->ssi.pending = cur;
     1556
     1557        /* If we're not waiting for any more acks, then send more SNACs */
     1558        if (!sess->ssi.pending) {
     1559                sess->ssi.pending = NULL;
     1560                sess->ssi.waiting_for_ack = 0;
     1561                aim_ssi_sync(sess);
     1562        }
     1563
     1564        return ret;
     1565}
     1566
     1567/*
     1568 * Subtype 0x000f - SSI Data Unchanged.
     1569 *
     1570 * Response to aim_ssi_reqifchanged() if the server-side data is not newer than
     1571 * posted local stamp/revision.
     1572 *
     1573 */
     1574static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1575{
     1576        int ret = 0;
     1577        aim_rxcallback_t userfunc;
     1578
     1579        sess->ssi.received_data = 1;
    13581580
    13591581        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     
    13641586
    13651587/*
    1366  * SSI Begin Data Modification.
     1588 * Subtype 0x0011 - SSI Begin Data Modification.
    13671589 *
    13681590 * Tells the server you're going to start modifying data.
    13691591 *
    13701592 */
    1371 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn)
    1372 {
     1593faim_export int aim_ssi_modbegin(aim_session_t *sess)
     1594{
     1595        aim_conn_t *conn;
     1596
     1597        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1598                return -EINVAL;
     1599
    13731600        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
    13741601}
    13751602
    13761603/*
    1377  * SSI End Data Modification.
    1378  *
    1379  * Tells the server you're done modifying data.
    1380  *
    1381  */
    1382 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn)
    1383 {
     1604 * Subtype 0x0012 - SSI End Data Modification.
     1605 *
     1606 * Tells the server you're finished modifying data.
     1607 *
     1608 */
     1609faim_export int aim_ssi_modend(aim_session_t *sess)
     1610{
     1611        aim_conn_t *conn;
     1612
     1613        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1614                return -EINVAL;
     1615
    13841616        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
    13851617}
    13861618
    13871619/*
    1388  * SSI Data Unchanged.
    1389  *
    1390  * Response to aim_ssi_reqdata() if the server-side data is not newer than
    1391  * posted local stamp/revision.
    1392  *
    1393  */
    1394 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1620 * Subtype 0x0014 - Grant authorization
     1621 *
     1622 * Authorizes a contact so they can add you to their contact list.
     1623 *
     1624 */
     1625faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg)
     1626{
     1627        aim_conn_t *conn;
     1628        aim_frame_t *fr;
     1629        aim_snacid_t snacid;
     1630
     1631        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1632                return -EINVAL;
     1633
     1634        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
     1635                return -ENOMEM;
     1636
     1637        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0);
     1638        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid);
     1639
     1640        /* Screen name */
     1641        aimbs_put8(&fr->data, strlen(sn));
     1642        aimbs_putraw(&fr->data, sn, strlen(sn));
     1643
     1644        /* Message (null terminated) */
     1645        aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
     1646        if (msg) {
     1647                aimbs_putraw(&fr->data, msg, strlen(msg));
     1648                aimbs_put8(&fr->data, 0x00);
     1649        }
     1650
     1651        /* Unknown */
     1652        aimbs_put16(&fr->data, 0x0000);
     1653
     1654        aim_tx_enqueue(sess, fr);
     1655
     1656        return 0;
     1657}
     1658
     1659/*
     1660 * Subtype 0x0015 - Receive an authorization grant
     1661 */
     1662static int receiveauthgrant(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    13951663{
    13961664        int ret = 0;
    13971665        aim_rxcallback_t userfunc;
    1398 
    1399         sess->ssi.received_data = 1;
     1666        fu16_t tmp;
     1667        char *sn, *msg;
     1668
     1669        /* Read screen name */
     1670        if ((tmp = aimbs_get8(bs)))
     1671                sn = aimbs_getstr(bs, tmp);
     1672        else
     1673                sn = NULL;
     1674
     1675        /* Read message (null terminated) */
     1676        if ((tmp = aimbs_get16(bs)))
     1677                msg = aimbs_getstr(bs, tmp);
     1678        else
     1679                msg = NULL;
     1680
     1681        /* Unknown */
     1682        tmp = aimbs_get16(bs);
    14001683
    14011684        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1402                 ret = userfunc(sess, rx);
     1685                ret = userfunc(sess, rx, sn, msg);
     1686
     1687        free(sn);
     1688        free(msg);
     1689
     1690        return ret;
     1691}
     1692
     1693/*
     1694 * Subtype 0x0018 - Send authorization request
     1695 *
     1696 * Sends a request for authorization to the given contact.  The request will either be
     1697 * granted, denied, or dropped.
     1698 *
     1699 */
     1700faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg)
     1701{
     1702        aim_conn_t *conn;
     1703        aim_frame_t *fr;
     1704        aim_snacid_t snacid;
     1705
     1706        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1707                return -EINVAL;
     1708
     1709        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
     1710                return -ENOMEM;
     1711
     1712        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0);
     1713        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid);
     1714
     1715        /* Screen name */
     1716        aimbs_put8(&fr->data, strlen(sn));
     1717        aimbs_putraw(&fr->data, sn, strlen(sn));
     1718
     1719        /* Message (null terminated) */
     1720        aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
     1721        if (msg) {
     1722                aimbs_putraw(&fr->data, msg, strlen(msg));
     1723                aimbs_put8(&fr->data, 0x00);
     1724        }
     1725
     1726        /* Unknown */
     1727        aimbs_put16(&fr->data, 0x0000);
     1728
     1729        aim_tx_enqueue(sess, fr);
     1730
     1731        return 0;
     1732}
     1733
     1734/*
     1735 * Subtype 0x0019 - Receive an authorization request
     1736 */
     1737static int receiveauthrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1738{
     1739        int ret = 0;
     1740        aim_rxcallback_t userfunc;
     1741        fu16_t tmp;
     1742        char *sn, *msg;
     1743
     1744        /* Read screen name */
     1745        if ((tmp = aimbs_get8(bs)))
     1746                sn = aimbs_getstr(bs, tmp);
     1747        else
     1748                sn = NULL;
     1749
     1750        /* Read message (null terminated) */
     1751        if ((tmp = aimbs_get16(bs)))
     1752                msg = aimbs_getstr(bs, tmp);
     1753        else
     1754                msg = NULL;
     1755
     1756        /* Unknown */
     1757        tmp = aimbs_get16(bs);
     1758
     1759        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1760                ret = userfunc(sess, rx, sn, msg);
     1761
     1762        free(sn);
     1763        free(msg);
     1764
     1765        return ret;
     1766}
     1767
     1768/*
     1769 * Subtype 0x001a - Send authorization reply
     1770 *
     1771 * Sends a reply to a request for authorization.  The reply can either
     1772 * grant authorization or deny authorization.
     1773 *
     1774 * if reply=0x00 then deny
     1775 * if reply=0x01 then grant
     1776 *
     1777 */
     1778faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg)
     1779{
     1780        aim_conn_t *conn;
     1781        aim_frame_t *fr;
     1782        aim_snacid_t snacid;
     1783
     1784        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1785                return -EINVAL;
     1786
     1787        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2)))
     1788                return -ENOMEM;
     1789
     1790        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0);
     1791        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid);
     1792
     1793        /* Screen name */
     1794        aimbs_put8(&fr->data, strlen(sn));
     1795        aimbs_putraw(&fr->data, sn, strlen(sn));
     1796
     1797        /* Grant or deny */
     1798        aimbs_put8(&fr->data, reply);
     1799
     1800        /* Message (null terminated) */
     1801        aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0);
     1802        if (msg) {
     1803                aimbs_putraw(&fr->data, msg, strlen(msg));
     1804                aimbs_put8(&fr->data, 0x00);
     1805        }
     1806
     1807        /* Unknown */
     1808        aimbs_put16(&fr->data, 0x0000);
     1809
     1810        aim_tx_enqueue(sess, fr);
     1811
     1812        return 0;
     1813}
     1814
     1815/*
     1816 * Subtype 0x001b - Receive an authorization reply
     1817 * You get this bad boy when other people respond to the authorization
     1818 * request that you have previously sent them.
     1819 */
     1820static int receiveauthreply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1821{
     1822        int ret = 0;
     1823        aim_rxcallback_t userfunc;
     1824        fu16_t tmp;
     1825        fu8_t reply;
     1826        char *sn, *msg;
     1827
     1828        /* Read screen name */
     1829        if ((tmp = aimbs_get8(bs)))
     1830                sn = aimbs_getstr(bs, tmp);
     1831        else
     1832                sn = NULL;
     1833
     1834        /* Read reply */
     1835        reply = aimbs_get8(bs);
     1836
     1837        /* Read message (null terminated) */
     1838        if ((tmp = aimbs_get16(bs)))
     1839                msg = aimbs_getstr(bs, tmp);
     1840        else
     1841                msg = NULL;
     1842
     1843        /* Unknown */
     1844        tmp = aimbs_get16(bs);
     1845
     1846        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1847                ret = userfunc(sess, rx, sn, reply, msg);
     1848
     1849        free(sn);
     1850        free(msg);
     1851
     1852        return ret;
     1853}
     1854
     1855/*
     1856 * Subtype 0x001c - Receive a message telling you someone added you to their list.
     1857 */
     1858static int receiveadded(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
     1859{
     1860        int ret = 0;
     1861        aim_rxcallback_t userfunc;
     1862        fu16_t tmp;
     1863        char *sn;
     1864
     1865        /* Read screen name */
     1866        if ((tmp = aimbs_get8(bs)))
     1867                sn = aimbs_getstr(bs, tmp);
     1868        else
     1869                sn = NULL;
     1870
     1871        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1872                ret = userfunc(sess, rx, sn);
     1873
     1874        free(sn);
    14031875
    14041876        return ret;
     
    14121884        else if (snac->subtype == AIM_CB_SSI_LIST)
    14131885                return parsedata(sess, mod, rx, snac, bs);
     1886        else if (snac->subtype == AIM_CB_SSI_ADD)
     1887                return parseadd(sess, mod, rx, snac, bs);
     1888        else if (snac->subtype == AIM_CB_SSI_MOD)
     1889                return parsemod(sess, mod, rx, snac, bs);
     1890        else if (snac->subtype == AIM_CB_SSI_DEL)
     1891                return parsedel(sess, mod, rx, snac, bs);
    14141892        else if (snac->subtype == AIM_CB_SSI_SRVACK)
    14151893                return parseack(sess, mod, rx, snac, bs);
    14161894        else if (snac->subtype == AIM_CB_SSI_NOLIST)
    14171895                return parsedataunchanged(sess, mod, rx, snac, bs);
     1896        else if (snac->subtype == AIM_CB_SSI_RECVAUTH)
     1897                return receiveauthgrant(sess, mod, rx, snac, bs);
     1898        else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ)
     1899                return receiveauthrequest(sess, mod, rx, snac, bs);
     1900        else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP)
     1901                return receiveauthreply(sess, mod, rx, snac, bs);
     1902        else if (snac->subtype == AIM_CB_SSI_ADDED)
     1903                return receiveadded(sess, mod, rx, snac, bs);
    14181904
    14191905        return 0;
     
    14311917
    14321918        mod->family = AIM_CB_FAM_SSI;
    1433         mod->version = 0x0001;
     1919        mod->version = 0x0004;
    14341920        mod->toolid = 0x0110;
    1435         mod->toolversion = 0x047b;
     1921        mod->toolversion = 0x0629;
    14361922        mod->flags = 0;
    14371923        strncpy(mod->name, "ssi", sizeof(mod->name));
  • libfaim/stats.c

    r862371b re374dee  
    99static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    1010{
     11        int ret = 0;
     12        aim_rxcallback_t userfunc;
    1113        fu16_t interval;
    12         aim_rxcallback_t userfunc;
    1314
    1415        interval = aimbs_get16(bs);
    1516
    1617        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    17                 return userfunc(sess, rx, interval);
     18                ret = userfunc(sess, rx, interval);
    1819
    19         return 0;
     20        return ret;
    2021}
    2122
  • libfaim/tlv.c

    r862371b re374dee  
    114114 *        There are a number of places where you want to read in a tlvchain,
    115115 *        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.
     116 *        preceeded by the number of TLVs.  So you can limit that with this.
    117117 *
    118118 * Reads and parses a series of TLV patterns from a data buffer; the
     
    131131{
    132132        aim_tlvlist_t *list = NULL, *cur;
    133        
     133
    134134        while ((aim_bstream_empty(bs) > 0) && (num != 0)) {
    135135                fu16_t type, length;
     
    159159                cur->tlv->type = type;
    160160                if ((cur->tlv->length = length)) {
    161                        cur->tlv->value = aimbs_getraw(bs, length);     
     161                       cur->tlv->value = aimbs_getraw(bs, length);
    162162                       if (!cur->tlv->value) {
    163163                               freetlv(&cur->tlv);
     
    177177
    178178/**
     179 * aim_readtlvchain_len - Read a TLV chain from a buffer.
     180 * @param bs Input bstream
     181 * @param len The max length in bytes that will be read.
     182 *        There are a number of places where you want to read in a tlvchain,
     183 *        but the chain is not at the end of the SNAC, and the chain is
     184 *        preceeded by the length of the TLVs.  So you can limit that with this.
     185 *
     186 * Reads and parses a series of TLV patterns from a data buffer; the
     187 * returned structure is manipulatable with the rest of the TLV
     188 * routines.  When done with a TLV chain, aim_freetlvchain() should
     189 * be called to free the dynamic substructures.
     190 *
     191 * XXX There should be a flag setable here to have the tlvlist contain
     192 * bstream references, so that at least the ->value portion of each
     193 * element doesn't need to be malloc/memcpy'd.  This could prove to be
     194 * just as effecient as the in-place TLV parsing used in a couple places
     195 * in libfaim.
     196 *
     197 */
     198faim_internal aim_tlvlist_t *aim_readtlvchain_len(aim_bstream_t *bs, fu16_t len)
     199{
     200        aim_tlvlist_t *list = NULL, *cur;
     201
     202        while ((aim_bstream_empty(bs) > 0) && (len > 0)) {
     203                fu16_t type, length;
     204
     205                type = aimbs_get16(bs);
     206                length = aimbs_get16(bs);
     207
     208                if (length > aim_bstream_empty(bs)) {
     209                        aim_freetlvchain(&list);
     210                        return NULL;
     211                }
     212
     213                cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
     214                if (!cur) {
     215                        aim_freetlvchain(&list);
     216                        return NULL;
     217                }
     218
     219                memset(cur, 0, sizeof(aim_tlvlist_t));
     220
     221                cur->tlv = createtlv();
     222                if (!cur->tlv) {
     223                        free(cur);
     224                        aim_freetlvchain(&list);
     225                        return NULL;
     226                }
     227                cur->tlv->type = type;
     228                if ((cur->tlv->length = length)) {
     229                       cur->tlv->value = aimbs_getraw(bs, length);
     230                       if (!cur->tlv->value) {
     231                               freetlv(&cur->tlv);
     232                               free(cur);
     233                               aim_freetlvchain(&list);
     234                               return NULL;
     235                       }
     236                }
     237
     238                len -= aim_sizetlvchain(&cur);
     239                cur->next = list;
     240                list = cur;
     241        }
     242
     243        return list;
     244}
     245
     246/**
     247 * aim_tlvlist_copy - Duplicate a TLV chain.
     248 * @param orig
     249 *
     250 * This is pretty pelf exslanatory.
     251 *
     252 */
     253faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig)
     254{
     255        aim_tlvlist_t *new = NULL;
     256
     257        while (orig) {
     258                aim_addtlvtochain_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value);
     259                orig = orig->next;
     260        }
     261
     262        return new;
     263}
     264
     265/*
     266 * Compare two TLV lists for equality.  This probably is not the most
     267 * efficient way to do this.
     268 *
     269 * @param one One of the TLV chains to compare.
     270 * @param two The other TLV chain to compare.
     271 * @preturn Retrun 0 if the lists are the same, return 1 if they are different.
     272 */
     273faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two)
     274{
     275        aim_bstream_t bs1, bs2;
     276
     277        if (aim_sizetlvchain(&one) != aim_sizetlvchain(&two))
     278                return 1;
     279
     280        aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_sizetlvchain(&one)*sizeof(fu8_t))), aim_sizetlvchain(&one));
     281        aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_sizetlvchain(&two)*sizeof(fu8_t))), aim_sizetlvchain(&two));
     282
     283        aim_writetlvchain(&bs1, &one);
     284        aim_writetlvchain(&bs2, &two);
     285
     286        if (memcmp(bs1.data, bs2.data, bs1.len)) {
     287                free(bs1.data);
     288                free(bs2.data);
     289                return 1;
     290        }
     291
     292        free(bs1.data);
     293        free(bs2.data);
     294
     295        return 0;
     296}
     297
     298/**
    179299 * aim_freetlvchain - Free a TLV chain structure
    180300 * @list: Chain to be freed
     
    463583
    464584        /* do an initial run to test total length */
    465         for (cur = *list, goodbuflen = 0; cur; cur = cur->next) {
    466                 goodbuflen += 2 + 2; /* type + len */
    467                 goodbuflen += cur->tlv->length;
    468         }
     585        goodbuflen = aim_sizetlvchain(list);
    469586
    470587        if (goodbuflen > aim_bstream_empty(bs))
  • libfaim/txqueue.c

    r862371b re374dee  
    2929faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen)
    3030{
    31         aim_frame_t *fr;
    32 
    33         if (!conn) {
    34                 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n");
    35                 return NULL;
    36         }
    37 
    38         /* For sanity... */
    39         if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) ||
    40                         (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) {
    41                 if (framing != AIM_FRAMETYPE_OFT) {
    42                         faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n");
    43                         return NULL;
    44                 }
    45         } else {
    46                 if (framing != AIM_FRAMETYPE_FLAP) {
    47                         faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n");
    48                         return NULL;
    49                 }
    50         }
    51 
    52         if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
    53                 return NULL;
    54         memset(fr, 0, sizeof(aim_frame_t));
    55 
    56         fr->conn = conn;
    57 
    58         fr->hdrtype = framing;
    59 
    60         if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
    61 
    62                 fr->hdr.flap.type = chan;
    63 
    64         } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) {
    65 
    66                 fr->hdr.rend.type = chan;
    67 
    68         } else
    69                 faimdprintf(sess, 0, "tx_new: unknown framing\n");
    70 
    71         if (datalen > 0) {
    72                 fu8_t *data;
    73 
    74                 if (!(data = (unsigned char *)malloc(datalen))) {
    75                         aim_frame_destroy(fr);
    76                         return NULL;
    77                 }
    78 
    79                 aim_bstream_init(&fr->data, data, datalen);
    80         }
    81 
    82         return fr;
     31  aim_frame_t *fr;
     32 
     33  if (!conn) {
     34    faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n");
     35    return NULL;
     36  }
     37 
     38  /* For sanity... */
     39  if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_LISTENER)) {
     40    if (framing != AIM_FRAMETYPE_OFT) {
     41      faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n");
     42      return NULL;
     43    }
     44  } else {
     45    if (framing != AIM_FRAMETYPE_FLAP) {
     46      faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n");
     47      return NULL;
     48    }
     49  }
     50 
     51  if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) return NULL;
     52  memset(fr, 0, sizeof(aim_frame_t));
     53 
     54  fr->conn = conn;
     55  fr->hdrtype = framing;
     56  if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
     57    fr->hdr.flap.type = chan;
     58  } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) {
     59    fr->hdr.rend.type = chan;
     60  } else {
     61    faimdprintf(sess, 0, "tx_new: unknown framing\n");
     62  }
     63 
     64  if (datalen > 0) {
     65    fu8_t *data;
     66    if (!(data = (unsigned char *)malloc(datalen))) {
     67      aim_frame_destroy(fr);
     68      return NULL;
     69    }
     70    aim_bstream_init(&fr->data, data, datalen);
     71  }
     72 
     73  return fr;
    8374}
    8475
     
    9990static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)
    10091{
    101 
    102         if (!fr->conn) {
    103                 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
    104                 fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
    105         }
    106 
    107         if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
    108                 /* assign seqnum -- XXX should really not assign until hardxmit */
    109                 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
    110         }
    111 
    112         fr->handled = 0; /* not sent yet */
    113 
    114         /* see overhead note in aim_rxqueue counterpart */
    115         if (!sess->queue_outgoing)
    116                 sess->queue_outgoing = fr;
    117         else {
    118                 aim_frame_t *cur;
    119 
    120                 for (cur = sess->queue_outgoing; cur->next; cur = cur->next)
    121                         ;
    122                 cur->next = fr;
    123         }
    124 
    125         return 0;
     92 
     93  if (!fr->conn) {
     94    faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
     95    fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
     96  }
     97 
     98  if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
     99    /* assign seqnum -- XXX should really not assign until hardxmit */
     100    fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
     101  }
     102 
     103  fr->handled = 0; /* not sent yet */
     104 
     105  /* see overhead note in aim_rxqueue counterpart */
     106  if (!sess->queue_outgoing)
     107    sess->queue_outgoing = fr;
     108  else {
     109    aim_frame_t *cur;
     110   
     111    for (cur = sess->queue_outgoing; cur->next; cur = cur->next)
     112      ;
     113    cur->next = fr;
     114  }
     115 
     116  return 0;
    126117}
    127118
     
    140131{
    141132
    142         if (!fr->conn) {
    143                 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n");
    144                 aim_frame_destroy(fr);
    145                 return 0;
    146         }
    147 
    148         if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
    149                 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
    150 
    151         fr->handled = 0; /* not sent yet */
    152 
    153         aim_tx_sendframe(sess, fr);
    154 
    155         aim_frame_destroy(fr);
    156 
    157         return 0;
     133  if (!fr->conn) {
     134    faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n");
     135    aim_frame_destroy(fr);
     136    return 0;
     137  }
     138 
     139  if (fr->hdrtype == AIM_FRAMETYPE_FLAP) fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
     140  fr->handled = 0; /* not sent yet */
     141  aim_tx_sendframe(sess, fr);
     142  aim_frame_destroy(fr);
     143 
     144  return 0;
    158145}
    159146
    160147faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *))
    161148{
    162        
    163         if (what == AIM_TX_QUEUED)
    164                 sess->tx_enqueue = &aim_tx_enqueue__queuebased;
    165         else if (what == AIM_TX_IMMEDIATE)
    166                 sess->tx_enqueue = &aim_tx_enqueue__immediate;
    167         else if (what == AIM_TX_USER) {
    168                 if (!func)
    169                         return -EINVAL;
    170                 sess->tx_enqueue = func;
    171         } else
    172                 return -EINVAL; /* unknown action */
    173 
    174         return 0;
     149  if (what == AIM_TX_QUEUED) {
     150    sess->tx_enqueue = &aim_tx_enqueue__queuebased;
     151  } else if (what == AIM_TX_IMMEDIATE) {
     152    sess->tx_enqueue = &aim_tx_enqueue__immediate;
     153  } else if (what == AIM_TX_USER) {
     154    if (!func) return -EINVAL;
     155    sess->tx_enqueue = func;
     156  } else {
     157    return -EINVAL; /* unknown action */
     158  }
     159 
     160  return 0;
    175161}
    176162
    177163faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr)
    178164{
    179        
    180         /*
    181         * If we want to send a connection thats inprogress, we have to force
    182         * them to use the queue based version. Otherwise, use whatever they
    183         * want.
    184         */
    185         if (fr && fr->conn &&
    186                         (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
    187                 return aim_tx_enqueue__queuebased(sess, fr);
    188         }
    189 
    190         return (*sess->tx_enqueue)(sess, fr);
     165 
     166  /*
     167  * If we want to send a connection thats inprogress, we have to force
     168  * them to use the queue based version. Otherwise, use whatever they
     169  * want.
     170  */
     171  if (fr && fr->conn &&
     172      (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
     173    return aim_tx_enqueue__queuebased(sess, fr);
     174  }
     175 
     176  return (*sess->tx_enqueue)(sess, fr);
    191177}
    192178
     
    202188faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn)
    203189{
    204         flap_seqnum_t ret;
    205        
    206         ret = ++conn->seqnum;
    207 
    208         return ret;
     190  flap_seqnum_t ret;
     191  ret = ++conn->seqnum;
     192  return ret;
    209193}
    210194
    211195static int aim_send(int fd, const void *buf, size_t count)
    212196{
    213         int left, cur;
    214 
    215         for (cur = 0, left = count; left; ) {
    216                 int ret;
    217 
    218                 ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
    219                 if (ret == -1)
    220                         return -1;
    221                 else if (ret == 0)
    222                         return cur;
    223 
    224                 cur += ret;
    225                 left -= ret;
    226         }
    227 
    228         return cur;
     197  int left, cur;
     198 
     199  for (cur = 0, left = count; left; ) {
     200    int ret;
     201   
     202    ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
     203    if (ret == -1) {
     204      return -1;
     205    } else if (ret == 0) {
     206      return cur;
     207    }
     208   
     209    cur += ret;
     210    left -= ret;
     211  }
     212 
     213  return cur;
    229214}
    230215
    231216static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
    232217{
    233         int wrote = 0;
    234         if (!bs || !conn || (count < 0))
    235                 return -EINVAL;
    236 
    237         if (count > aim_bstream_empty(bs))
    238                 count = aim_bstream_empty(bs); /* truncate to remaining space */
    239 
    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        
    262 
    263         if (((aim_session_t *)conn->sessv)->debug >= 2) {
    264                 int i;
    265                 aim_session_t *sess = (aim_session_t *)conn->sessv;
    266 
    267                 faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote);
    268                 for (i = 0; i < wrote; i++) {
    269                         if (!(i % 8))
    270                                 faimdprintf(sess, 2, "\n\t");
    271                         faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i));
    272                 }
    273                 faimdprintf(sess, 2, "\n");
    274         }
    275 
    276 
    277         bs->offset += wrote;
    278 
    279         return wrote;   
     218  int wrote = 0;
     219  if (!bs || !conn || (count < 0))
     220    return -EINVAL;
     221 
     222  if (count > aim_bstream_empty(bs))
     223    count = aim_bstream_empty(bs); /* truncate to remaining space */
     224 
     225  if (count) {
     226    if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) &&
     227        (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
     228      /* I strongly suspect that this is a horrible thing to do
     229       * and I feel really guilty doing it. */
     230      const char *sn = aim_odc_getsn(conn);
     231      aim_rxcallback_t userfunc;
     232      while (count - wrote > 1024) {
     233        wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, 1024);
     234        if ((userfunc=aim_callhandler(conn->sessv, conn,
     235                                      AIM_CB_FAM_SPECIAL,
     236                                      AIM_CB_SPECIAL_IMAGETRANSFER)))
     237          userfunc(conn->sessv, NULL, sn,
     238                   count-wrote>1024 ? ((double)wrote / count) : 1);
     239      }
     240    }
     241    if (count - wrote) {
     242      wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
     243    }
     244   
     245  }
     246 
     247  if (((aim_session_t *)conn->sessv)->debug >= 2) {
     248    int i;
     249    aim_session_t *sess = (aim_session_t *)conn->sessv;
     250   
     251    faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote);
     252    for (i = 0; i < wrote; i++) {
     253      if (!(i % 8))
     254        faimdprintf(sess, 2, "\n\t");
     255      faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i));
     256    }
     257    faimdprintf(sess, 2, "\n");
     258  }
     259 
     260  bs->offset += wrote;
     261 
     262  return wrote;
    280263}
    281264
    282265static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr)
    283266{
    284         aim_bstream_t obs;
    285         fu8_t *obs_raw;
    286         int payloadlen, err = 0, obslen;
    287 
    288         payloadlen = aim_bstream_curpos(&fr->data);
    289 
    290         if (!(obs_raw = malloc(6 + payloadlen)))
    291                 return -ENOMEM;
    292 
    293         aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
    294 
    295         /* FLAP header */
    296         aimbs_put8(&obs, 0x2a);
    297         aimbs_put8(&obs, fr->hdr.flap.type);
    298         aimbs_put16(&obs, fr->hdr.flap.seqnum);
    299         aimbs_put16(&obs, payloadlen);
    300 
    301         /* payload */
    302         aim_bstream_rewind(&fr->data);
    303         aimbs_putbs(&obs, &fr->data, payloadlen);
    304 
    305         obslen = aim_bstream_curpos(&obs);
    306         aim_bstream_rewind(&obs);
    307         if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)
    308                 err = -errno;
    309        
    310         free(obs_raw); /* XXX aim_bstream_free */
    311 
    312         fr->handled = 1;
    313         fr->conn->lastactivity = time(NULL);
    314 
    315         return err;
     267  aim_bstream_t obs;
     268  fu8_t *obs_raw;
     269  int payloadlen, err = 0, obslen;
     270 
     271  payloadlen = aim_bstream_curpos(&fr->data);
     272 
     273  if (!(obs_raw = malloc(6 + payloadlen)))
     274    return -ENOMEM;
     275 
     276  aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
     277 
     278  /* FLAP header */
     279  aimbs_put8(&obs, 0x2a);
     280  aimbs_put8(&obs, fr->hdr.flap.type);
     281  aimbs_put16(&obs, fr->hdr.flap.seqnum);
     282  aimbs_put16(&obs, payloadlen);
     283 
     284  /* payload */
     285  aim_bstream_rewind(&fr->data);
     286  aimbs_putbs(&obs, &fr->data, payloadlen);
     287 
     288  obslen = aim_bstream_curpos(&obs);
     289  aim_bstream_rewind(&obs);
     290  if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)
     291    err = -errno;
     292 
     293  free(obs_raw); /* XXX aim_bstream_free */
     294 
     295  fr->handled = 1;
     296  fr->conn->lastactivity = time(NULL);
     297 
     298  return err;
    316299}
    317300
  • libfaim/util.c

    r862371b re374dee  
    11/*
    2  *
    3  *
    4  *
     2 * A little bit of this
     3 * A little bit of that
     4 * It started with a kiss
     5 * Now we're up to bat
    56 */
    67
     
    910#include <ctype.h>
    1011
    11 faim_export faim_shortfunc int aimutil_putstr(u_char *dest, const char *src, int len)
     12#ifdef _WIN32
     13#include "win32dep.h"
     14#endif
     15
     16faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...)
     17{
     18        if (!sess) {
     19                fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format);
     20                return;
     21        }
     22        if ((dlevel <= sess->debug) && sess->debugcb) {
     23                va_list ap;
     24                va_start(ap, format);
     25                sess->debugcb(sess, dlevel, format, ap);
     26                va_end(ap);
     27        }
     28
     29        return;
     30}
     31
     32faim_export int aimutil_putstr(char *dest, const char *src, int len)
    1233{
    1334        memcpy(dest, src, len);
     
    2041 *
    2142 */
    22 faim_export int aimutil_tokslen(char *toSearch, int index, char dl)
     43faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl)
    2344{
    2445        int curCount = 1;
     
    3051        next = strchr(toSearch, dl);
    3152
    32         while(curCount < index && next != NULL) {
     53        while(curCount < theindex && next != NULL) {
    3354                curCount++;
    3455                last = next + 1;
     
    3657        }
    3758
    38         if ((curCount < index) || (next == NULL))
     59        if ((curCount < theindex) || (next == NULL))
    3960                toReturn = strlen(toSearch) - (curCount - 1);
    4061        else
     
    6182}
    6283
    63 faim_export char *aimutil_itemidx(char *toSearch, int index, char dl)
     84faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl)
    6485{
    6586        int curCount;
     
    7394        next = strchr(toSearch, dl);
    7495
    75         while (curCount < index && next != NULL) {
     96        while (curCount < theindex && next != NULL) {
    7697                curCount++;
    7798                last = next + 1;
     
    79100        }
    80101
    81         if (curCount < index) {
     102        if (curCount < theindex) {
    82103                toReturn = malloc(sizeof(char));
    83104                *toReturn = '\0';
     
    85106        next = strchr(last, dl);
    86107
    87         if (curCount < index) {
     108        if (curCount < theindex) {
    88109                toReturn = malloc(sizeof(char));
    89110                *toReturn = '\0';
     
    101122}
    102123
     124/**
     125 * Calculate the checksum of a given icon.
     126 *
     127 */
     128faim_export fu16_t aimutil_iconsum(const fu8_t *buf, int buflen)
     129{
     130        fu32_t sum;
     131        int i;
     132
     133        for (i=0, sum=0; i+1<buflen; i+=2)
     134                sum += (buf[i+1] << 8) + buf[i];
     135        if (i < buflen)
     136                sum += buf[i];
     137        sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
     138
     139        return sum;
     140}
     141
     142faim_export int aim_util_getlocalip(fu8_t *ip)
     143{
     144        struct hostent *hptr;
     145        char localhost[129];
     146
     147        /* XXX if available, use getaddrinfo() */
     148        /* XXX allow client to specify which IP to use for multihomed boxes */
     149
     150        if (gethostname(localhost, 128) < 0)
     151                return -1;
     152
     153        if (!(hptr = gethostbyname(localhost)))
     154                return -1;
     155        memcpy(ip, hptr->h_addr_list[0], 4);
     156
     157        return 0;
     158}
     159
    103160/*
    104161* int snlen(const char *)
     
    112169{
    113170        int i = 0;
    114         const char *curPtr = NULL;
    115171
    116172        if (!sn)
    117173                return 0;
    118174
    119         curPtr = sn;
    120         while ( (*curPtr) != (char) NULL) {
    121                 if ((*curPtr) != ' ')
    122                 i++;
    123                 curPtr++;
     175        while (*sn != '\0') {
     176                if (*sn != ' ')
     177                        i++;
     178                sn++;
    124179        }
    125180
     
    133188* on screen names for AIM/AOL.  Mainly, this means case and space
    134189* insensitivity (all case differences and spacing differences are
    135 * ignored).
     190* ignored, with the exception that screen names can not start with
     191* a space).
    136192*
    137193* Return: 0 if equal
     
    141197faim_export int aim_sncmp(const char *sn1, const char *sn2)
    142198{
    143         const char *curPtr1 = NULL, *curPtr2 = NULL;
    144 
    145         if (aim_snlen(sn1) != aim_snlen(sn2))
    146                 return 1;
    147 
    148         curPtr1 = sn1;
    149         curPtr2 = sn2;
    150         while ( (*curPtr1 != (char) NULL) && (*curPtr2 != (char) NULL) ) {
    151                 if ( (*curPtr1 == ' ') || (*curPtr2 == ' ') ) {
    152                         if (*curPtr1 == ' ')
    153                                 curPtr1++;
    154                         if (*curPtr2 == ' ')
    155                                 curPtr2++;
    156                 } else {
    157                         if ( toupper(*curPtr1) != toupper(*curPtr2))
    158                                 return 1;
    159                         curPtr1++;
    160                         curPtr2++;
    161                 }
    162         }
    163 
    164         /* Should both be NULL */
    165         if (*curPtr1 != *curPtr2)
    166                 return 1;
     199
     200        do {
     201                while (*sn2 == ' ')
     202                        sn2++;
     203                while (*sn1 == ' ')
     204                        sn1++;
     205                if (toupper(*sn1) != toupper(*sn2))
     206                        return 1;
     207        } while ((*sn1 != '\0') && sn1++ && sn2++);
    167208
    168209        return 0;
    169210}
    170 
    171 /* strsep Copyright (C) 1992, 1993 Free Software Foundation, Inc.
    172 strsep is part of the GNU C Library.
    173 
    174 The GNU C Library is free software; you can redistribute it and/or
    175 modify it under the terms of the GNU Library General Public License as
    176 published by the Free Software Foundation; either version 2 of the
    177 License, or (at your option) any later version.
    178 
    179 The GNU C Library is distributed in the hope that it will be useful,
    180 but WITHOUT ANY WARRANTY; without even the implied warranty of
    181 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    182 Library General Public License for more details.
    183 
    184 You should have received a copy of the GNU Library General Public
    185 License along with the GNU C Library; see the file COPYING.LIB.  If
    186 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
    187 Cambridge, MA 02139, USA.  */
    188 
    189 /* Minor changes by and1000 on 15/1/97 to make it go under Nemesis */
    190 
    191 faim_export char *aim_strsep(char **pp, const char *delim)
    192 {
    193         char *p, *q;
    194 
    195         if (!(p = *pp))
    196                 return 0;
    197 
    198         if ((q = strpbrk (p, delim))) {
    199                 *pp = q + 1;
    200                 *q = '\0';
    201         } else
    202                 *pp = 0;
    203 
    204         return p;
    205 }
Note: See TracChangeset for help on using the changeset viewer.