comparison src/protocols/oscar/im.c @ 3952:07283934dedd

[gaim-migrate @ 4133] Ok, big commit with little functionality change. Most of it is me shuffling crap around because I'm one of them neat freaks. Lots of general code cleanup too. I'm trying to move to that whole "one-family-per-file" thing. The details... I added libfaim support for aim's new search family, 0x000f. I only tested this briefly, so if anyone uses it for anything, be aware that it could be buggy. I'll add oscar support sometime. Advantages of this family are... when you search for someone, you get the directory info for that person. So like, first name, middle name, last name, maiden name, city, state, country, zip, address, interests, nickname, and maybe some other stuff. Basically all the info that they've set in their directory info thing. Info. Oh, and I'm calling it "new search" because seach was already taken, and cookie monster ate my right brain. The reason I didn't add support to oscar.c... the new search family requires making a connection to another server. While moving stuff around I realized that I didn't really like how new connections are made. It's kind of sloppy. I'm thinking it would be nice to have an outgoing queue for each type of connection, and then let the client queue messages as much as they want. Then, if libfaim sees that there is a message for a certain type of connection, and there is no open connection of that type, it will connect, and then flush the queue when the connection is made. This seems a lot cleaner, but it also seems like a pain in the ass. I should do ssi for icq first, anyway :-) Also, I think it would be neat if there was an ICBM file that handled channels 1 through 4. Then im.c and chat.c could pass the ICBM part to the icbm stuff and it could get parsed there. im.c is really huge right now. I applied a patch from Graham Booker that paves the way for unicode in direct IMs. Thanks Graham. Now we just need Paco-Paco to git a little free time and write a patch for this. http://sourceforge.net/tracker/index.php?func=detail&aid=633589&group_id=235&atid=300235 I applied 2 patches from Will Mahan dealing with file transfer/oft/rendezous/whatever. Here's some info on them, from The Man himself: Patch 1 "Currently the Rendezvous code is rather messy; this patch attempts to bring it up to speed with the rest of the Oscar prpl. Its changes include: * Rewrite several ft.c functions to use bstreams. Apparently the code in question was written before bstreams were implemented. * Handle incoming Rendezvous packets through the rxqueue like FLAP packets, rather than handling them as a special case as soon as they are received. This takes advantage of the bstream cleanup to unify some code and simplify the aim_frame_t struct. * Change some names used to try to clarify the distinction between OFT, which refers specifically to file transfer, and Rendezvous, which encompasses OFT as well as other types of client-to-client connections." Patch 2 "* Add some comments I inadvertently left out of my last patch. * Fix a double-free that occurs when connections time out. * Correct a bug causing filenames to be truncated by 4 characters on some clients. * Preserve directory structure when sending multiple files. * Handle (throw away) resource forks sent by Mac clients." I also changed all indents to tabs in ft.c. And split all the bstream stuff from rxqueue.c and put it in bstream.c. It really is a separate thing. Especially since it can be used for outgoing connections. Also, I was going to look over the whole patch tonight to make sure it's all good, but it's like 6000 lines, so, uh, I'll do it later. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 13 Nov 2002 07:01:37 +0000
parents 765769211688
children 2532f1192da3
comparison
equal deleted inserted replaced
3951:32942c49dced 3952:07283934dedd
6 * the ICBM types (family 4), a channel is defined. Each channel 6 * the ICBM types (family 4), a channel is defined. Each channel
7 * represents a different type of message. Channel 1 is used for 7 * represents a different type of message. Channel 1 is used for
8 * what would commonly be called an "instant message". Channel 2 8 * what would commonly be called an "instant message". Channel 2
9 * is used for negotiating "rendezvous". These transactions end in 9 * is used for negotiating "rendezvous". These transactions end in
10 * something more complex happening, such as a chat invitation, or 10 * something more complex happening, such as a chat invitation, or
11 * a file transfer. Channel 4 is used for various ICQ messages. 11 * a file transfer. Channel 3 is used for chat messages (not in
12 * Examples are normal messages, URLs, and old-style authorization. 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.
13 * 15 *
14 * In addition to the channel, every ICBM contains a cookie. For 16 * In addition to the channel, every ICBM contains a cookie. For
15 * standard IMs, these are only used for error messages. However, 17 * standard IMs, these are only used for error messages. However,
16 * the more complex rendezvous messages make suitably more complex 18 * the more complex rendezvous messages make suitably more complex
17 * use of this field. 19 * use of this field.
86 } 88 }
87 89
88 return AIM_CLIENTTYPE_UNKNOWN; 90 return AIM_CLIENTTYPE_UNKNOWN;
89 } 91 }
90 92
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 */
100 faim_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. */
134 faim_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 */
145 static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
146 {
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
91 /* This should be endian-safe now... but who knows... */ 163 /* This should be endian-safe now... but who knows... */
92 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen) 164 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen)
93 { 165 {
94 fu32_t sum; 166 fu32_t sum;
95 int i; 167 int i;
103 175
104 return (fu16_t)sum; 176 return (fu16_t)sum;
105 } 177 }
106 178
107 /* 179 /*
108 * Send an ICBM (instant message). 180 * Subtype 0x0006 - Send an ICBM (instant message).
109 * 181 *
110 * 182 *
111 * Possible flags: 183 * Possible flags:
112 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse 184 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse
113 * AIM_IMFLAGS_ACK -- Requests that the server send an ack 185 * AIM_IMFLAGS_ACK -- Requests that the server send an ack
371 443
372 return aim_send_im_ext(sess, &args); 444 return aim_send_im_ext(sess, &args);
373 } 445 }
374 446
375 /* 447 /*
448 * Subtype 0x0006
449 *
376 * This is also performance sensitive. (If you can believe it...) 450 * This is also performance sensitive. (If you can believe it...)
377 * 451 *
378 */ 452 */
379 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) 453 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum)
380 { 454 {
454 528
455 return 0; 529 return 0;
456 } 530 }
457 531
458 /* 532 /*
533 * Subtype 0x0006
534 *
459 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only 535 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only
460 * send it to clients advertising the RTF capability. In fact, if you send 536 * send it to clients advertising the RTF capability. In fact, if you send
461 * it to a client that doesn't support that capability, the server will gladly 537 * it to a client that doesn't support that capability, the server will gladly
462 * bounce it back to you. 538 * bounce it back to you.
463 * 539 *
569 aim_tx_enqueue(sess, fr); 645 aim_tx_enqueue(sess, fr);
570 646
571 return 0; 647 return 0;
572 } 648 }
573 649
650 /* Subtype 0x0006 */
574 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret) 651 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret)
575 { 652 {
576 aim_conn_t *conn; 653 aim_conn_t *conn;
577 fu8_t ck[8]; 654 fu8_t ck[8];
578 aim_frame_t *fr; 655 aim_frame_t *fr;
645 aim_tx_enqueue(sess, fr); 722 aim_tx_enqueue(sess, fr);
646 723
647 return 0; 724 return 0;
648 } 725 }
649 726
727 /* Subtype 0x0006 */
650 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) 728 faim_internal int aim_request_sendfile(aim_session_t *sess, const char *sn, const char *filename, fu16_t numfiles, fu32_t totsize, fu8_t *ip, fu16_t port, fu8_t *ckret)
651 { 729 {
652 aim_conn_t *conn; 730 aim_conn_t *conn;
653 int i; 731 int i;
654 fu8_t ck[8]; 732 fu8_t ck[8];
751 829
752 return 0; 830 return 0;
753 } 831 }
754 832
755 /** 833 /**
756 * Request the status message of the given ICQ user. 834 * Subtype 0x0006 - Request the status message of the given ICQ user.
757 * 835 *
758 * @param sess The oscar session. 836 * @param sess The oscar session.
759 * @param sn The UIN of the user of whom you wish to request info. 837 * @param sn The UIN of the user of whom you wish to request info.
760 * @param type The type of info you wish to request. This should be the current 838 * @param type The type of info you wish to request. This should be the current
761 * state of the user, as one of the AIM_ICQ_STATE_* defines. 839 * state of the user, as one of the AIM_ICQ_STATE_* defines.
815 /* TLV t(2711) */ 893 /* TLV t(2711) */
816 aimbs_put16(&fr->data, 0x2711); 894 aimbs_put16(&fr->data, 0x2711);
817 aimbs_put16(&fr->data, 0x0036); 895 aimbs_put16(&fr->data, 0x0036);
818 { /* V */ 896 { /* V */
819 aimbs_putle16(&fr->data, 0x001b); /* L */ 897 aimbs_putle16(&fr->data, 0x001b); /* L */
820 aimbs_putle16(&fr->data, 0x0008); /* AAA - Protocol version */ 898 aimbs_putle16(&fr->data, 0x0008); /* XXX - Protocol version */
821 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ 899 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
822 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ 900 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
823 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ 901 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
824 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ 902 aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
825 aimbs_putle16(&fr->data, 0x0000); /* Unknown */ 903 aimbs_putle16(&fr->data, 0x0000); /* Unknown */
861 939
862 return 0; 940 return 0;
863 } 941 }
864 942
865 /** 943 /**
944 * Subtype 0x0006
945 *
866 * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way." 946 * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way."
867 * The new way is to use SSI. I like the new way a lot better. This seems like such a hack, 947 * The new way is to use SSI. I like the new way a lot better. This seems like such a hack,
868 * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while, 948 * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while,
869 * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people 949 * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people
870 * were taking when they merged the two protocols. 950 * were taking when they merged the two protocols.
1552 { 1632 {
1553 1633
1554 args->destructor = (void *)incomingim_ch2_sendfile_free; 1634 args->destructor = (void *)incomingim_ch2_sendfile_free;
1555 1635
1556 if (servdata) { 1636 if (servdata) {
1637 int flen;
1638
1557 /* subtype is one of AIM_OFT_SUBTYPE_* */ 1639 /* subtype is one of AIM_OFT_SUBTYPE_* */
1558 args->info.sendfile.subtype = aimbs_get16(servdata); 1640 args->info.sendfile.subtype = aimbs_get16(servdata);
1559 args->info.sendfile.totfiles = aimbs_get16(servdata); 1641 args->info.sendfile.totfiles = aimbs_get16(servdata);
1560 args->info.sendfile.totsize = aimbs_get32(servdata); 1642 args->info.sendfile.totsize = aimbs_get32(servdata);
1561 args->info.sendfile.filename = aimbs_getstr(servdata, 1643
1562 servdata->len - (2+2+4+4)); 1644 /* XXX - create an aimbs_getnullstr function */
1563 1645 /* Use an inelegant way of getting the null-terminated filename,
1564 aimbs_get32(servdata); /* 0x00030000 (?) */ 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. */
1565 } 1653 }
1566 1654
1567 return; 1655 return;
1568 } 1656 }
1569 1657
1784 1872
1785 return ret; 1873 return ret;
1786 } 1874 }
1787 1875
1788 /* 1876 /*
1877 * Subtype 0x0007
1878 *
1789 * It can easily be said that parsing ICBMs is THE single 1879 * It can easily be said that parsing ICBMs is THE single
1790 * most difficult thing to do in the in AIM protocol. In 1880 * most difficult thing to do in the in AIM protocol. In
1791 * fact, I think I just did say that. 1881 * fact, I think I just did say that.
1792 * 1882 *
1793 * Below is the best damned solution I've come up with 1883 * Below is the best damned solution I've come up with
1887 1977
1888 return ret; 1978 return ret;
1889 } 1979 }
1890 1980
1891 /* 1981 /*
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 */
1990 faim_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 */
2016 static 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 *
1892 * Possible codes: 2040 * Possible codes:
1893 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" 2041 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
1894 * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer" 2042 * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
1895 * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" 2043 * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
1896 * 2044 *
1925 2073
1926 return 0; 2074 return 0;
1927 } 2075 }
1928 2076
1929 /* 2077 /*
1930 * aim_reqicbmparaminfo() 2078 * Subtype 0x000b - Receive the response from an ICQ status message request.
1931 * 2079 *
1932 * Request ICBM parameter information. 2080 * This contains the ICQ status message. Go figure.
1933 * 2081 *
1934 */
1935 faim_export int aim_reqicbmparams(aim_session_t *sess)
1936 {
1937 aim_conn_t *conn;
1938
1939 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
1940 return -EINVAL;
1941
1942 return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
1943 }
1944
1945 /*
1946 *
1947 * I definitly recommend sending this. If you don't, you'll be stuck
1948 * with the rather unreasonable defaults. You don't want those. Send this.
1949 *
1950 */
1951 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)
1952 {
1953 aim_conn_t *conn;
1954 aim_frame_t *fr;
1955 aim_snacid_t snacid;
1956
1957 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
1958 return -EINVAL;
1959
1960 if (!params)
1961 return -EINVAL;
1962
1963 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16)))
1964 return -ENOMEM;
1965
1966 snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
1967 aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
1968
1969 /* This is read-only (see Parameter Reply). Must be set to zero here. */
1970 aimbs_put16(&fr->data, 0x0000);
1971
1972 /* These are all read-write */
1973 aimbs_put32(&fr->data, params->flags);
1974 aimbs_put16(&fr->data, params->maxmsglen);
1975 aimbs_put16(&fr->data, params->maxsenderwarn);
1976 aimbs_put16(&fr->data, params->maxrecverwarn);
1977 aimbs_put32(&fr->data, params->minmsginterval);
1978
1979 aim_tx_enqueue(sess, fr);
1980
1981 return 0;
1982 }
1983
1984 static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
1985 {
1986 struct aim_icbmparameters params;
1987 aim_rxcallback_t userfunc;
1988
1989 params.maxchan = aimbs_get16(bs);
1990 params.flags = aimbs_get32(bs);
1991 params.maxmsglen = aimbs_get16(bs);
1992 params.maxsenderwarn = aimbs_get16(bs);
1993 params.maxrecverwarn = aimbs_get16(bs);
1994 params.minmsginterval = aimbs_get32(bs);
1995
1996 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
1997 return userfunc(sess, rx, &params);
1998
1999 return 0;
2000 }
2001
2002 static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2003 {
2004 int ret = 0;
2005 aim_rxcallback_t userfunc;
2006 fu16_t channel, nummissed, reason;
2007 aim_userinfo_t userinfo;
2008
2009 while (aim_bstream_empty(bs)) {
2010
2011 channel = aimbs_get16(bs);
2012 aim_extractuserinfo(sess, bs, &userinfo);
2013 nummissed = aimbs_get16(bs);
2014 reason = aimbs_get16(bs);
2015
2016 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2017 ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
2018 }
2019
2020 return ret;
2021 }
2022
2023 /*
2024 * Receive the response from an ICQ status message request. This contains the
2025 * ICQ status message. Go figure.
2026 */ 2082 */
2027 static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2083 static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2028 { 2084 {
2029 int ret = 0; 2085 int ret = 0;
2030 aim_rxcallback_t userfunc; 2086 aim_rxcallback_t userfunc;
2036 channel = aimbs_get16(bs); 2092 channel = aimbs_get16(bs);
2037 snlen = aimbs_get8(bs); 2093 snlen = aimbs_get8(bs);
2038 sn = aimbs_getstr(bs, snlen); 2094 sn = aimbs_getstr(bs, snlen);
2039 reason = aimbs_get16(bs); 2095 reason = aimbs_get16(bs);
2040 2096
2041 if (channel == 2) { 2097 if (channel == 0x0002) { /* File transfer declined */
2042 /* File transfer declined. */
2043 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2098 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2044 ret = userfunc(sess, rx, channel, sn, reason, ck); 2099 ret = userfunc(sess, rx, channel, sn, reason, ck);
2045 2100 } else if (channel == 0x0004) { /* ICQ message */
2046 free(sn); 2101 switch (reason) {
2047 free(ck); 2102 case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */
2048 return ret; 2103 fu8_t statusmsgtype, *msg;
2049 } 2104 fu16_t len;
2050 2105 fu32_t state;
2051 switch (reason) { 2106
2052 case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */ 2107 len = aimbs_getle16(bs); /* Should be 0x001b */
2053 fu8_t statusmsgtype, *msg; 2108 aim_bstream_advance(bs, len); /* Unknown */
2054 fu16_t len; 2109
2055 fu32_t state; 2110 len = aimbs_getle16(bs); /* Should be 0x000e */
2056 2111 aim_bstream_advance(bs, len); /* Unknown */
2057 len = aimbs_getle16(bs); /* Should be 0x001b */ 2112
2058 aim_bstream_advance(bs, len); /* Unknown */ 2113 statusmsgtype = aimbs_getle8(bs);
2059 2114 switch (statusmsgtype) {
2060 len = aimbs_getle16(bs); /* Should be 0x000e */ 2115 case 0xe8:
2061 aim_bstream_advance(bs, len); /* Unknown */ 2116 state = AIM_ICQ_STATE_AWAY;
2062 2117 break;
2063 statusmsgtype = aimbs_getle8(bs); 2118 case 0xe9:
2064 switch (statusmsgtype) { 2119 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
2065 case 0xe8: 2120 break;
2066 state = AIM_ICQ_STATE_AWAY; 2121 case 0xea:
2067 break; 2122 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_OUT;
2068 case 0xe9: 2123 break;
2069 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY; 2124 case 0xeb:
2070 break; 2125 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
2071 case 0xea: 2126 break;
2072 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_OUT; 2127 case 0xec:
2073 break; 2128 state = AIM_ICQ_STATE_CHAT;
2074 case 0xeb: 2129 break;
2075 state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY; 2130 default:
2076 break; 2131 state = 0;
2077 case 0xec: 2132 break;
2078 state = AIM_ICQ_STATE_CHAT; 2133 }
2079 break; 2134
2080 default: 2135 aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
2081 state = 0; 2136 aimbs_getle16(bs); /* Unknown - 0x0000 */
2082 break; 2137 aimbs_getle16(bs); /* Unknown - 0x0000 */
2083 } 2138
2084 2139 len = aimbs_getle16(bs);
2085 aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */ 2140 msg = aimbs_getraw(bs, len);
2086 aimbs_getle16(bs); /* Unknown - 0x0000 */ 2141
2087 aimbs_getle16(bs); /* Unknown - 0x0000 */ 2142 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2088 2143 ret = userfunc(sess, rx, channel, sn, reason, state, msg);
2089 len = aimbs_getle16(bs); 2144
2090 msg = aimbs_getraw(bs, len); 2145 free(msg);
2091 2146 } break;
2092 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2147
2093 ret = userfunc(sess, rx, channel, sn, reason, state, msg); 2148 default: {
2094 2149 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2095 free(msg); 2150 ret = userfunc(sess, rx, channel, sn, reason);
2096 } break; 2151 } break;
2097 2152 } /* end switch */
2098 default: { 2153 }
2099 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2100 ret = userfunc(sess, rx, channel, sn, reason);
2101 } break;
2102 } /* end switch */
2103 2154
2104 free(ck); 2155 free(ck);
2105 free(sn); 2156 free(sn);
2106 2157
2107 return ret; 2158 return ret;
2108 } 2159 }
2109 2160
2161 /* Subtype 0x000c */
2110 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2162 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2111 { 2163 {
2112 aim_rxcallback_t userfunc; 2164 aim_rxcallback_t userfunc;
2113 fu16_t type; 2165 fu16_t type;
2114 fu8_t snlen, *ck; 2166 fu8_t snlen, *ck;
2128 2180
2129 return ret; 2181 return ret;
2130 } 2182 }
2131 2183
2132 /* 2184 /*
2133 * Send a mini typing notification (mtn) packet. This is supported by winaim 5 and up. 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 *
2134 */ 2190 */
2135 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2) 2191 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2)
2136 { 2192 {
2137 aim_conn_t *conn; 2193 aim_conn_t *conn;
2138 aim_frame_t *fr; 2194 aim_frame_t *fr;
2179 2235
2180 return 0; 2236 return 0;
2181 } 2237 }
2182 2238
2183 /* 2239 /*
2184 * Receive a mini typing notification (mtn) packet. This is supported by winaim5 and up. 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 *
2185 */ 2245 */
2186 static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2246 static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2187 { 2247 {
2188 int ret = 0; 2248 int ret = 0;
2189 aim_rxcallback_t userfunc; 2249 aim_rxcallback_t userfunc;
2237 } 2297 }
2238 /* Note that we return 1 for success, 0 for failure. */ 2298 /* Note that we return 1 for success, 0 for failure. */
2239 return ret; 2299 return ret;
2240 } 2300 }
2241 2301
2242
2243 faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod) 2302 faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod)
2244 { 2303 {
2245 2304
2246 mod->family = 0x0004; 2305 mod->family = 0x0004;
2247 mod->version = 0x0001; 2306 mod->version = 0x0001;