Changeset 862371b for libfaim/im.c
- Timestamp:
- Jun 29, 2003, 1:47:04 PM (21 years ago)
- Branches:
- master, barnowl_perlaim, debian, owl, release-1.10, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
- Children:
- e016fc2
- Parents:
- 03ad7b2
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfaim/im.c
r5e53c4a r862371b 1 1 /* 2 * aim_im.c 3 * 4 * The routines for sending/receiving Instant Messages. 2 * Family 0x0004 - Routines for sending/receiving Instant Messages. 5 3 * 6 4 * Note the term ICBM (Inter-Client Basic Message) which blankets … … 11 9 * is used for negotiating "rendezvous". These transactions end in 12 10 * 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. 14 15 * 15 16 * In addition to the channel, every ICBM contains a cookie. For … … 22 23 #define FAIM_INTERNAL 23 24 #include <aim.h> 25 26 #ifdef _WIN32 27 #include "win32dep.h" 28 #endif 24 29 25 30 /* … … 37 42 * 4.3.2229, 4.4.2286 38 43 * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here) 44 * 0501 0003 0101 02 WinAIM 5 45 * 0501 0001 01 iChat x.x 39 46 * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any 40 47 * TOC client … … 84 91 } 85 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, ¶ms); 159 160 return 0; 161 } 162 86 163 /* This should be endian-safe now... but who knows... */ 87 164 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen) … … 101 178 102 179 /* 103 * S end an ICBM (instant message).180 * Subtype 0x0006 - Send an ICBM (instant message). 104 181 * 105 182 * … … 195 272 } 196 273 197 198 274 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) 199 275 return -ENOMEM; … … 315 391 /* 316 392 * 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. 317 395 */ 318 396 if (args->flags & AIM_IMFLAGS_HASICON) { … … 327 405 /* 328 406 * Set the Buddy Icon Requested flag. 407 * XXX - Everytime? Surely not... 329 408 */ 330 409 if (args->flags & AIM_IMFLAGS_BUDDYREQ) { … … 367 446 368 447 /* 448 * Subtype 0x0006 449 * 369 450 * This is also performance sensitive. (If you can believe it...) 370 451 * … … 450 531 451 532 /* 533 * Subtype 0x0006 534 * 452 535 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only 453 536 * send it to clients advertising the RTF capability. In fact, if you send … … 565 648 } 566 649 650 /* Subtype 0x0006 */ 567 651 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret) 568 652 { … … 641 725 } 642 726 727 /* Subtype 0x0006 */ 643 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) 644 729 { … … 648 733 aim_frame_t *fr; 649 734 aim_snacid_t snacid; 735 struct aim_snac_destructor snacdest; 650 736 651 737 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) … … 657 743 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4))) 658 744 return -ENOMEM; 659 660 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);661 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);662 745 663 746 for (i = 0; i < 7; i++) … … 667 750 if (ckret) 668 751 memcpy(ckret, ck, 8); 752 753 /* Fill in the snac destructor so we know if the request 754 * times out. Use the cookie in the data field, so we 755 * know what request to cancel if there is an error. 756 */ 757 snacdest.data = malloc(8); 758 memcpy(snacdest.data, ck, 8); 759 snacdest.conn = conn; 760 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, &snacdest, sizeof(snacdest)); 761 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 669 762 670 763 /* … … 720 813 721 814 /* ? */ 722 aimbs_put16(&fr->data, 0x0001);815 aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001); 723 816 aimbs_put16(&fr->data, numfiles); 724 817 aimbs_put32(&fr->data, totsize); … … 727 820 /* ? */ 728 821 aimbs_put32(&fr->data, 0x00000000); 822 823 #if 0 824 /* Newer clients seem to send this (?) -- wtm */ 825 aimbs_put32(&fr->data, 0x00030000); 826 #endif 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 */ 842 faim_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 */ 957 faim_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); 729 1018 730 1019 aim_tx_enqueue(sess, fr); … … 1157 1446 args.icbmflags |= AIM_IMFLAGS_BUDDYREQ; 1158 1447 1448 } else if (type == 0x000b) { /* Non-direct connect typing notification */ 1449 1450 args.icbmflags |= AIM_IMFLAGS_TYPINGNOT; 1451 1159 1452 } else if (type == 0x0017) { 1160 1453 … … 1331 1624 } 1332 1625 1626 static void incomingim_ch2_sendfile_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args) 1627 { 1628 free(args->info.sendfile.filename); 1629 } 1630 1631 static 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 1333 1658 typedef void (*ch2_args_destructor_t)(aim_session_t *sess, struct aim_incomingim_ch2_args *args); 1334 1659 … … 1358 1683 * First two bytes represent the status of the connection. 1359 1684 * 1360 * 0 is a request, 1 is a deny (?), 2 is an accept1685 * 0 is a request, 1 is a cancel, 2 is an accept 1361 1686 */ 1362 1687 args.status = aimbs_get16(&bbs); … … 1502 1827 else if (args.reqclass & AIM_CAPS_ICQSERVERRELAY) 1503 1828 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); 1504 1831 1505 1832 … … 1520 1847 } 1521 1848 1849 static 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 1522 1876 /* 1877 * Subtype 0x0007 1878 * 1523 1879 * It can easily be said that parsing ICBMs is THE single 1524 1880 * most difficult thing to do in the in AIM protocol. In … … 1557 1913 * is where Chat Invitiations and various client-client 1558 1914 * connection negotiations come from. 1559 * 1915 * 1916 * Channel 0x0004 is used for ICQ authorization, or 1917 * possibly any system notice. 1918 * 1560 1919 */ 1561 1920 channel = aimbs_get16(bs); … … 1603 1962 aim_freetlvchain(&tlvlist); 1604 1963 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 1605 1971 } else { 1606 1972 … … 1614 1980 1615 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 * 1616 2040 * Possible codes: 1617 2041 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" … … 1652 2076 1653 2077 /* 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. 1657 2081 * 1658 2082 */ 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, ¶ms); 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) 2083 static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1748 2084 { 1749 2085 int ret = 0; … … 1759 2095 reason = aimbs_get16(bs); 1760 2096 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 } 1763 2154 1764 2155 free(ck); … … 1768 2159 } 1769 2160 2161 /* Subtype 0x000c */ 1770 2162 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1771 2163 { … … 1786 2178 free(sn); 1787 2179 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 */ 2191 faim_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 */ 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) 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); 1788 2264 1789 2265 return ret; … … 1802 2278 return missedcall(sess, mod, rx, snac, bs); 1803 2279 else if (snac->subtype == 0x000b) 1804 return client err(sess, mod, rx, snac, bs);2280 return clientautoresp(sess, mod, rx, snac, bs); 1805 2281 else if (snac->subtype == 0x000c) 1806 2282 return msgack(sess, mod, rx, snac, bs); 2283 else if (snac->subtype == 0x0014) 2284 return mtn_receive(sess, mod, rx, snac, bs); 1807 2285 1808 2286 return 0; 2287 } 2288 2289 static int snacdestructor(aim_session_t *sess, aim_conn_t *conn, aim_modsnac_t *snac, void *data) 2290 { 2291 aim_rxcallback_t userfunc; 2292 int ret = 0; 2293 2294 if (snac->subtype == 0x0006) { 2295 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_MSGTIMEOUT))) 2296 ret = userfunc(sess, NULL, conn, data); 2297 } 2298 /* Note that we return 1 for success, 0 for failure. */ 2299 return ret; 1809 2300 } 1810 2301 … … 1819 2310 strncpy(mod->name, "messaging", sizeof(mod->name)); 1820 2311 mod->snachandler = snachandler; 2312 mod->snacdestructor = snacdestructor; 1821 2313 1822 2314 return 0;
Note: See TracChangeset
for help on using the changeset viewer.