Changeset 862371b for libfaim/im.c


Ignore:
Timestamp:
Jun 29, 2003, 1:47:04 PM (18 years ago)
Author:
James M. Kretchmar <kretch@mit.edu>
Branches:
master, barnowl_perlaim, debian, owl, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
e016fc2
Parents:
03ad7b2
Message:
*** empty log message ***
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libfaim/im.c

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