Changeset e374dee


Ignore:
Timestamp:
Oct 10, 2003, 5:12:30 PM (21 years ago)
Author:
James M. Kretchmar <kretch@mit.edu>
Branches:
master, barnowl_perlaim, debian, owl, release-1.10, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
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