- Timestamp:
- Jun 29, 2003, 1:47:04 PM (23 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
- Location:
- libfaim
- Files:
-
- 3 added
- 32 edited
-
Makefile.in (modified) (1 diff)
-
admin.c (modified) (2 diffs)
-
adverts.c (modified) (2 diffs)
-
aim.h (modified) (27 diffs)
-
aim_cbtypes.h (modified) (8 diffs)
-
aim_internal.h (modified) (6 diffs)
-
auth.c (modified) (9 diffs)
-
bos.c (modified) (5 diffs)
-
bstream.c (added)
-
buddylist.c (modified) (5 diffs)
-
chat.c (modified) (5 diffs)
-
chatnav.c (modified) (5 diffs)
-
conn.c (modified) (13 diffs)
-
email.c (added)
-
ft.c (modified) (42 diffs)
-
icq.c (modified) (2 diffs)
-
im.c (modified) (32 diffs)
-
info.c (modified) (12 diffs)
-
invite.c (modified) (2 diffs)
-
meta.c (modified) (2 diffs)
-
misc.c (modified) (4 diffs)
-
msgcookie.c (modified) (1 diff)
-
newsearch.c (added)
-
popups.c (modified) (2 diffs)
-
rxhandlers.c (modified) (4 diffs)
-
rxqueue.c (modified) (4 diffs)
-
search.c (modified) (4 diffs)
-
service.c (modified) (29 diffs)
-
snac.c (modified) (3 diffs)
-
ssi.c (modified) (13 diffs)
-
stats.c (modified) (1 diff)
-
tlv.c (modified) (8 diffs)
-
translate.c (modified) (2 diffs)
-
txqueue.c (modified) (11 diffs)
-
util.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libfaim/Makefile.in
r5e53c4a r862371b 3 3 LDFLAGS=@LDFLAGS@ 4 4 RANLIB=@RANLIB@ 5 OBJS=admin.o adverts.o auth.o bos.o buddylist.o \6 chat.o chatnav.o conn.o ft.o icq.o im.o \7 info.o invite.o md5.o meta.o misc.o msgcookie.o \5 OBJS=admin.o adverts.o auth.o bos.o buddylist.o bstream.o \ 6 chat.o chatnav.o conn.o email.o ft.o icq.o im.o \ 7 info.o invite.o md5.o meta.o misc.o msgcookie.o newsearch.o \ 8 8 popups.o rxhandlers.o rxqueue.o search.o service.o \ 9 9 snac.o ssi.o stats.o tlv.o translate.o txqueue.o \ -
libfaim/admin.c
r5e53c4a r862371b 1 /* 2 * Family 0x0007 - Account Administration. 3 * 4 * Used for stuff like changing the formating of your screen name, changing your 5 * email address, requesting an account confirmation email, getting account info, 6 * 7 */ 1 8 2 9 #define FAIM_INTERNAL 3 10 #include <aim.h> 4 11 5 /* called for both reply and change-reply */ 12 /* 13 * Subtype 0x0002 - Request a bit of account info. 14 * 15 * Info should be one of the following: 16 * 0x0001 - Screen name formatting 17 * 0x0011 - Email address 18 * 0x0013 - Unknown 19 * 20 */ 21 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info) 22 { 23 aim_frame_t *fr; 24 aim_snacid_t snacid; 25 26 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14))) 27 return -ENOMEM; 28 29 snacid = aim_cachesnac(sess, 0x0007, 0x0002, 0x0000, NULL, 0); 30 aim_putsnac(&fr->data, 0x0007, 0x0002, 0x0000, snacid); 31 32 aimbs_put16(&fr->data, info); 33 aimbs_put16(&fr->data, 0x0000); 34 35 aim_tx_enqueue(sess, fr); 36 37 return 0; 38 } 39 40 /* 41 * Subtypes 0x0003 and 0x0005 - Parse account info. 42 * 43 * Called in reply to both an information request (subtype 0x0002) and 44 * an information change (subtype 0x0004). 45 * 46 */ 6 47 static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 7 48 { 8 9 /* 10 * struct { 11 * unsigned short perms; 12 * unsigned short tlvcount; 13 * aim_tlv_t tlvs[tlvcount]; 14 * } admin_info[n]; 15 */ 16 while (aim_bstream_empty(bs)) { 17 fu16_t perms, tlvcount; 18 19 perms = aimbs_get16(bs); 20 tlvcount = aimbs_get16(bs); 21 22 while (tlvcount && aim_bstream_empty(bs)) { 23 aim_rxcallback_t userfunc; 24 fu16_t type, len; 25 fu8_t *val; 26 int str = 0; 27 28 type = aimbs_get16(bs); 29 len = aimbs_get16(bs); 30 31 if ((type == 0x0011) || (type == 0x0004)) 32 str = 1; 33 34 if (str) 35 val = aimbs_getstr(bs, len); 36 else 37 val = aimbs_getraw(bs, len); 38 39 /* XXX fix so its only called once for the entire packet */ 40 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 41 userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str); 42 43 free(val); 44 45 tlvcount--; 49 aim_rxcallback_t userfunc; 50 char *url=NULL, *sn=NULL, *email=NULL; 51 fu16_t perms, tlvcount, err=0; 52 53 perms = aimbs_get16(bs); 54 tlvcount = aimbs_get16(bs); 55 56 while (tlvcount && aim_bstream_empty(bs)) { 57 fu16_t type, length; 58 59 type = aimbs_get16(bs); 60 length = aimbs_get16(bs); 61 62 switch (type) { 63 case 0x0001: { 64 sn = aimbs_getstr(bs, length); 65 } break; 66 67 case 0x0004: { 68 url = aimbs_getstr(bs, length); 69 } break; 70 71 case 0x0008: { 72 err = aimbs_get16(bs); 73 } break; 74 75 case 0x0011: { 76 if (length == 0) { 77 email = (char*)malloc(13*sizeof(char)); 78 strcpy(email, "*suppressed*"); 79 } else 80 email = aimbs_getstr(bs, length); 81 } break; 46 82 } 83 84 tlvcount--; 47 85 } 48 86 87 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 88 userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, err, url, sn, email); 89 90 if (sn) free(sn); 91 if (url) free(url); 92 if (email) free(email); 93 49 94 return 1; 50 95 } 51 96 97 /* 98 * Subtype 0x0004 - Set screenname formatting. 99 * 100 */ 101 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick) 102 { 103 aim_frame_t *fr; 104 aim_snacid_t snacid; 105 aim_tlvlist_t *tl = NULL; 106 107 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newnick)))) 108 return -ENOMEM; 109 110 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); 111 aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); 112 113 aim_addtlvtochain_raw(&tl, 0x0001, strlen(newnick), newnick); 114 115 aim_writetlvchain(&fr->data, &tl); 116 aim_freetlvchain(&tl); 117 118 aim_tx_enqueue(sess, fr); 119 120 121 return 0; 122 } 123 124 /* 125 * Subtype 0x0004 - Change password. 126 * 127 */ 128 faim_export int aim_admin_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw) 129 { 130 aim_frame_t *fr; 131 aim_tlvlist_t *tl = NULL; 132 aim_snacid_t snacid; 133 134 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw)))) 135 return -ENOMEM; 136 137 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); 138 aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); 139 140 /* new password TLV t(0002) */ 141 aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw); 142 143 /* current password TLV t(0012) */ 144 aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw); 145 146 aim_writetlvchain(&fr->data, &tl); 147 aim_freetlvchain(&tl); 148 149 aim_tx_enqueue(sess, fr); 150 151 return 0; 152 } 153 154 /* 155 * Subtype 0x0004 - Change email address. 156 * 157 */ 158 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail) 159 { 160 aim_frame_t *fr; 161 aim_snacid_t snacid; 162 aim_tlvlist_t *tl = NULL; 163 164 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail)))) 165 return -ENOMEM; 166 167 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); 168 aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); 169 170 aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail); 171 172 aim_writetlvchain(&fr->data, &tl); 173 aim_freetlvchain(&tl); 174 175 aim_tx_enqueue(sess, fr); 176 177 return 0; 178 } 179 180 /* 181 * Subtype 0x0006 - Request account confirmation. 182 * 183 * This will cause an email to be sent to the address associated with 184 * the account. By following the instructions in the mail, you can 185 * get the TRIAL flag removed from your account. 186 * 187 */ 188 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn) 189 { 190 return aim_genericreq_n(sess, conn, 0x0007, 0x0006); 191 } 192 193 /* 194 * Subtype 0x0007 - Account confirmation request acknowledgement. 195 * 196 */ 52 197 static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 53 198 { 54 199 aim_rxcallback_t userfunc; 55 200 fu16_t status; 201 aim_tlvlist_t *tl; 56 202 57 203 status = aimbs_get16(bs); 204 /* This is 0x0013 if unable to confirm at this time */ 205 206 tl = aim_readtlvchain(bs); 58 207 59 208 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) … … 87 236 return 0; 88 237 } 89 90 faim_export int aim_admin_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw)91 {92 aim_frame_t *tx;93 aim_tlvlist_t *tl = NULL;94 aim_snacid_t snacid;95 96 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw))))97 return -ENOMEM;98 99 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);100 aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);101 102 /* new password TLV t(0002) */103 aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw);104 105 /* current password TLV t(0012) */106 aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw);107 108 aim_writetlvchain(&tx->data, &tl);109 aim_freetlvchain(&tl);110 111 aim_tx_enqueue(sess, tx);112 113 return 0;114 }115 116 /*117 * Request account confirmation.118 *119 * This will cause an email to be sent to the address associated with120 * the account. By following the instructions in the mail, you can121 * get the TRIAL flag removed from your account.122 *123 */124 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn)125 {126 return aim_genericreq_n(sess, conn, 0x0007, 0x0006);127 }128 129 /*130 * Request a bit of account info.131 *132 * The only known valid tag is 0x0011 (email address).133 *134 */135 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info)136 {137 aim_frame_t *tx;138 aim_snacid_t snacid;139 140 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14)))141 return -ENOMEM;142 143 snacid = aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0);144 aim_putsnac(&tx->data, 0x0007, 0x0002, 0x0000, snacid);145 146 aimbs_put16(&tx->data, info);147 aimbs_put16(&tx->data, 0x0000);148 149 aim_tx_enqueue(sess, tx);150 151 return 0;152 }153 154 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail)155 {156 aim_frame_t *tx;157 aim_snacid_t snacid;158 aim_tlvlist_t *tl = NULL;159 160 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail))))161 return -ENOMEM;162 163 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);164 aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);165 166 aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail);167 168 aim_writetlvchain(&tx->data, &tl);169 aim_freetlvchain(&tl);170 171 aim_tx_enqueue(sess, tx);172 173 return 0;174 }175 176 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick)177 {178 aim_frame_t *tx;179 aim_snacid_t snacid;180 aim_tlvlist_t *tl = NULL;181 182 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newnick))))183 return -ENOMEM;184 185 snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);186 aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);187 188 aim_addtlvtochain_raw(&tl, 0x0001, strlen(newnick), newnick);189 190 aim_writetlvchain(&tx->data, &tl);191 aim_freetlvchain(&tl);192 193 aim_tx_enqueue(sess, tx);194 195 return 0;196 }197 -
libfaim/adverts.c
r5e53c4a r862371b 1 1 /* 2 * 2 * Family 0x0005 - Advertisements. 3 3 * 4 4 */ … … 30 30 return 0; 31 31 } 32 33 -
libfaim/aim.h
r5e53c4a r862371b 12 12 #define FAIM_VERSION_MAJOR 0 13 13 #define FAIM_VERSION_MINOR 99 14 #define FAIM_VERSION_MINORMINOR 414 #define FAIM_VERSION_MINORMINOR 1 15 15 16 16 #include <faimconfig.h> … … 26 26 #include <time.h> 27 27 28 #ifdef _WIN32 29 #include <windows.h> 30 #include <io.h> 31 #else 28 #ifndef _WIN32 32 29 #include <sys/time.h> 33 30 #include <unistd.h> 34 31 #include <netinet/in.h> 35 32 #include <sys/socket.h> 33 #else 34 #include <winsock.h> 36 35 #endif 37 36 … … 42 41 typedef fu32_t aim_snacid_t; 43 42 typedef fu16_t flap_seqnum_t; 44 45 /* Portability stuff (DMP) */46 47 #ifdef _WIN3248 #define sleep(x) Sleep((x)*1000)49 #define snprintf _snprintf /* I'm not sure whats wrong with Microsoft here */50 #define close(x) closesocket(x) /* no comment */51 #endif52 43 53 44 #if defined(mach) && defined(__APPLE__) … … 147 138 }; 148 139 149 #define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \140 #define CLIENTINFO_AIM_3_5_1670 { \ 150 141 "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ 151 142 0x0004, \ … … 158 149 } 159 150 160 #define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \151 #define CLIENTINFO_AIM_4_1_2010 { \ 161 152 "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ 162 153 0x0004, \ … … 169 160 } 170 161 162 #define CLIENTINFO_AIM_5_0_2938 { \ 163 "AOL Instant Messenger, version 5.0.2938/WIN32", \ 164 0x0109, \ 165 0x0005, \ 166 0x0000, \ 167 0x0000, \ 168 0x0b7a, \ 169 "us", \ 170 "en", \ 171 } 172 173 #define CLIENTINFO_ICQ_4_65_3281 { \ 174 "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \ 175 0x010a, \ 176 0x0004, \ 177 0x0041, \ 178 0x0001, \ 179 0x0cd1, \ 180 "us", \ 181 "en", \ 182 } 183 184 #define CLIENTINFO_ICQ_5_34_3728 { \ 185 "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \ 186 0x010a, \ 187 0x0005, \ 188 0x0022, \ 189 0x0001, \ 190 0x0e8f, \ 191 "us", \ 192 "en", \ 193 } 194 171 195 /* 172 196 * I would make 4.1.2010 the default, but they seem to have found … … 174 198 * 175 199 * 3.5.1670 should work fine, however, you will be subjected to the 176 * memory test, which may require you to have a WinAIM binary l aying200 * memory test, which may require you to have a WinAIM binary lying 177 201 * around. (see login.c::memrequest()) 178 202 */ 179 #define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 203 #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_3_5_1670 204 #define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_4_65_3281 180 205 181 206 #ifndef TRUE … … 192 217 #define AIM_CONN_TYPE_CHAT 0x000e 193 218 #define AIM_CONN_TYPE_CHATNAV 0x000d 219 #define AIM_CONN_TYPE_SEARCH 0x000f 220 #define AIM_CONN_TYPE_EMAIL 0x0018 194 221 195 222 /* they start getting arbitrary in rendezvous stuff =) */ … … 250 277 typedef struct aim_bstream_s { 251 278 fu8_t *data; 252 fu 16_t len;253 fu 16_t offset;279 fu32_t len; 280 fu32_t offset; 254 281 } aim_bstream_t; 255 282 … … 262 289 } flap; 263 290 struct { 291 fu8_t magic[4]; /* ODC2 OFT2 */ 292 fu16_t hdrlen; 264 293 fu16_t type; 265 fu8_t magic[4]; /* ODC2 OFT2 */ 266 fu16_t hdr2len; 267 fu8_t *hdr2; /* rest of bloated header */ 268 } oft; 294 } rend; 269 295 } hdr; 270 296 aim_bstream_t data; /* payload stream */ … … 305 331 306 332 /* ---- Internal Use Only ------------------------ */ 333 334 /* Server-stored information (ssi) */ 335 struct { 336 int received_data; 337 fu16_t revision; 338 struct aim_ssi_item *items; 339 time_t timestamp; 340 int waiting_for_ack; 341 aim_frame_t *holding_queue; 342 } ssi; 343 344 struct aim_emailinfo *emailinfo; 307 345 308 346 /* Connection information */ … … 381 419 fu32_t membersince; /* time_t */ 382 420 fu32_t onlinesince; /* time_t */ 383 fu32_t sessionlen; /* in seconds */421 fu32_t sessionlen; /* in seconds */ 384 422 fu32_t capabilities; 385 423 struct { … … 459 497 /* TLV list handling. */ 460 498 faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs); 499 faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num); 461 500 faim_internal void aim_freetlvchain(aim_tlvlist_t **list); 462 501 faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n); … … 518 557 char *bosip; 519 558 fu8_t *cookie; 559 char *chpassurl; 520 560 struct aim_clientrelease latestrelease; 521 561 struct aim_clientrelease latestbeta; … … 574 614 faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd); 575 615 576 /* aim_misc.c */616 /* misc.c */ 577 617 578 618 #define AIM_VISIBILITYCHANGE_PERMITADD 0x05 … … 620 660 faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn); 621 661 622 /* aim_im.c */662 /* im.c */ 623 663 624 664 struct aim_fileheader_t { … … 657 697 }; 658 698 659 struct aim_filetransfer_priv { 660 char sn[MAXSNLEN]; 661 char cookie[8]; 662 char ip[30]; 663 int state; 664 struct aim_fileheader_t fh; 665 }; 699 #define AIM_OFT_SUBTYPE_SEND_FILE 0x0001 700 #define AIM_OFT_SUBTYPE_SEND_DIR 0x0002 701 #define AIM_OFT_SUBTYPE_GET_FILE 0x0011 702 #define AIM_OPT_SUBTYPE_GET_LIST 0x0012 666 703 667 704 struct aim_chat_roominfo { … … 683 720 #define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */ 684 721 #define AIM_IMFLAGS_OFFLINE 0x0800 /* send to offline user */ 722 #define AIM_IMFLAGS_TYPINGNOT 0x1000 /* typing notification */ 685 723 686 724 /* … … 822 860 const char *rtfmsg; 823 861 } rtfmsg; 862 struct { 863 fu16_t subtype; 864 fu16_t totfiles; 865 fu32_t totsize; 866 char *filename; 867 } sendfile; 824 868 } info; 825 869 void *destructor; /* used internally only */ 870 }; 871 872 /* Valid values for channel 4 args->type */ 873 #define AIM_ICQMSG_AUTHREQUEST 0x0006 874 #define AIM_ICQMSG_AUTHDENIED 0x0007 875 #define AIM_ICQMSG_AUTHGRANTED 0x0008 876 877 struct aim_incomingim_ch4_args { 878 fu32_t uin; /* Of the sender of the ICBM */ 879 fu16_t type; 880 char *msg; /* Reason for auth request, deny, or accept */ 826 881 }; 827 882 … … 831 886 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum); 832 887 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen); 833 faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg); 888 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing); 889 faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg, int len, int encoding); 834 890 faim_export const char *aim_directim_getsn(aim_conn_t *conn); 835 891 faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, const char *destsn); 836 892 faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie); 837 893 838 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize); 894 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type); 895 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret); 896 faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message); 897 898 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2); 839 899 840 900 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn); 841 901 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size); 902 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, 903 const char *name, int filesdone, int numfiles, int size, 904 int totsize); 842 905 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn); 843 faim_export int aim_oft_ getfile_end(aim_session_t *sess, aim_conn_t *conn);844 845 /* aim_info.c */906 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn); 907 908 /* info.c */ 846 909 #define AIM_CAPS_BUDDYICON 0x00000001 847 910 #define AIM_CAPS_VOICE 0x00000002 … … 904 967 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 905 968 faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, unsigned short code); 906 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid); 969 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t port, fu16_t rendid, ...); 970 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn, 971 const char *cookie, const char *sn, int rendid); 972 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn, 973 const unsigned char *buffer, int bufferlen); 907 974 908 975 faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short); … … 933 1000 934 1001 struct aim_icbmparameters { 935 unsigned short maxchan;936 unsigned longflags; /* AIM_IMPARAM_FLAG_ */937 unsigned short maxmsglen; /* message size that you will accept */938 unsigned short maxsenderwarn; /* this and below are *10 (999=99.9%) */939 unsigned short maxrecverwarn;940 unsigned longminmsginterval; /* in milliseconds? */1002 fu16_t maxchan; 1003 fu32_t flags; /* AIM_IMPARAM_FLAG_ */ 1004 fu16_t maxmsglen; /* message size that you will accept */ 1005 fu16_t maxsenderwarn; /* this and below are *10 (999=99.9%) */ 1006 fu16_t maxrecverwarn; 1007 fu32_t minmsginterval; /* in milliseconds? */ 941 1008 }; 942 1009 … … 954 1021 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick); 955 1022 956 /* aim_buddylist.c */1023 /* buddylist.c */ 957 1024 faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *); 958 1025 faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *); 959 1026 960 /* aim_search.c */1027 /* search.c */ 961 1028 faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *); 1029 1030 /* newsearch.c */ 1031 struct aim_usersearch { 1032 char *first; 1033 char *last; 1034 char *middle; 1035 char *maiden; 1036 char *email; 1037 char *country; 1038 char *state; 1039 char *city; 1040 char *sn; 1041 char *interest; 1042 char *nick; 1043 char *zip; 1044 char *region; 1045 char *address; 1046 struct aim_usersearch *next; 1047 }; 1048 1049 faim_export int aim_usersearch_email(aim_session_t *, const char *, const char *); 1050 faim_export int aim_usersearch_name(aim_session_t *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); 1051 faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *); 1052 962 1053 963 1054 /* These apply to exchanges as well. */ … … 995 1086 #define AIM_SSI_TYPE_BUDDY 0x0000 996 1087 #define AIM_SSI_TYPE_GROUP 0x0001 997 #define AIM_SSI_TYPE_PERMIT LIST0x0002998 #define AIM_SSI_TYPE_DENY LIST0x00031088 #define AIM_SSI_TYPE_PERMIT 0x0002 1089 #define AIM_SSI_TYPE_DENY 0x0003 999 1090 #define AIM_SSI_TYPE_PDINFO 0x0004 1000 1091 #define AIM_SSI_TYPE_PRESENCEPREFS 0x0005 … … 1009 1100 }; 1010 1101 1102 /* These build the actual SNACs and queue them to be sent */ 1011 1103 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn); 1012 1104 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev); 1013 1105 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn); 1106 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype); 1014 1107 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn); 1015 1108 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn); 1109 1110 /* These handle the local variables */ 1111 faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid); 1112 faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type); 1113 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn); 1114 faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list); 1115 faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list); 1116 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn); 1117 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num); 1118 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn); 1119 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num); 1120 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type); 1121 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn); 1122 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn); 1123 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num); 1124 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn); 1125 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num); 1126 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn); 1127 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type); 1128 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask); 1129 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence); 1016 1130 1017 1131 struct aim_icq_offlinemsg { … … 1035 1149 faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin); 1036 1150 1037 /* aim_util.c */ 1151 /* email.c */ 1152 struct aim_emailinfo { 1153 fu8_t *cookie16; 1154 fu8_t *cookie8; 1155 char *url; 1156 fu16_t nummsgs; 1157 fu8_t unread; 1158 char *domain; 1159 fu16_t flag; 1160 struct aim_emailinfo *next; 1161 }; 1162 1163 faim_export int aim_email_sendcookies(aim_session_t *sess, aim_conn_t *conn); 1164 faim_export int aim_email_activate(aim_session_t *sess, aim_conn_t *conn); 1165 1166 /* util.c */ 1038 1167 /* 1039 1168 * These are really ugly. You'd think this was LISP. I wish it was. … … 1100 1229 faim_export char *aim_strsep(char **pp, const char *delim); 1101 1230 1102 /* aim_meta.c */1231 /* meta.c */ 1103 1232 faim_export char *aim_getbuilddate(void); 1104 1233 faim_export char *aim_getbuildtime(void); -
libfaim/aim_cbtypes.h
r5e53c4a r862371b 24 24 #define AIM_CB_FAM_CTN 0x000d /* ChatNav */ 25 25 #define AIM_CB_FAM_CHT 0x000e /* Chat */ 26 #define AIM_CB_FAM_SCH 0x000f /* "New" search */ 27 #define AIM_CB_FAM_SSI 0x0013 /* Server stored information */ 26 28 #define AIM_CB_FAM_ICQ 0x0015 27 29 #define AIM_CB_FAM_ATH 0x0017 30 #define AIM_CB_FAM_EML 0x0018 28 31 #define AIM_CB_FAM_OFT 0xfffe /* OFT/Rvous */ 29 32 #define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */ … … 97 100 #define AIM_CB_MSG_EVIL 0x0009 98 101 #define AIM_CB_MSG_MISSEDCALL 0x000a 99 #define AIM_CB_MSG_CLIENT ERROR0x000b102 #define AIM_CB_MSG_CLIENTAUTORESP 0x000b 100 103 #define AIM_CB_MSG_ACK 0x000c 104 #define AIM_CB_MSG_MTN 0x0014 101 105 #define AIM_CB_MSG_DEFAULT 0xffff 102 106 … … 174 178 175 179 /* 180 * SNAC Family: "New" Search 181 * 182 * Most of these are actually special. 183 */ 184 #define AIM_CB_SCH_ERROR 0x0001 185 #define AIM_CB_SCH_SEARCH 0x0002 186 #define AIM_CB_SCH_RESULTS 0x0003 187 188 /* 176 189 * SNAC Family: ICQ 177 190 * … … 185 198 186 199 /* 200 * SNAC Family: Server-Stored Buddy Lists 201 */ 202 #define AIM_CB_SSI_ERROR 0x0001 203 #define AIM_CB_SSI_REQRIGHTS 0x0002 204 #define AIM_CB_SSI_RIGHTSINFO 0x0003 205 #define AIM_CB_SSI_REQLIST 0x0005 206 #define AIM_CB_SSI_LIST 0x0006 207 #define AIM_CB_SSI_ACTIVATE 0x0007 208 #define AIM_CB_SSI_ADD 0x0008 209 #define AIM_CB_SSI_MOD 0x0009 210 #define AIM_CB_SSI_DEL 0x000A 211 #define AIM_CB_SSI_SRVACK 0x000E 212 #define AIM_CB_SSI_NOLIST 0x000F 213 #define AIM_CB_SSI_EDITSTART 0x0011 214 #define AIM_CB_SSI_EDITSTOP 0x0012 215 216 /* 187 217 * SNAC Family: Authorizer 188 218 * … … 197 227 198 228 /* 229 * SNAC Family: Email 230 * 231 * Used for getting information on the email address 232 * associated with your screen name. 233 * 234 */ 235 #define AIM_CB_EML_ERROR 0x0001 236 #define AIM_CB_EML_SENDCOOKIES 0x0006 237 #define AIM_CB_EML_MAILSTATUS 0x0007 238 #define AIM_CB_EML_INIT 0x0016 239 240 /* 199 241 * OFT Services 200 242 * … … 207 249 #define AIM_CB_OFT_DIRECTIMINITIATE 0x0005 208 250 251 /* had been removed, put back by kretch */ 209 252 #define AIM_CB_OFT_GETFILECONNECTREQ 0x0006 /* connect request -- actually an OSCAR CAP*/ 210 253 #define AIM_CB_OFT_GETFILELISTINGREQ 0x0007 /* OFT listing.txt request */ … … 219 262 #define AIM_CB_OFT_GETFILESTATE4 0x0010 220 263 221 #define AIM_CB_OFT_SENDFILEDISCONNECT 0x0020 /* OFT connection disconnected.*/ 222 264 #define AIM_CB_OFT_SENDFILEFILEREQ 0x0011 /* started receiving file */ 265 #define AIM_CB_OFT_SENDFILEFILESEND 0x0012 /* buddy ready to for us to send */ 266 #define AIM_CB_OFT_SENDFILECOMPLETE 0x0013 /* send to buddy complete */ 267 #define AIM_CB_OFT_SENDFILEINITIATE 0x0014 /* connection to buddy initiated */ 223 268 224 269 … … 237 282 #define AIM_CB_SPECIAL_FLAPVER 0x0005 238 283 #define AIM_CB_SPECIAL_CONNINITDONE 0x0006 284 #define AIM_CB_SPECIAL_IMAGETRANSFER 0x007 285 #define AIM_CB_SPECIAL_MSGTIMEOUT 0x008 239 286 #define AIM_CB_SPECIAL_UNKNOWN 0xffff 240 287 #define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN 241 288 289 /* SNAC flags */ 290 #define AIM_SNACFLAGS_DESTRUCTOR 0x0001 242 291 243 292 #endif/*__AIM_CBTYPES_H__ */ -
libfaim/aim_internal.h
r5e53c4a r862371b 25 25 char name[AIM_MODULENAME_MAXLEN+1]; 26 26 int (*snachandler)(aim_session_t *sess, struct aim_module_s *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); 27 int (*snacdestructor)(aim_session_t *sess, aim_conn_t *conn, aim_modsnac_t *snac, void *data); 28 27 29 void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod); 28 30 void *priv; … … 53 55 faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod); 54 56 faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod); 57 faim_internal int email_modfirst(aim_session_t *sess, aim_module_t *mod); 58 faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod); 55 59 56 60 faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); … … 61 65 #define AIMBS_CURPOSPAIR(x) ((x)->data + (x)->offset), ((x)->len - (x)->offset) 62 66 63 faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn); 64 faim_internal int aim_recv(int fd, void *buf, size_t count); 65 faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count); 67 /* bstream.c */ 66 68 faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len); 67 69 faim_internal int aim_bstream_empty(aim_bstream_t *bs); … … 88 90 faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len); 89 91 90 faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn); 91 92 faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur); 93 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *); 94 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen); 95 faim_internal void aim_frame_destroy(aim_frame_t *); 96 faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *); 97 faim_internal int aim_tx_printqueue(aim_session_t *); 98 faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *); 99 92 /* conn.c */ 93 faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src); 94 95 /* ft.c */ 96 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr); 97 98 /* rxhandlers.c */ 100 99 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type); 101 100 faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_frame_t *ptr); 101 faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...); 102 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src); 103 104 /* rxqueue.c */ 105 faim_internal int aim_recv(int fd, void *buf, size_t count); 106 faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count); 107 faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn); 108 faim_internal void aim_frame_destroy(aim_frame_t *); 109 110 /* txqueue.c */ 111 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen); 112 faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *); 113 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *); 114 faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur); 115 faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *); 116 117 /* XXX - What is this? faim_internal int aim_tx_printqueue(aim_session_t *); */ 102 118 103 119 /* … … 114 130 } aim_snac_t; 115 131 132 struct aim_snac_destructor { 133 aim_conn_t *conn; 134 void *data; 135 }; 136 137 /* snac.c */ 116 138 faim_internal void aim_initsnachash(aim_session_t *sess); 117 139 faim_internal aim_snacid_t aim_newsnac(aim_session_t *, aim_snac_t *newsnac); … … 120 142 faim_internal void aim_cleansnacs(aim_session_t *, int maxage); 121 143 faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id); 122 123 faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src);124 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src);125 126 faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *);127 128 faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...);129 144 130 145 /* Stored in ->priv of the service request SNAC for chats. */ -
libfaim/auth.c
r5e53c4a r862371b 1 1 /* 2 * Deals with the authorizer (group 0x0017=23, and old-style non-SNAC login). 2 * Family 0x0017 - Authentication. 3 * 4 * Deals with the authorizer for SNAC-based login, and also old-style 5 * non-SNAC login. 3 6 * 4 7 */ … … 148 151 149 152 /* 150 * Part two of the ICQ hack. Note the ignoring of the key and clientinfo. 151 */ 152 static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password) 153 { 154 static const char clientstr[] = {"ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85"}; 155 static const char lang[] = {"en"}; 156 static const char country[] = {"us"}; 153 * Part two of the ICQ hack. Note the ignoring of the key. 154 */ 155 static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *ci) 156 { 157 157 aim_frame_t *fr; 158 158 aim_tlvlist_t *tl = NULL; … … 169 169 aim_encode_password(password, password_encoded); 170 170 171 aimbs_put32(&fr->data, 0x00000001); 171 aimbs_put32(&fr->data, 0x00000001); /* FLAP Version */ 172 172 aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); 173 173 aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded); 174 aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientstr), clientstr); 175 aim_addtlvtochain16(&tl, 0x0016, 0x010a); /* cliend ID */ 176 aim_addtlvtochain16(&tl, 0x0017, 0x0004); /* major version */ 177 aim_addtlvtochain16(&tl, 0x0018, 0x0041); /* minor version */ 178 aim_addtlvtochain16(&tl, 0x0019, 0x0001); /* point version */ 179 aim_addtlvtochain16(&tl, 0x001a, 0x0cd1); /* build */ 174 175 if (ci->clientstring) 176 aim_addtlvtochain_raw(&tl, 0x0003, strlen(ci->clientstring), ci->clientstring); 177 aim_addtlvtochain16(&tl, 0x0016, (fu16_t)ci->clientid); 178 aim_addtlvtochain16(&tl, 0x0017, (fu16_t)ci->major); 179 aim_addtlvtochain16(&tl, 0x0018, (fu16_t)ci->minor); 180 aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point); 181 aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build); 180 182 aim_addtlvtochain32(&tl, 0x0014, 0x00000055); /* distribution chan */ 181 aim_addtlvtochain_raw(&tl, 0x000f, strlen( lang),lang);182 aim_addtlvtochain_raw(&tl, 0x000e, strlen(c ountry),country);183 aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang); 184 aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country); 183 185 184 186 aim_writetlvchain(&fr->data, &tl); … … 277 279 */ 278 280 if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) 279 return goddamnicq2(sess, conn, sn, password );281 return goddamnicq2(sess, conn, sn, password, ci); 280 282 281 283 … … 290 292 aim_encode_password_md5(password, key, digest); 291 293 aim_addtlvtochain_raw(&tl, 0x0025, 16, digest); 294 295 /* 296 * Newer versions of winaim have an empty type x004c TLV here. 297 */ 292 298 293 299 if (ci->clientstring) … … 305 311 * to use SSI. 306 312 */ 307 if (0) 308 aim_addtlvtochain8(&tl, 0x004a, 0x01); 313 aim_addtlvtochain8(&tl, 0x004a, 0x01); 309 314 310 315 aim_writetlvchain(&fr->data, &tl); … … 473 478 ; /* no idea what this is */ 474 479 480 /* 481 * URL to change password. 482 */ 483 if (aim_gettlv(tlvlist, 0x0054, 1)) 484 info.chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1); 475 485 476 486 if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) … … 481 491 free(info.errorurl); 482 492 free(info.email); 493 free(info.chpassurl); 483 494 free(info.latestrelease.name); 484 495 free(info.latestrelease.url); … … 539 550 return 0; 540 551 } 541 -
libfaim/bos.c
r5e53c4a r862371b 1 /* 2 * Family 0x0009 - Basic Oscar Service. 3 * 4 */ 1 5 2 6 #define FAIM_INTERNAL 3 7 #include <aim.h> 4 8 5 /* Request BOS rights (group 9, type 2)*/9 /* Subtype 0x0002 - Request BOS rights. */ 6 10 faim_export int aim_bos_reqrights(aim_session_t *sess, aim_conn_t *conn) 7 11 { … … 9 13 } 10 14 11 /* BOS Rights (group 9, type 3)*/15 /* Subtype 0x0003 - BOS Rights. */ 12 16 static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 13 17 { … … 43 47 44 48 /* 45 * S et group permisson mask (group 9, type 4)49 * Subtype 0x0004 - Set group permisson mask. 46 50 * 47 51 * Normally 0x1f (all classes). … … 58 62 59 63 /* 60 * Modify permit/deny lists (group 9, types 5, 6, 7, and 8)64 * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists. 61 65 * 62 66 * Changes your visibility depending on changetype: … … 159 163 return 0; 160 164 } 161 162 -
libfaim/buddylist.c
r5e53c4a r862371b 1 /* 2 * Family 0x0003 - Old-style Buddylist Management (non-SSI). 3 * 4 */ 1 5 2 6 #define FAIM_INTERNAL … … 4 8 5 9 /* 6 * Oncoming Buddy notifications contain a subset of the 7 * user information structure. Its close enough to run 8 * through aim_extractuserinfo() however. 9 * 10 * Although the offgoing notification contains no information, 11 * it is still in a format parsable by extractuserinfo. 12 * 13 */ 14 static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 15 { 16 aim_userinfo_t userinfo; 17 aim_rxcallback_t userfunc; 18 19 aim_extractuserinfo(sess, bs, &userinfo); 20 21 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 22 return userfunc(sess, rx, &userinfo); 23 24 return 0; 25 } 26 10 * Subtype 0x0002 - Request rights. 11 * 12 * Request Buddy List rights. 13 * 14 */ 15 faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn) 16 { 17 return aim_genericreq_n(sess, conn, 0x0003, 0x0002); 18 } 19 20 /* 21 * Subtype 0x0003 - Rights. 22 * 23 */ 27 24 static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 28 25 { … … 54 51 maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); 55 52 53 /* 54 * TLV type 0x0003: Unknown. 55 * 56 * ICQ only? 57 */ 58 56 59 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 57 60 ret = userfunc(sess, rx, maxbuddies, maxwatchers); … … 60 63 61 64 return ret; 65 } 66 67 /* 68 * Subtype 0x0004 - Add buddy to list. 69 * 70 * Adds a single buddy to your buddy list after login. 71 * XXX This should just be an extension of setbuddylist() 72 * 73 */ 74 faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) 75 { 76 aim_frame_t *fr; 77 aim_snacid_t snacid; 78 79 if (!sn || !strlen(sn)) 80 return -EINVAL; 81 82 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) 83 return -ENOMEM; 84 85 snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); 86 aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); 87 88 aimbs_put8(&fr->data, strlen(sn)); 89 aimbs_putraw(&fr->data, sn, strlen(sn)); 90 91 aim_tx_enqueue(sess, fr); 92 93 return 0; 94 } 95 96 /* 97 * Subtype 0x0004 - Add multiple buddies to your buddy list. 98 * 99 * This just builds the "set buddy list" command then queues it. 100 * 101 * buddy_list = "Screen Name One&ScreenNameTwo&"; 102 * 103 * XXX Clean this up. 104 * 105 */ 106 faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list) 107 { 108 aim_frame_t *fr; 109 aim_snacid_t snacid; 110 int len = 0; 111 char *localcpy = NULL; 112 char *tmpptr = NULL; 113 114 if (!buddy_list || !(localcpy = strdup(buddy_list))) 115 return -EINVAL; 116 117 for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { 118 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr)); 119 len += 1 + strlen(tmpptr); 120 tmpptr = strtok(NULL, "&"); 121 } 122 123 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len))) 124 return -ENOMEM; 125 126 snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0); 127 aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); 128 129 strncpy(localcpy, buddy_list, strlen(buddy_list) + 1); 130 131 for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { 132 133 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr)); 134 135 aimbs_put8(&fr->data, strlen(tmpptr)); 136 aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr)); 137 tmpptr = strtok(NULL, "&"); 138 } 139 140 aim_tx_enqueue(sess, fr); 141 142 free(localcpy); 143 144 return 0; 145 } 146 147 /* 148 * Subtype 0x0005 - Remove buddy from list. 149 * 150 * XXX generalise to support removing multiple buddies (basically, its 151 * the same as setbuddylist() but with a different snac subtype). 152 * 153 */ 154 faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) 155 { 156 aim_frame_t *fr; 157 aim_snacid_t snacid; 158 159 if (!sn || !strlen(sn)) 160 return -EINVAL; 161 162 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) 163 return -ENOMEM; 164 165 snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); 166 aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid); 167 168 aimbs_put8(&fr->data, strlen(sn)); 169 aimbs_putraw(&fr->data, sn, strlen(sn)); 170 171 aim_tx_enqueue(sess, fr); 172 173 return 0; 174 } 175 176 /* 177 * Subtype 0x000b 178 * 179 * XXX Why would we send this? 180 * 181 */ 182 faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info) 183 { 184 aim_frame_t *fr; 185 aim_snacid_t snacid; 186 187 if (!sess || !conn || !info) 188 return -EINVAL; 189 190 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) 191 return -ENOMEM; 192 193 snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0); 194 195 aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid); 196 aim_putuserinfo(&fr->data, info); 197 198 aim_tx_enqueue(sess, fr); 199 200 return 0; 201 } 202 203 /* 204 * Subtype 0x000c 205 * 206 * XXX Why would we send this? 207 * 208 */ 209 faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn) 210 { 211 aim_frame_t *fr; 212 aim_snacid_t snacid; 213 214 if (!sess || !conn || !sn) 215 return -EINVAL; 216 217 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) 218 return -ENOMEM; 219 220 snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0); 221 222 aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid); 223 aimbs_put8(&fr->data, strlen(sn)); 224 aimbs_putraw(&fr->data, sn, strlen(sn)); 225 226 aim_tx_enqueue(sess, fr); 227 228 return 0; 229 } 230 231 /* 232 * Subtypes 0x000b and 0x000c - Change in buddy status 233 * 234 * Oncoming Buddy notifications contain a subset of the 235 * user information structure. Its close enough to run 236 * through aim_extractuserinfo() however. 237 * 238 * Although the offgoing notification contains no information, 239 * it is still in a format parsable by extractuserinfo. 240 * 241 */ 242 static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 243 { 244 aim_userinfo_t userinfo; 245 aim_rxcallback_t userfunc; 246 247 aim_extractuserinfo(sess, bs, &userinfo); 248 249 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 250 return userfunc(sess, rx, &userinfo); 251 252 return 0; 62 253 } 63 254 … … 86 277 return 0; 87 278 } 88 89 /*90 * aim_add_buddy()91 *92 * Adds a single buddy to your buddy list after login.93 *94 * XXX this should just be an extension of setbuddylist()95 *96 */97 faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)98 {99 aim_frame_t *fr;100 aim_snacid_t snacid;101 102 if (!sn || !strlen(sn))103 return -EINVAL;104 105 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))106 return -ENOMEM;107 108 snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);109 aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);110 111 aimbs_put8(&fr->data, strlen(sn));112 aimbs_putraw(&fr->data, sn, strlen(sn));113 114 aim_tx_enqueue(sess, fr);115 116 return 0;117 }118 119 /*120 * XXX generalise to support removing multiple buddies (basically, its121 * the same as setbuddylist() but with a different snac subtype).122 *123 */124 faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn)125 {126 aim_frame_t *fr;127 aim_snacid_t snacid;128 129 if (!sn || !strlen(sn))130 return -EINVAL;131 132 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))133 return -ENOMEM;134 135 snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);136 aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid);137 138 aimbs_put8(&fr->data, strlen(sn));139 aimbs_putraw(&fr->data, sn, strlen(sn));140 141 aim_tx_enqueue(sess, fr);142 143 return 0;144 }145 -
libfaim/chat.c
r5e53c4a r862371b 1 1 /* 2 * aim_chat.c 3 * 4 * Routines for the Chat service. 2 * Family 0x000e - Routines for the Chat service. 5 3 * 6 4 */ … … 16 14 }; 17 15 18 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)19 {20 int i;21 22 if (!sess || !buf || !len)23 return;24 25 faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf);26 27 for (i = 0; i < len; i++) {28 if ((i % 8) == 0)29 faimdprintf(sess, 1, "\n\t");30 31 faimdprintf(sess, 1, "0x%2x ", buf[i]);32 }33 34 faimdprintf(sess, 1, "\n\n");35 36 return;37 }38 39 16 faim_internal void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn) 40 17 { … … 107 84 } 108 85 86 static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) 87 { 88 fu8_t *buf; 89 int buflen; 90 aim_bstream_t bs; 91 92 buflen = 2 + 1 + strlen(roomname) + 2; 93 94 if (!(buf = malloc(buflen))) 95 return 0; 96 97 aim_bstream_init(&bs, buf, buflen); 98 99 aimbs_put16(&bs, exchange); 100 aimbs_put8(&bs, strlen(roomname)); 101 aimbs_putraw(&bs, roomname, strlen(roomname)); 102 aimbs_put16(&bs, instance); 103 104 aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); 105 106 free(buf); 107 108 return 0; 109 } 110 109 111 /* 110 * Send a Chat Message. 112 * Join a room of name roomname. This is the first step to joining an 113 * already created room. It's basically a Service Request for 114 * family 0x000e, with a little added on to specify the exchange and room 115 * name. 116 */ 117 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) 118 { 119 aim_frame_t *fr; 120 aim_snacid_t snacid; 121 aim_tlvlist_t *tl = NULL; 122 struct chatsnacinfo csi; 123 124 if (!sess || !conn || !roomname || !strlen(roomname)) 125 return -EINVAL; 126 127 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) 128 return -ENOMEM; 129 130 memset(&csi, 0, sizeof(csi)); 131 csi.exchange = exchange; 132 strncpy(csi.name, roomname, sizeof(csi.name)); 133 csi.instance = instance; 134 135 snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); 136 aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); 137 138 /* 139 * Requesting service chat (0x000e) 140 */ 141 aimbs_put16(&fr->data, 0x000e); 142 143 aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance); 144 aim_writetlvchain(&fr->data, &tl); 145 aim_freetlvchain(&tl); 146 147 aim_tx_enqueue(sess, fr); 148 149 return 0; 150 } 151 152 faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) 153 { 154 int namelen; 155 156 if (!bs || !outinfo) 157 return 0; 158 159 outinfo->exchange = aimbs_get16(bs); 160 namelen = aimbs_get8(bs); 161 outinfo->name = aimbs_getstr(bs, namelen); 162 outinfo->instance = aimbs_get16(bs); 163 164 return 0; 165 } 166 167 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name) 168 { 169 aim_conn_t *conn; 170 171 if (!(conn = aim_chat_getconn(sess, name))) 172 return -ENOENT; 173 174 aim_conn_close(conn); 175 176 return 0; 177 } 178 179 /* 180 * conn must be a BOS connection! 181 */ 182 faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) 183 { 184 int i; 185 aim_frame_t *fr; 186 aim_msgcookie_t *cookie; 187 struct aim_invite_priv *priv; 188 fu8_t ckstr[8]; 189 aim_snacid_t snacid; 190 aim_tlvlist_t *otl = NULL, *itl = NULL; 191 fu8_t *hdr; 192 int hdrlen; 193 aim_bstream_t hdrbs; 194 195 if (!sess || !conn || !sn || !msg || !roomname) 196 return -EINVAL; 197 198 if (conn->type != AIM_CONN_TYPE_BOS) 199 return -EINVAL; 200 201 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) 202 return -ENOMEM; 203 204 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); 205 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 206 207 208 /* 209 * Cookie 210 */ 211 for (i = 0; i < sizeof(ckstr); i++) 212 aimutil_put8(ckstr, (fu8_t) rand()); 213 214 /* XXX should be uncached by an unwritten 'invite accept' handler */ 215 if ((priv = malloc(sizeof(struct aim_invite_priv)))) { 216 priv->sn = strdup(sn); 217 priv->roomname = strdup(roomname); 218 priv->exchange = exchange; 219 priv->instance = instance; 220 } 221 222 if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) 223 aim_cachecookie(sess, cookie); 224 else 225 free(priv); 226 227 for (i = 0; i < sizeof(ckstr); i++) 228 aimbs_put8(&fr->data, ckstr[i]); 229 230 231 /* 232 * Channel (2) 233 */ 234 aimbs_put16(&fr->data, 0x0002); 235 236 /* 237 * Dest sn 238 */ 239 aimbs_put8(&fr->data, strlen(sn)); 240 aimbs_putraw(&fr->data, sn, strlen(sn)); 241 242 /* 243 * TLV t(0005) 244 * 245 * Everything else is inside this TLV. 246 * 247 * Sigh. AOL was rather inconsistent right here. So we have 248 * to play some minor tricks. Right inside the type 5 is some 249 * raw data, followed by a series of TLVs. 250 * 251 */ 252 hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; 253 hdr = malloc(hdrlen); 254 aim_bstream_init(&hdrbs, hdr, hdrlen); 255 256 aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ 257 aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ 258 aim_putcap(&hdrbs, AIM_CAPS_CHAT); 259 260 aim_addtlvtochain16(&itl, 0x000a, 0x0001); 261 aim_addtlvtochain_noval(&itl, 0x000f); 262 aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); 263 aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); 264 aim_writetlvchain(&hdrbs, &itl); 265 266 aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); 267 268 aim_writetlvchain(&fr->data, &otl); 269 270 free(hdr); 271 aim_freetlvchain(&itl); 272 aim_freetlvchain(&otl); 273 274 aim_tx_enqueue(sess, fr); 275 276 return 0; 277 } 278 279 /* 280 * Subtype 0x0002 - General room information. Lots of stuff. 281 * 282 * Values I know are in here but I havent attached 283 * them to any of the 'Unknown's: 284 * - Language (English) 285 * 286 */ 287 static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 288 { 289 aim_userinfo_t *userinfo = NULL; 290 aim_rxcallback_t userfunc; 291 int ret = 0; 292 int usercount = 0; 293 fu8_t detaillevel = 0; 294 char *roomname = NULL; 295 struct aim_chat_roominfo roominfo; 296 fu16_t tlvcount = 0; 297 aim_tlvlist_t *tlvlist; 298 char *roomdesc = NULL; 299 fu16_t flags = 0; 300 fu32_t creationtime = 0; 301 fu16_t maxmsglen = 0, maxvisiblemsglen = 0; 302 fu16_t unknown_d2 = 0, unknown_d5 = 0; 303 304 aim_chat_readroominfo(bs, &roominfo); 305 306 detaillevel = aimbs_get8(bs); 307 308 if (detaillevel != 0x02) { 309 faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel); 310 return 1; 311 } 312 313 tlvcount = aimbs_get16(bs); 314 315 /* 316 * Everything else are TLVs. 317 */ 318 tlvlist = aim_readtlvchain(bs); 319 320 /* 321 * TLV type 0x006a is the room name in Human Readable Form. 322 */ 323 if (aim_gettlv(tlvlist, 0x006a, 1)) 324 roomname = aim_gettlv_str(tlvlist, 0x006a, 1); 325 326 /* 327 * Type 0x006f: Number of occupants. 328 */ 329 if (aim_gettlv(tlvlist, 0x006f, 1)) 330 usercount = aim_gettlv16(tlvlist, 0x006f, 1); 331 332 /* 333 * Type 0x0073: Occupant list. 334 */ 335 if (aim_gettlv(tlvlist, 0x0073, 1)) { 336 int curoccupant = 0; 337 aim_tlv_t *tmptlv; 338 aim_bstream_t occbs; 339 340 tmptlv = aim_gettlv(tlvlist, 0x0073, 1); 341 342 /* Allocate enough userinfo structs for all occupants */ 343 userinfo = calloc(usercount, sizeof(aim_userinfo_t)); 344 345 aim_bstream_init(&occbs, tmptlv->value, tmptlv->length); 346 347 while (curoccupant < usercount) 348 aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]); 349 } 350 351 /* 352 * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG) 353 */ 354 if (aim_gettlv(tlvlist, 0x00c9, 1)) 355 flags = aim_gettlv16(tlvlist, 0x00c9, 1); 356 357 /* 358 * Type 0x00ca: Creation time (4 bytes) 359 */ 360 if (aim_gettlv(tlvlist, 0x00ca, 1)) 361 creationtime = aim_gettlv32(tlvlist, 0x00ca, 1); 362 363 /* 364 * Type 0x00d1: Maximum Message Length 365 */ 366 if (aim_gettlv(tlvlist, 0x00d1, 1)) 367 maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1); 368 369 /* 370 * Type 0x00d2: Unknown. (2 bytes) 371 */ 372 if (aim_gettlv(tlvlist, 0x00d2, 1)) 373 unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1); 374 375 /* 376 * Type 0x00d3: Room Description 377 */ 378 if (aim_gettlv(tlvlist, 0x00d3, 1)) 379 roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); 380 381 /* 382 * Type 0x000d4: Unknown (flag only) 383 */ 384 if (aim_gettlv(tlvlist, 0x000d4, 1)) 385 ; 386 387 /* 388 * Type 0x00d5: Unknown. (1 byte) 389 */ 390 if (aim_gettlv(tlvlist, 0x00d5, 1)) 391 unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1); 392 393 394 /* 395 * Type 0x00d6: Encoding 1 ("us-ascii") 396 */ 397 if (aim_gettlv(tlvlist, 0x000d6, 1)) 398 ; 399 400 /* 401 * Type 0x00d7: Language 1 ("en") 402 */ 403 if (aim_gettlv(tlvlist, 0x000d7, 1)) 404 ; 405 406 /* 407 * Type 0x00d8: Encoding 2 ("us-ascii") 408 */ 409 if (aim_gettlv(tlvlist, 0x000d8, 1)) 410 ; 411 412 /* 413 * Type 0x00d9: Language 2 ("en") 414 */ 415 if (aim_gettlv(tlvlist, 0x000d9, 1)) 416 ; 417 418 /* 419 * Type 0x00da: Maximum visible message length 420 */ 421 if (aim_gettlv(tlvlist, 0x000da, 1)) 422 maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1); 423 424 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { 425 ret = userfunc(sess, 426 rx, 427 &roominfo, 428 roomname, 429 usercount, 430 userinfo, 431 roomdesc, 432 flags, 433 creationtime, 434 maxmsglen, 435 unknown_d2, 436 unknown_d5, 437 maxvisiblemsglen); 438 } 439 440 free(roominfo.name); 441 free(userinfo); 442 free(roomname); 443 free(roomdesc); 444 aim_freetlvchain(&tlvlist); 445 446 return ret; 447 } 448 449 /* Subtypes 0x0003 and 0x0004 */ 450 static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 451 { 452 aim_userinfo_t *userinfo = NULL; 453 aim_rxcallback_t userfunc; 454 int curcount = 0, ret = 0; 455 456 while (aim_bstream_empty(bs)) { 457 curcount++; 458 userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t)); 459 aim_extractuserinfo(sess, bs, &userinfo[curcount-1]); 460 } 461 462 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 463 ret = userfunc(sess, rx, curcount, userinfo); 464 465 free(userinfo); 466 467 return ret; 468 } 469 470 /* 471 * Subtype 0x0005 - Send a Chat Message. 111 472 * 112 473 * Possible flags: … … 204 565 } 205 566 206 static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance)207 {208 fu8_t *buf;209 int buflen;210 aim_bstream_t bs;211 212 buflen = 2 + 1 + strlen(roomname) + 2;213 214 if (!(buf = malloc(buflen)))215 return 0;216 217 aim_bstream_init(&bs, buf, buflen);218 219 aimbs_put16(&bs, exchange);220 aimbs_put8(&bs, strlen(roomname));221 aimbs_putraw(&bs, roomname, strlen(roomname));222 aimbs_put16(&bs, instance);223 224 aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);225 226 free(buf);227 228 return 0;229 }230 231 567 /* 232 * Join a room of name roomname. This is the first step to joining an 233 * already created room. It's basically a Service Request for 234 * family 0x000e, with a little added on to specify the exchange and room 235 * name. 236 */ 237 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) 238 { 239 aim_frame_t *fr; 240 aim_snacid_t snacid; 241 aim_tlvlist_t *tl = NULL; 242 struct chatsnacinfo csi; 243 244 if (!sess || !conn || !roomname || !strlen(roomname)) 245 return -EINVAL; 246 247 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) 248 return -ENOMEM; 249 250 memset(&csi, 0, sizeof(csi)); 251 csi.exchange = exchange; 252 strncpy(csi.name, roomname, sizeof(csi.name)); 253 csi.instance = instance; 254 255 snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); 256 aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); 257 258 /* 259 * Requesting service chat (0x000e) 260 */ 261 aimbs_put16(&fr->data, 0x000e); 262 263 aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance); 264 aim_writetlvchain(&fr->data, &tl); 265 aim_freetlvchain(&tl); 266 267 aim_tx_enqueue(sess, fr); 268 269 return 0; 270 } 271 272 faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) 273 { 274 int namelen; 275 276 if (!bs || !outinfo) 277 return 0; 278 279 outinfo->exchange = aimbs_get16(bs); 280 namelen = aimbs_get8(bs); 281 outinfo->name = aimbs_getstr(bs, namelen); 282 outinfo->instance = aimbs_get16(bs); 283 284 return 0; 285 } 286 287 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name) 288 { 289 aim_conn_t *conn; 290 291 if (!(conn = aim_chat_getconn(sess, name))) 292 return -ENOENT; 293 294 aim_conn_close(conn); 295 296 return 0; 297 } 298 299 /* 300 * conn must be a BOS connection! 301 */ 302 faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) 303 { 304 int i; 305 aim_frame_t *fr; 306 aim_msgcookie_t *cookie; 307 struct aim_invite_priv *priv; 308 fu8_t ckstr[8]; 309 aim_snacid_t snacid; 310 aim_tlvlist_t *otl = NULL, *itl = NULL; 311 fu8_t *hdr; 312 int hdrlen; 313 aim_bstream_t hdrbs; 314 315 if (!sess || !conn || !sn || !msg || !roomname) 316 return -EINVAL; 317 318 if (conn->type != AIM_CONN_TYPE_BOS) 319 return -EINVAL; 320 321 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) 322 return -ENOMEM; 323 324 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); 325 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 326 327 328 /* 329 * Cookie 330 */ 331 for (i = 0; i < sizeof(ckstr); i++) 332 aimutil_put8(ckstr, (fu8_t) rand()); 333 334 /* XXX should be uncached by an unwritten 'invite accept' handler */ 335 if ((priv = malloc(sizeof(struct aim_invite_priv)))) { 336 priv->sn = strdup(sn); 337 priv->roomname = strdup(roomname); 338 priv->exchange = exchange; 339 priv->instance = instance; 340 } 341 342 if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) 343 aim_cachecookie(sess, cookie); 344 else 345 free(priv); 346 347 for (i = 0; i < sizeof(ckstr); i++) 348 aimbs_put8(&fr->data, ckstr[i]); 349 350 351 /* 352 * Channel (2) 353 */ 354 aimbs_put16(&fr->data, 0x0002); 355 356 /* 357 * Dest sn 358 */ 359 aimbs_put8(&fr->data, strlen(sn)); 360 aimbs_putraw(&fr->data, sn, strlen(sn)); 361 362 /* 363 * TLV t(0005) 364 * 365 * Everything else is inside this TLV. 366 * 367 * Sigh. AOL was rather inconsistent right here. So we have 368 * to play some minor tricks. Right inside the type 5 is some 369 * raw data, followed by a series of TLVs. 370 * 371 */ 372 hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; 373 hdr = malloc(hdrlen); 374 aim_bstream_init(&hdrbs, hdr, hdrlen); 375 376 aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ 377 aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ 378 aim_putcap(&hdrbs, AIM_CAPS_CHAT); 379 380 aim_addtlvtochain16(&itl, 0x000a, 0x0001); 381 aim_addtlvtochain_noval(&itl, 0x000f); 382 aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); 383 aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); 384 aim_writetlvchain(&hdrbs, &itl); 385 386 aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); 387 388 aim_writetlvchain(&fr->data, &otl); 389 390 free(hdr); 391 aim_freetlvchain(&itl); 392 aim_freetlvchain(&otl); 393 394 aim_tx_enqueue(sess, fr); 395 396 return 0; 397 } 398 399 /* 400 * General room information. Lots of stuff. 568 * Subtype 0x0006 401 569 * 402 * Values I know are in here but I havent attached403 * them to any of the 'Unknown's:404 * - Language (English)405 *406 * SNAC 000e/0002407 */408 static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)409 {410 aim_userinfo_t *userinfo = NULL;411 aim_rxcallback_t userfunc;412 int ret = 0;413 int usercount = 0;414 fu8_t detaillevel = 0;415 char *roomname = NULL;416 struct aim_chat_roominfo roominfo;417 fu16_t tlvcount = 0;418 aim_tlvlist_t *tlvlist;419 char *roomdesc = NULL;420 fu16_t flags = 0;421 fu32_t creationtime = 0;422 fu16_t maxmsglen = 0, maxvisiblemsglen = 0;423 fu16_t unknown_d2 = 0, unknown_d5 = 0;424 425 dumpbox(sess, bs->data + bs->offset, aim_bstream_empty(bs));426 427 aim_chat_readroominfo(bs, &roominfo);428 429 detaillevel = aimbs_get8(bs);430 431 if (detaillevel != 0x02) {432 faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);433 return 1;434 }435 436 tlvcount = aimbs_get16(bs);437 438 /*439 * Everything else are TLVs.440 */441 tlvlist = aim_readtlvchain(bs);442 443 /*444 * TLV type 0x006a is the room name in Human Readable Form.445 */446 if (aim_gettlv(tlvlist, 0x006a, 1))447 roomname = aim_gettlv_str(tlvlist, 0x006a, 1);448 449 /*450 * Type 0x006f: Number of occupants.451 */452 if (aim_gettlv(tlvlist, 0x006f, 1))453 usercount = aim_gettlv16(tlvlist, 0x006f, 1);454 455 /*456 * Type 0x0073: Occupant list.457 */458 if (aim_gettlv(tlvlist, 0x0073, 1)) {459 int curoccupant = 0;460 aim_tlv_t *tmptlv;461 aim_bstream_t occbs;462 463 tmptlv = aim_gettlv(tlvlist, 0x0073, 1);464 465 /* Allocate enough userinfo structs for all occupants */466 userinfo = calloc(usercount, sizeof(aim_userinfo_t));467 468 aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);469 470 while (curoccupant < usercount)471 aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);472 }473 474 /*475 * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)476 */477 if (aim_gettlv(tlvlist, 0x00c9, 1))478 flags = aim_gettlv16(tlvlist, 0x00c9, 1);479 480 /*481 * Type 0x00ca: Creation time (4 bytes)482 */483 if (aim_gettlv(tlvlist, 0x00ca, 1))484 creationtime = aim_gettlv32(tlvlist, 0x00ca, 1);485 486 /*487 * Type 0x00d1: Maximum Message Length488 */489 if (aim_gettlv(tlvlist, 0x00d1, 1))490 maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1);491 492 /*493 * Type 0x00d2: Unknown. (2 bytes)494 */495 if (aim_gettlv(tlvlist, 0x00d2, 1))496 unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1);497 498 /*499 * Type 0x00d3: Room Description500 */501 if (aim_gettlv(tlvlist, 0x00d3, 1))502 roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1);503 504 /*505 * Type 0x000d4: Unknown (flag only)506 */507 if (aim_gettlv(tlvlist, 0x000d4, 1))508 ;509 510 /*511 * Type 0x00d5: Unknown. (1 byte)512 */513 if (aim_gettlv(tlvlist, 0x00d5, 1))514 unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1);515 516 517 /*518 * Type 0x00d6: Encoding 1 ("us-ascii")519 */520 if (aim_gettlv(tlvlist, 0x000d6, 1))521 ;522 523 /*524 * Type 0x00d7: Language 1 ("en")525 */526 if (aim_gettlv(tlvlist, 0x000d7, 1))527 ;528 529 /*530 * Type 0x00d8: Encoding 2 ("us-ascii")531 */532 if (aim_gettlv(tlvlist, 0x000d8, 1))533 ;534 535 /*536 * Type 0x00d9: Language 2 ("en")537 */538 if (aim_gettlv(tlvlist, 0x000d9, 1))539 ;540 541 /*542 * Type 0x00da: Maximum visible message length543 */544 if (aim_gettlv(tlvlist, 0x000da, 1))545 maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1);546 547 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {548 ret = userfunc(sess,549 rx,550 &roominfo,551 roomname,552 usercount,553 userinfo,554 roomdesc,555 flags,556 creationtime,557 maxmsglen,558 unknown_d2,559 unknown_d5,560 maxvisiblemsglen);561 }562 563 free(roominfo.name);564 free(userinfo);565 free(roomname);566 free(roomdesc);567 aim_freetlvchain(&tlvlist);568 569 return ret;570 }571 572 static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)573 {574 aim_userinfo_t *userinfo = NULL;575 aim_rxcallback_t userfunc;576 int curcount = 0, ret = 0;577 578 while (aim_bstream_empty(bs)) {579 curcount++;580 userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t));581 aim_extractuserinfo(sess, bs, &userinfo[curcount-1]);582 }583 584 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))585 ret = userfunc(sess, rx, curcount, userinfo);586 587 free(userinfo);588 589 return ret;590 }591 592 /*593 570 * We could probably include this in the normal ICBM parsing 594 571 * code as channel 0x0003, however, since only the start … … 734 711 return 0; 735 712 } 736 737 -
libfaim/chatnav.c
r5e53c4a r862371b 1 1 /* 2 * Handle ChatNav.3 * 4 * [The ChatNav(igation) service does various things to keep chat5 * alive. It provides room information, room searching and creating,6 * as well as giving users the right ("permission") to use chat.]2 * Family 0x000d - Handle ChatNav. 3 * 4 * The ChatNav(igation) service does various things to keep chat 5 * alive. It provides room information, room searching and creating, 6 * as well as giving users the right ("permission") to use chat. 7 7 * 8 8 */ … … 12 12 13 13 /* 14 * Subtype 0x0002 15 * 14 16 * conn must be a chatnav connection! 17 * 15 18 */ 16 19 faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn) … … 19 22 } 20 23 24 /* 25 * Subtype 0x0008 26 */ 21 27 faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange) 22 28 { … … 346 352 347 353 /* 354 * Subtype 0x0009 355 * 348 356 * Since multiple things can trigger this callback, we must lookup the 349 357 * snacid to determine the original snac subtype that was called. … … 416 424 417 425 mod->family = 0x000d; 418 mod->version = 0x000 1;426 mod->version = 0x0003; 419 427 mod->toolid = 0x0010; 420 428 mod->toolversion = 0x047c; -
libfaim/conn.c
r5e53c4a r862371b 1 2 1 /* 3 2 * conn.c … … 15 14 #include <sys/socket.h> 16 15 #include <netinet/in.h> 16 #endif 17 18 #ifdef _WIN32 19 #include "win32dep.h" 17 20 #endif 18 21 … … 446 449 i = 3; 447 450 } 448 449 451 if (write(fd, buf, i) < i) { 450 452 *statusret = errno; … … 452 454 return -1; 453 455 } 454 455 456 if (read(fd, buf, 2) < 2) { 456 457 *statusret = errno; … … 502 503 return -1; 503 504 } 505 504 506 if (read(fd, buf, 10) < 10) { 505 507 *statusret = errno; … … 877 879 sess->modlistv = NULL; 878 880 881 sess->ssi.received_data = 0; 882 sess->ssi.waiting_for_ack = 0; 883 sess->ssi.holding_queue = NULL; 884 sess->ssi.revision = 0; 885 sess->ssi.items = NULL; 886 sess->ssi.timestamp = (time_t)0; 887 888 sess->emailinfo = NULL; 889 879 890 /* 880 891 * Default to SNAC login unless XORLOGIN is explicitly set. … … 909 920 aim__registermodule(sess, chatnav_modfirst); 910 921 aim__registermodule(sess, chat_modfirst); 911 /* missing 0x0f - 0x12 */ 922 aim__registermodule(sess, newsearch_modfirst); 923 /* missing 0x10 - 0x12 */ 912 924 aim__registermodule(sess, ssi_modfirst); 913 925 /* missing 0x14 */ 914 aim__registermodule(sess, icq_modfirst); 926 aim__registermodule(sess, icq_modfirst); /* XXX - Make sure this isn't sent for AIM */ 915 927 /* missing 0x16 */ 916 928 aim__registermodule(sess, auth_modfirst); 929 aim__registermodule(sess, email_modfirst); 917 930 918 931 return; … … 981 994 fd_set fds, wfds; 982 995 struct timeval tv; 983 int res, error = ETIMEDOUT; 996 int res; 997 int error = ETIMEDOUT; 998 984 999 aim_rxcallback_t userfunc; 985 1000 … … 1009 1024 if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { 1010 1025 int len = sizeof(error); 1011 1012 1026 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) 1013 1027 error = errno; … … 1019 1033 return -1; 1020 1034 } 1021 1022 1035 fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ 1023 1036 … … 1054 1067 1055 1068 return 0; 1056 1057 1069 } 1058 1070 … … 1061 1073 * 1062 1074 * No-op. WinAIM 4.x sends these _every minute_ to keep 1063 * the connection alive. 1075 * the connection alive. 1064 1076 */ 1065 1077 faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn) … … 1074 1086 return 0; 1075 1087 } 1076 1077 -
libfaim/ft.c
r5e53c4a r862371b 10 10 #endif 11 11 #include <aim.h> 12 13 12 14 13 #ifndef _WIN32 … … 17 16 #include <netinet/in.h> 18 17 #include <sys/utsname.h> /* for aim_directim_initiate */ 19 20 18 #include <arpa/inet.h> /* for inet_ntoa */ 21 19 #define G_DIR_SEPARATOR '/' 22 20 #endif 23 21 24 /* TODO: 25 o look for memory leaks.. there's going to be shitloads, i'm sure. 26 */ 22 #ifdef _WIN32 23 #include "win32dep.h" 24 #endif 25 26 #define AIM_OFT_PROTO_OFFER 0x0101 27 #define AIM_OFT_PROTO_ACCEPT 0x0202 28 #define AIM_OFT_PROTO_RESUME 0x0205 29 #define AIM_OFT_PROTO_RESUMEACCEPT 0x0207 30 #define AIM_OFT_PROTO_ACK 0x0204 31 32 struct aim_filetransfer_priv { 33 char sn[MAXSNLEN+1]; 34 char cookie[8]; 35 char ip[30]; 36 int state; 37 struct aim_fileheader_t fh; 38 }; 27 39 28 40 struct aim_directim_intdata { … … 33 45 34 46 static int listenestablish(fu16_t portnum); 47 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs); 48 static void oft_dirconvert(char *name); 49 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh); 35 50 36 51 /** … … 90 105 aim_rxcallback_t userfunc; 91 106 92 93 107 newconn->priv = cur->priv; 94 108 cur->priv = NULL; … … 100 114 ret = userfunc(sess, NULL, newconn, cur); 101 115 #endif 116 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { 117 struct aim_filetransfer_priv *ft; 118 aim_rxcallback_t userfunc; 119 120 /* The new conn automatically inherits the internal value 121 * of cur. */ 122 cur->internal = NULL; 123 ft = (struct aim_filetransfer_priv *)newconn->internal; 124 125 snprintf(ft->ip, sizeof(ft->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); 126 127 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEINITIATE))) 128 ret = userfunc(sess, NULL, newconn, cur); 102 129 } else { 103 130 faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n"); … … 110 137 111 138 /** 139 * aim_send_typing - send client-to-client typing notification over established connection 140 * @sess: session to conn 141 * @conn: directim connection 142 * @typing: If true, notify user has started typing; if false, notify user has stopped. 143 * 144 * The connection must have been previously established. 145 */ 146 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) 147 { 148 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 149 aim_frame_t *fr; 150 aim_bstream_t *hdrbs; 151 fu8_t *hdr; 152 int hdrlen = 0x44; 153 154 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 155 return -EINVAL; 156 157 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) 158 return -ENOMEM; 159 memcpy(fr->hdr.rend.magic, "ODC2", 4); 160 fr->hdr.rend.hdrlen = hdrlen; 161 162 if (!(hdr = calloc(1, hdrlen))) { 163 aim_frame_destroy(fr); 164 return -ENOMEM; 165 } 166 167 hdrbs = &(fr->data); 168 aim_bstream_init(hdrbs, hdr, hdrlen); 169 170 aimbs_put16(hdrbs, 0x0006); 171 aimbs_put16(hdrbs, 0x0000); 172 aimbs_putraw(hdrbs, intdata->cookie, 8); 173 aimbs_put16(hdrbs, 0x0000); 174 aimbs_put16(hdrbs, 0x0000); 175 aimbs_put16(hdrbs, 0x0000); 176 aimbs_put16(hdrbs, 0x0000); 177 aimbs_put32(hdrbs, 0x00000000); 178 aimbs_put16(hdrbs, 0x0000); 179 aimbs_put16(hdrbs, 0x0000); 180 aimbs_put16(hdrbs, 0x0000); 181 182 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */ 183 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002)); 184 185 aimbs_put16(hdrbs, 0x0000); 186 aimbs_put16(hdrbs, 0x0000); 187 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 188 189 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 190 191 aimbs_put8(hdrbs, 0x00); 192 aimbs_put16(hdrbs, 0x0000); 193 aimbs_put16(hdrbs, 0x0000); 194 aimbs_put16(hdrbs, 0x0000); 195 aimbs_put16(hdrbs, 0x0000); 196 aimbs_put16(hdrbs, 0x0000); 197 aimbs_put16(hdrbs, 0x0000); 198 aimbs_put16(hdrbs, 0x0000); 199 aimbs_put8(hdrbs, 0x00); 200 201 /* end of hdr */ 202 203 aim_tx_enqueue(sess, fr); 204 205 return 0; 206 } 207 208 /** 112 209 * aim_send_im_direct - send IM client-to-client over established connection 113 210 * @sess: session to conn 114 211 * @conn: directim connection 115 * @msg: null-terminated string to send; if this is NULL, it will send a "typing" notice. 116 * 212 * @msg: null-terminated string to send. 213 * @len: The length of the message to send, including binary data. 214 * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1 215 * 117 216 * Call this just like you would aim_send_im, to send a directim. You 118 217 * _must_ have previously established the directim connection. 119 218 */ 120 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg )219 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding) 121 220 { 122 221 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 123 222 aim_frame_t *fr; 124 aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */ 125 126 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 223 aim_bstream_t *hdrbs; 224 int hdrlen = 0x44; 225 fu8_t *hdr; 226 227 if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 127 228 return -EINVAL; 128 229 129 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, strlen(msg)))) 130 return -ENOMEM; 131 132 memcpy(fr->hdr.oft.magic, "ODC2", 4); 230 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len))) 231 return -ENOMEM; 232 233 memcpy(fr->hdr.rend.magic, "ODC2", 4); 234 fr->hdr.rend.hdrlen = hdrlen; 133 235 134 fr->hdr.oft.hdr2len = 0x44; 135 136 if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) { 236 if (!(hdr = calloc(1, hdrlen + len))) { 137 237 aim_frame_destroy(fr); 138 238 return -ENOMEM; 139 239 } 240 241 hdrbs = &(fr->data); 242 aim_bstream_init(hdrbs, hdr, hdrlen + len); 243 244 aimbs_put16(hdrbs, 0x0006); 245 aimbs_put16(hdrbs, 0x0000); 246 aimbs_putraw(hdrbs, intdata->cookie, 8); 247 aimbs_put16(hdrbs, 0x0000); 248 aimbs_put16(hdrbs, 0x0000); 249 aimbs_put16(hdrbs, 0x0000); 250 aimbs_put16(hdrbs, 0x0000); 251 aimbs_put32(hdrbs, len); 252 aimbs_put16(hdrbs, encoding); 253 aimbs_put16(hdrbs, 0x0000); 254 aimbs_put16(hdrbs, 0x0000); 140 255 141 aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); 142 143 aimbs_put16(&hdrbs, 0x0006); 144 aimbs_put16(&hdrbs, 0x0000); 145 aimbs_putraw(&hdrbs, intdata->cookie, 8); 146 aimbs_put16(&hdrbs, 0x0000); 147 aimbs_put16(&hdrbs, 0x0000); 148 aimbs_put16(&hdrbs, 0x0000); 149 aimbs_put16(&hdrbs, 0x0000); 150 aimbs_put32(&hdrbs, strlen(msg)); 151 aimbs_put16(&hdrbs, 0x0000); 152 aimbs_put16(&hdrbs, 0x0000); 153 aimbs_put16(&hdrbs, 0x0000); 154 155 /* flags -- 0x000e for "typing", 0x0000 for message */ 156 aimbs_put16(&hdrbs, msg ? 0x0000 : 0x000e); 157 158 aimbs_put16(&hdrbs, 0x0000); 159 aimbs_put16(&hdrbs, 0x0000); 160 aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn)); 161 162 aim_bstream_setpos(&hdrbs, 52); /* bleeehh */ 163 164 aimbs_put8(&hdrbs, 0x00); 165 aimbs_put16(&hdrbs, 0x0000); 166 aimbs_put16(&hdrbs, 0x0000); 167 aimbs_put16(&hdrbs, 0x0000); 168 aimbs_put16(&hdrbs, 0x0000); 169 aimbs_put16(&hdrbs, 0x0000); 170 aimbs_put16(&hdrbs, 0x0000); 171 aimbs_put16(&hdrbs, 0x0000); 172 256 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */ 257 aimbs_put16(hdrbs, 0x0000); 258 259 aimbs_put16(hdrbs, 0x0000); 260 aimbs_put16(hdrbs, 0x0000); 261 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 262 263 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 264 265 aimbs_put8(hdrbs, 0x00); 266 aimbs_put16(hdrbs, 0x0000); 267 aimbs_put16(hdrbs, 0x0000); 268 aimbs_put16(hdrbs, 0x0000); 269 aimbs_put16(hdrbs, 0x0000); 270 aimbs_put16(hdrbs, 0x0000); 271 aimbs_put16(hdrbs, 0x0000); 272 aimbs_put16(hdrbs, 0x0000); 273 aimbs_put8(hdrbs, 0x00); 274 173 275 /* end of hdr2 */ 174 175 if (msg) { 276 176 277 #if 0 /* XXX this is how you send buddy icon info... */ 177 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);178 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);179 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);180 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);181 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);182 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);183 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);184 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);278 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); 279 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c); 280 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); 281 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466); 282 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); 283 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); 284 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); 285 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8); 185 286 #endif 186 aimbs_putraw(&fr->data, msg, strlen(msg)); 187 } 188 287 aimbs_putraw(hdrbs, msg, len); 288 189 289 aim_tx_enqueue(sess, fr); 190 290 191 291 return 0; 192 292 } … … 279 379 * 280 380 */ 281 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize )381 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret) 282 382 { 283 383 aim_conn_t *newconn; 284 384 aim_msgcookie_t *cookie; 285 struct aim_ directim_intdata *priv;385 struct aim_filetransfer_priv *ft; 286 386 int listenfd; 387 388 /* XXX allow different ports */ 287 389 fu16_t port = 4443; 288 390 fu8_t localip[4]; … … 299 401 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); 300 402 memcpy(cookie->cookie, ck, 8); 301 cookie->type = AIM_COOKIETYPE_OFTIM; 403 cookie->type = AIM_COOKIETYPE_OFTSEND; 404 memcpy(cookret, ck, 8); 302 405 303 406 /* this one is for the cookie */ 304 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));305 306 memcpy( priv->cookie, ck, 8);307 strncpy( priv->sn, destsn, sizeof(priv->sn));308 cookie->data = priv;407 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 408 409 memcpy(ft->cookie, ck, 8); 410 strncpy(ft->sn, destsn, sizeof(ft->sn)); 411 cookie->data = ft; 309 412 aim_cachecookie(sess, cookie); 310 413 311 /* XXX switch to aim_cloneconn()? */312 414 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { 313 415 close(listenfd); … … 316 418 317 419 /* this one is for the conn */ 318 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));319 320 memcpy( priv->cookie, ck, 8);321 strncpy( priv->sn, destsn, sizeof(priv->sn));420 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 421 422 memcpy(ft->cookie, ck, 8); 423 strncpy(ft->sn, destsn, sizeof(ft->sn)); 322 424 323 425 newconn->fd = listenfd; 324 426 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 325 newconn->internal = priv;427 newconn->internal = ft; 326 428 newconn->lastactivity = time(NULL); 327 429 … … 335 437 * unsigned int aim_oft_listener_clean - close up old listeners 336 438 * @sess: session to clean up in 337 * @age: maximum age in seconds 439 * @age: maximum age in seconds 338 440 * 339 441 * returns number closed, -1 on error. 340 442 */ 341 faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time_t age) 342 { 343 struct aim_conn_t *cur; 344 time_t now; 345 unsigned int hit = 0; 346 347 if (!sess) 348 return -1; 349 now = time(NULL); 350 faim_mutex_lock(&sess->connlistlock); 351 for(cur = sess->connlist;cur; cur = cur->next) 352 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 353 faim_mutex_lock(&cur->active); 354 if (cur->lastactivity < (now - age) ) { 355 faim_mutex_unlock(&cur->active); 356 aim_conn_close(cur); 357 hit++; 358 } else 359 faim_mutex_unlock(&cur->active); 360 } 361 faim_mutex_unlock(&sess->connlistlock); 362 return hit; 363 } 364 #endif 443 faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age) 444 { 445 aim_conn_t *cur; 446 time_t now; 447 unsigned int hit = 0; 448 449 if (!sess) 450 return -1; 451 now = time(NULL); 452 453 for(cur = sess->connlist;cur; cur = cur->next) 454 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 455 if (cur->lastactivity < (now - age) ) { 456 aim_conn_close(cur); 457 hit++; 458 } 459 } 460 return hit; 461 } 462 #endif 365 463 366 464 faim_export const char *aim_directim_getsn(aim_conn_t *conn) … … 369 467 370 468 if (!conn) 371 return NULL;469 return NULL; 372 470 373 471 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 374 472 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) 375 return NULL;473 return NULL; 376 474 377 475 if (!conn->internal) … … 432 530 * aim_directim_getconn - find a directim conn for buddy name 433 531 * @sess: your session, 434 * @name: the name to get, 532 * @name: the name to get, 435 533 * 436 534 * returns conn for directim with name, %NULL if none found. … … 466 564 * @cookie: the cookie used 467 565 * @ip: the ip to connect to 566 * @port: the port to use 567 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) 568 * 468 569 * @listingfiles: number of files to share 469 570 * @listingtotsize: total size of shared files 470 571 * @listingsize: length of the listing file(buffer) 471 572 * @listingchecksum: checksum of the listing 472 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)473 573 * 474 574 * Returns new connection or %NULL on error. … … 476 576 * XXX this should take a struct. 477 577 */ 478 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, 479 aim_conn_t *conn, 480 const char *sn, const fu8_t *cookie, 481 const fu8_t *ip, 482 fu16_t listingfiles, 483 fu16_t listingtotsize, 484 fu16_t listingsize, 485 fu32_t listingchecksum, 486 fu16_t rendid) 487 { 488 return NULL; 578 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, 579 const fu8_t *cookie, const fu8_t *ip, 580 fu16_t port, fu16_t rendid, ...) 581 { 582 aim_frame_t *newpacket; 583 aim_conn_t *newconn; 584 struct aim_filetransfer_priv *priv; 585 int i; 586 char addr[21]; 587 588 if (!sess || !conn || !sn || !cookie || !ip) { 589 return NULL; 590 } 591 592 /* OSCAR CAP accept packet */ 593 594 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 595 return NULL; 596 } 597 598 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 599 600 for (i = 0; i < 8; i++) 601 aimbs_put8(&newpacket->data, cookie[i]); 602 603 aimbs_put16(&newpacket->data, 0x0002); 604 aimbs_put8(&newpacket->data, strlen(sn)); 605 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 606 aimbs_put16(&newpacket->data, 0x0005); 607 aimbs_put16(&newpacket->data, 0x001a); 608 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT); 609 610 for (i = 0; i < 8; i++) /* yes, again... */ 611 aimbs_put8(&newpacket->data, cookie[i]); 612 613 aim_putcap(&newpacket->data, rendid); 614 aim_tx_enqueue(sess, newpacket); 615 616 snprintf(addr, sizeof(addr), "%s:%d", ip, port); 617 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr); 618 619 if (newconn->status & AIM_CONN_STATUS_CONNERR) { 620 return NULL; 621 } 622 623 if (!newconn || (newconn->fd == -1)) { 624 perror("aim_newconn"); 625 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0); 626 return newconn; 627 } 628 629 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 630 631 memcpy(priv->cookie, cookie, 8); 632 priv->state = 0; 633 strncpy(priv->sn, sn, MAXSNLEN); 634 strncpy(priv->ip, ip, sizeof(priv->ip)); 635 newconn->internal = (void *)priv; 636 637 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd); 638 639 if (rendid == AIM_CAPS_GETFILE) { 640 return NULL; /* This should never happen for now. -- wtm */ 641 489 642 #if 0 490 struct command_tx_struct *newpacket, *newoft; 491 struct aim_conn_t *newconn; 492 struct aim_fileheader_t *fh; 493 struct aim_filetransfer_priv *priv; 494 struct aim_msgcookie_t *cachedcook; 495 int curbyte, i; 496 497 if (!sess || !conn || !sn || !cookie || !ip) { 498 return NULL; 499 } 500 501 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip); 502 503 if (!newconn || (newconn->fd == -1)) { 504 perror("aim_newconn"); 505 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0); 506 return newconn; 507 } else { 508 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 509 510 memcpy(priv->cookie, cookie, 8); 511 priv->state = 0; 512 strncpy(priv->sn, sn, MAXSNLEN); 513 strncpy(priv->ip, ip, sizeof(priv->ip)); 514 newconn->priv = (void *)priv; 515 516 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd); 517 } 518 519 if (rendid == AIM_CAPS_GETFILE) { 520 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 521 522 faimdprintf(sess, 2, "faim: getfile request accept\n"); 523 524 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 525 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 526 /* XXX: conn leak here */ 527 return NULL; 528 } 529 530 newoft->lock = 1; 531 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 532 newoft->hdr.oft.hdr2len = 0x100 - 8; 533 534 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) { 535 /* XXX: conn leak here */ 536 perror("calloc"); 537 return NULL; 538 } 539 540 fh->encrypt = 0x0000; 541 fh->compress = 0x0000; 542 fh->totfiles = listingfiles; 543 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/ 544 fh->totparts = 0x0001; 545 fh->partsleft = 0x0001; 546 fh->totsize = listingtotsize; 547 fh->size = listingsize; /* ls -l listing.txt */ 548 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 549 fh->checksum = listingchecksum; 550 fh->rfcsum = 0x00000000; 551 fh->rfsize = 0x00000000; 552 fh->cretime = 0x00000000; 553 fh->rfcsum = 0x00000000; 554 fh->nrecvd = 0x00000000; 555 fh->recvcsum = 0x00000000; 556 memset(fh->idstring, 0, sizeof(fh->idstring)); 557 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 558 fh->flags = 0x02; 559 fh->lnameoffset = 0x1a; 560 fh->lsizeoffset = 0x10; 561 memset(fh->dummy, 0, sizeof(fh->dummy)); 562 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 563 564 /* we need to figure out these encodings for filenames */ 565 fh->nencode = 0x0000; 566 fh->nlanguage = 0x0000; 567 memset(fh->name, 0, sizeof(fh->name)); 568 memcpy(fh->name, "listing.txt", sizeof(fh->name)); 569 570 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 571 newoft->lock = 0; 572 aim_frame_destroy(newoft); 573 /* XXX: conn leak */ 574 perror("calloc (1)"); 575 return NULL; 576 } 577 578 memcpy(fh->bcookie, cookie, 8); 579 580 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh))) 581 faimdprintf(sess, 1, "eek, bh fail!\n"); 582 583 newoft->lock = 0; 584 aim_tx_enqueue(sess, newoft); 585 586 if (!(cachedcook = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) { 587 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n"); 588 /* XXX: more cleanup, conn leak */ 589 perror("calloc (2)"); 590 return NULL; 591 } 592 593 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t)); 594 memcpy(cachedcook->cookie, cookie, 8); 595 596 cachedcook->type = AIM_COOKIETYPE_OFTGET; 597 cachedcook->data = (void *)priv; 598 599 if (aim_cachecookie(sess, cachedcook) == -1) 600 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n"); 601 602 free(fh); 603 604 /* OSCAR CAP accept packet */ 605 606 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 607 return NULL; 608 } 609 } else { 610 return NULL; 611 } 612 613 newpacket->lock = 1; 614 curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); 615 616 for (i = 0; i < 8; i++) 617 curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); 618 619 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 620 curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); 621 curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); 622 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 623 curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a); 624 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept*/); 625 626 for (i = 0;i < 8; i++) 627 curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); 628 629 curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid); 630 newpacket->lock = 0; 631 aim_tx_enqueue(sess, newpacket); 632 633 return newconn; 643 struct aim_fileheader_t *fh; 644 aim_frame_t *newoft; 645 aim_msgcookie_t *cachedcook; 646 /* XXX take the following parameters fu16_t listingfiles, 647 fu16_t listingtotsize, 648 fu16_t listingsize, 649 fu32_t listingchecksum, */ 650 651 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 652 653 faimdprintf(sess, 2, "faim: getfile request accept\n"); 654 655 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 656 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 657 /* XXX: conn leak here */ 658 return NULL; 659 } 660 661 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 662 newoft->hdr.oft.hdr2len = 0x100 - 8; 663 664 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) { 665 /* XXX: conn leak here */ 666 perror("calloc"); 667 return NULL; 668 } 669 670 fh->encrypt = 0x0000; 671 fh->compress = 0x0000; 672 fh->totfiles = listingfiles; 673 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/ 674 fh->totparts = 0x0001; 675 fh->partsleft = 0x0001; 676 fh->totsize = listingtotsize; 677 fh->size = listingsize; /* ls -l listing.txt */ 678 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 679 fh->checksum = listingchecksum; 680 fh->rfcsum = 0x00000000; 681 fh->rfsize = 0x00000000; 682 fh->cretime = 0x00000000; 683 fh->rfcsum = 0x00000000; 684 fh->nrecvd = 0x00000000; 685 fh->recvcsum = 0x00000000; 686 memset(fh->idstring, 0, sizeof(fh->idstring)); 687 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 688 fh->flags = 0x02; 689 fh->lnameoffset = 0x1a; 690 fh->lsizeoffset = 0x10; 691 memset(fh->dummy, 0, sizeof(fh->dummy)); 692 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 693 694 /* we need to figure out these encodings for filenames */ 695 fh->nencode = 0x0000; 696 fh->nlanguage = 0x0000; 697 memset(fh->name, 0, sizeof(fh->name)); 698 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 699 700 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 701 aim_frame_destroy(newoft); 702 /* XXX: conn leak */ 703 perror("calloc (1)"); 704 return NULL; 705 } 706 707 memcpy(fh->bcookie, cookie, 8); 708 709 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh))) 710 faimdprintf(sess, 1, "eek, bh fail!\n"); 711 712 aim_tx_enqueue(sess, newoft); 713 714 if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { 715 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n"); 716 /* XXX: more cleanup, conn leak */ 717 perror("calloc (2)"); 718 return NULL; 719 } 720 721 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t)); 722 memcpy(cachedcook->cookie, cookie, 8); 723 724 cachedcook->type = AIM_COOKIETYPE_OFTGET; 725 /* XXX doesn't priv need to be copied so we don't 726 * double free? -- wtm 727 */ 728 cachedcook->data = (void *)priv; 729 730 if (aim_cachecookie(sess, cachedcook) == -1) 731 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n"); 732 733 free(fh); 634 734 #endif 735 736 } else if (rendid == AIM_CAPS_SENDFILE) { 737 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 738 priv->fh.recvcsum = 0xffff0000; 739 } else { 740 return NULL; 741 } 742 743 return newconn; 744 } 745 746 /* conn is a BOS connection over which to send the cancel msg */ 747 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn, 748 const char *cookie, const char *sn, int rendid) 749 { 750 aim_frame_t *newpacket; 751 int i; 752 753 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 754 return 1; 755 } 756 757 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 758 759 for (i = 0; i < 8; i++) 760 aimbs_put8(&newpacket->data, cookie[i]); 761 762 aimbs_put16(&newpacket->data, 0x0002); 763 aimbs_put8(&newpacket->data, strlen(sn)); 764 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 765 aimbs_put16(&newpacket->data, 0x0005); 766 aimbs_put16(&newpacket->data, 0x001a); 767 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL); 768 769 for (i = 0; i < 8; i++) 770 aimbs_put8(&newpacket->data, cookie[i]); 771 772 aim_putcap(&newpacket->data, rendid); 773 aim_tx_enqueue(sess, newpacket); 774 775 return 0; 635 776 } 636 777 637 778 /** 638 779 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE* 639 * @file is an opened listing file780 * @file is an opened listing file 640 781 * 641 782 * returns a pointer to the filled-in fileheader_t … … 649 790 return NULL; 650 791 #if 0 651 struct aim_fileheader_t *fh;652 u_long totsize = 0, size = 0, checksum = 0xffff0000;653 short totfiles = 0;654 char *linebuf, sizebuf[9];655 656 int linelength = 1024; 657 658 /* XXX: if we have a line longer than 1024chars, God help us. */ 659 if ( (linebuf = (char *)calloc(1, linelength)) == NULL ) { 660 faimdprintf(sess, 2, "linebuf calloc failed\n");661 return NULL; 662 } 663 664 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */ 665 perror("getlisting END1 fseek:");666 faimdprintf(sess, 2, "getlising fseek END1 error\n"); 667 } 668 669 if ((size = ftell(file)) == -1) { 670 perror("getlisting END1 getpos:");671 faimdprintf(sess, 2, "getlising getpos END1 error\n"); 672 } 673 674 if (fseek(file, 0, SEEK_SET) != 0) { 675 perror("getlesting fseek(SET):");676 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n"); 677 } 678 679 memset(linebuf, 0, linelength); 680 681 size = 0; 682 683 while(fgets(linebuf, linelength, file)) { 684 totfiles++;685 memset(sizebuf, 0, 9); 686 687 size += strlen(linebuf); 688 689 if (strlen(linebuf) < 23) { 690 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);691 continue; 692 } 693 if (linebuf[strlen(linebuf)-1] != '\n') {694 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");695 }696 697 memcpy(sizebuf, linebuf+17, 8);698 699 totsize += strtol(sizebuf, NULL, 10);700 memset(linebuf, 0, linelength);701 } 702 703 if (fseek(file, 0, SEEK_SET) == -1) {704 perror("getlisting END2 fseek:");705 faimdprintf(sess, 2, "getlising fseek END2 error\n");706 } 707 708 free(linebuf);709 710 /* we're going to ignore checksumming the data for now -- that711 * requires walking the whole listing.txt. it should probably be712 * done at register time and cached, but, eh. */ 713 714 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))715 return NULL;716 717 fh->encrypt= 0x0000;718 fh->compress = 0x0000; 719 fh->totfiles= totfiles;720 fh->filesleft = totfiles; /* is this right ?*/721 fh->totparts= 0x0001;722 fh->partsleft= 0x0001;723 fh->totsize= totsize;724 fh->size= size; /* ls -l listing.txt */725 fh->modtime= (int)time(NULL); /* we'll go with current time for now */726 fh->checksum= checksum; /* XXX: checksum ! */727 fh->rfcsum= 0x00000000;728 fh->rfsize= 0x00000000;729 fh->cretime= 0x00000000;730 fh->rfcsum= 0x00000000;731 fh->nrecvd= 0x00000000;732 fh->recvcsum= 0x00000000;733 734 /*memset(fh->idstring, 0, sizeof(fh->idstring)); */735 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));736 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));737 738 fh->flags= 0x02;739 fh->lnameoffset = 0x1a;740 fh->lsizeoffset = 0x10;741 742 /*memset(fh->dummy, 0, sizeof(fh->dummy)); */743 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));744 745 fh->nencode= 0x0000; /* we need to figure out these encodings for filenames */746 fh->nlanguage= 0x0000;747 748 /*memset(fh->name, 0, sizeof(fh->name)); */749 memcpy(fh->name, "listing.txt", sizeof(fh->name));750 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));751 752 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));753 return fh;792 struct aim_fileheader_t *fh; 793 u_long totsize = 0, size = 0, checksum = 0xffff0000; 794 short totfiles = 0; 795 char *linebuf, sizebuf[9]; 796 int linelength = 1024; 797 798 /* XXX: if we have a line longer than 1024chars, God help us. */ 799 if ((linebuf = (char *)calloc(1, linelength)) == NULL ) { 800 faimdprintf(sess, 2, "linebuf calloc failed\n"); 801 return NULL; 802 } 803 804 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */ 805 perror("getlisting END1 fseek:"); 806 faimdprintf(sess, 2, "getlising fseek END1 error\n"); 807 } 808 809 if ((size = ftell(file)) == -1) { 810 perror("getlisting END1 getpos:"); 811 faimdprintf(sess, 2, "getlising getpos END1 error\n"); 812 } 813 814 if (fseek(file, 0, SEEK_SET) != 0) { 815 perror("getlesting fseek(SET):"); 816 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n"); 817 } 818 819 memset(linebuf, 0, linelength); 820 821 size = 0; 822 823 while(fgets(linebuf, linelength, file)) { 824 totfiles++; 825 memset(sizebuf, 0, 9); 826 827 size += strlen(linebuf); 828 829 if (strlen(linebuf) < 23) { 830 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf); 831 continue; 832 } 833 834 if (linebuf[strlen(linebuf)-1] != '\n') { 835 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n"); 836 } 837 838 memcpy(sizebuf, linebuf+17, 8); 839 840 totsize += strtol(sizebuf, NULL, 10); 841 memset(linebuf, 0, linelength); 842 } 843 844 if (fseek(file, 0, SEEK_SET) == -1) { 845 perror("getlisting END2 fseek:"); 846 faimdprintf(sess, 2, "getlising fseek END2 error\n"); 847 } 848 849 free(linebuf); 850 851 /* we're going to ignore checksumming the data for now -- that 852 * requires walking the whole listing.txt. it should probably be 853 * done at register time and cached, but, eh. */ 854 855 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 856 return NULL; 857 858 fh->encrypt = 0x0000; 859 fh->compress = 0x0000; 860 fh->totfiles = totfiles; 861 fh->filesleft = totfiles; /* is this right? */ 862 fh->totparts = 0x0001; 863 fh->partsleft = 0x0001; 864 fh->totsize = totsize; 865 fh->size = size; /* ls -l listing.txt */ 866 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 867 fh->checksum = checksum; /* XXX: checksum ! */ 868 fh->rfcsum = 0x00000000; 869 fh->rfsize = 0x00000000; 870 fh->cretime = 0x00000000; 871 fh->rfcsum = 0x00000000; 872 fh->nrecvd = 0x00000000; 873 fh->recvcsum = 0x00000000; 874 875 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */ 876 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 877 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring)); 878 879 fh->flags = 0x02; 880 fh->lnameoffset = 0x1a; 881 fh->lsizeoffset = 0x10; 882 883 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */ 884 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 885 886 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */ 887 fh->nlanguage = 0x0000; 888 889 /* memset(fh->name, 0, sizeof(fh->name)); */ 890 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 891 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name)); 892 893 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name)))); 894 return fh; 754 895 #endif 755 896 } … … 757 898 /** 758 899 * aim_listenestablish - create a listening socket on a port. 759 * @portnum: the port number to bind to. 900 * @portnum: the port number to bind to. 760 901 * 761 902 * you need to call accept() when it's connected. returns your fd … … 784 925 ressave = res; 785 926 do { 786 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 927 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 787 928 if (listenfd < 0) 788 929 continue; … … 802 943 } 803 944 945 fcntl(listenfd, F_SETFL, O_NONBLOCK); 946 804 947 freeaddrinfo(ressave); 805 948 return listenfd; … … 834 977 return -1; 835 978 } 979 fcntl(listenfd, F_SETFL, O_NONBLOCK); 836 980 return listenfd; 837 981 #endif … … 849 993 int ret = 0; 850 994 char *listing; 851 struct command_tx_struct *newoft;995 aim_frame_t *newoft; 852 996 853 997 if (!(listing = malloc(ft->fh.size))) … … 860 1004 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { 861 1005 faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); 862 faim_mutex_unlock(&conn->active);863 1006 free(listing); 864 1007 aim_conn_close(conn); … … 896 1039 /* waiting on file data */ 897 1040 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) ) 898 return userfunc(sess, NULL, conn, ft); 1041 return userfunc(sess, NULL, conn, ft->fh.name, 1042 ft->fh.size); 899 1043 return 0; 900 1044 } … … 916 1060 { 917 1061 aim_msgcookie_t *cook; 918 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn-> priv;1062 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->internal; 919 1063 920 1064 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); … … 926 1070 static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn) 927 1071 { 928 929 1072 free(conn->internal); 930 1073 … … 934 1077 static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn) 935 1078 { 1079 #if 0 936 1080 aim_msgcookie_t *cook; 937 1081 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv; … … 939 1083 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET); 940 1084 aim_cookie_free(sess, cook); 941 1085 #endif 942 1086 return; 943 1087 } … … 1002 1146 } 1003 1147 1004 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)1148 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 1005 1149 { 1006 1150 aim_frame_t fr; 1007 1151 aim_rxcallback_t userfunc; 1008 1152 fu32_t payloadlength; 1009 fu16_t flags ;1153 fu16_t flags, encoding; 1010 1154 char *snptr = NULL; 1011 1155 1012 1156 fr.conn = conn; 1013 1157 1014 payloadlength = aimutil_get32(hdr+22); 1015 flags = aimutil_get16(hdr+32); 1016 snptr = (char *)hdr+38; 1158 /* XXX ugly */ 1159 aim_bstream_setpos(bs, 20); 1160 payloadlength = aimbs_get32(bs); 1161 1162 aim_bstream_setpos(bs, 24); 1163 encoding = aimbs_get16(bs); 1164 1165 aim_bstream_setpos(bs, 30); 1166 flags = aimbs_get16(bs); 1167 1168 aim_bstream_setpos(bs, 36); 1169 /* XXX -create an aimbs_getnullstr function? */ 1170 snptr = aimbs_getstr(bs, MAXSNLEN); 1017 1171 1018 1172 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr); 1019 1173 1020 if (flags == 0x000e) {1174 if (flags & 0x0002) { 1021 1175 int ret = 0; 1022 1176 1177 if (flags == 0x000c) { 1178 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1179 ret = userfunc(sess, &fr, snptr, 1); 1180 return ret; 1181 } 1182 1023 1183 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1024 ret = userfunc(sess, &fr, snptr );1184 ret = userfunc(sess, &fr, snptr, 0); 1025 1185 1026 1186 return ret; 1027 1187 1028 } else if (( flags == 0x0000) && payloadlength) {1029 char *msg ;1188 } else if (((flags & 0x000f) == 0x0000) && payloadlength) { 1189 char *msg, *msg2; 1030 1190 int ret = 0; 1191 int recvd = 0; 1192 int i; 1031 1193 1032 1194 if (!(msg = calloc(1, payloadlength+1))) 1033 1195 return -1; 1034 1035 if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) { 1036 free(msg); 1037 return -1; 1196 msg2 = msg; 1197 1198 while (payloadlength - recvd) { 1199 if (payloadlength - recvd >= 1024) 1200 i = aim_recv(conn->fd, msg2, 1024); 1201 else 1202 i = aim_recv(conn->fd, msg2, payloadlength - recvd); 1203 if (i <= 0) { 1204 free(msg); 1205 return -1; 1206 } 1207 recvd = recvd + i; 1208 msg2 = msg2 + i; 1209 if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) 1210 userfunc(sess, &fr, snptr, (double)recvd / payloadlength); 1038 1211 } 1039 1040 msg[payloadlength] = '\0'; 1041 1212 1042 1213 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) ) 1043 ret = userfunc(sess, &fr, snptr, msg );1214 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding); 1044 1215 1045 1216 free(msg); … … 1057 1228 struct aim_fileheader_t *fh; 1058 1229 struct aim_msgcookie_t *cook; 1059 struct command_tx_struct *newoft;1230 aim_frame_t *newoft; 1060 1231 aim_rxcallback_t userfunc; 1061 1232 … … 1081 1252 faimdprintf(sess, 1, "error caching cookie\n"); 1082 1253 return -1; 1083 } 1254 } 1084 1255 1085 1256 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) { … … 1121 1292 1122 1293 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) 1123 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);1294 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie); 1124 1295 1125 1296 ft = cook->data; … … 1173 1344 #if 0 1174 1345 struct aim_filetransfer_priv *ft; 1175 structaim_msgcookie_t *cook;1346 aim_msgcookie_t *cook; 1176 1347 struct aim_fileheader_t *fh; 1177 struct command_tx_struct *newoft;1348 aim_frame_t *newoft; 1178 1349 int i = 0; 1179 1350 aim_rxcallback_t userfunc; … … 1205 1376 } 1206 1377 1207 newoft->lock = 1;1208 1378 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1209 1379 newoft->hdr.oft.hdr2len = 0x100 - 8; … … 1221 1391 aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); 1222 1392 1223 newoft->lock = 0;1224 1393 aim_tx_enqueue(sess, newoft); 1225 1394 … … 1288 1457 } 1289 1458 1459 /* We are receiving a file, and the buddy sent us this header describing 1460 * it. We send back a similar header to confirm, then we're ready to 1461 * start reading the raw data. 1462 */ 1463 static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 1464 { 1465 struct aim_filetransfer_priv *ft; 1466 struct aim_fileheader_t *fh; 1467 aim_frame_t *newoft; 1468 aim_rxcallback_t userfunc; 1469 1470 fh = aim_oft_getfh(bs); 1471 1472 /* We receive a null cookie for the first file; we must fill 1473 * it in to authenticate ourselves. -- wtm 1474 */ 1475 ft = conn->internal; 1476 memcpy(&(fh->bcookie), ft->cookie, 8); 1477 1478 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 1479 free(fh); 1480 1481 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) { 1482 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); 1483 return -1; 1484 } 1485 1486 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 1487 return -1; 1488 } 1489 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 1490 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 1491 1492 aim_tx_enqueue(sess, newoft); 1493 1494 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL) 1495 return 1; 1496 1497 { 1498 char *cur; 1499 /* Convert the directory separator: it is sent 1500 * as ^A (0x01). 1501 */ 1502 while ((cur = strchr(ft->fh.name, 0x01))) { 1503 *cur = G_DIR_SEPARATOR; 1504 } 1505 } 1506 return userfunc(sess, NULL, conn, &(ft->fh)); 1507 } 1508 1509 1510 /* 1511 * These were originally described by Josh Myer: 1512 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/ 1513 * XXX this doesn't actually work yet 1514 * -- wtm 1515 */ 1516 static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) { 1517 aim_frame_t *newoft; 1518 aim_msgcookie_t *cook; 1519 struct aim_fileheader_t *fh; 1520 struct aim_filetransfer_priv *ft; 1521 1522 fh = aim_oft_getfh(bs); 1523 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1524 free(fh); 1525 return -1; 1526 } 1527 ft = (struct aim_filetransfer_priv *)cook->data; 1528 1529 ft->fh.nrecvd = fh->nrecvd; 1530 ft->fh.recvcsum = fh->recvcsum; 1531 strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name)); 1532 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) { 1533 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 1534 free(fh); 1535 return -1; 1536 } 1537 1538 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 1539 aim_frame_destroy(newoft); 1540 free(fh); 1541 return -1; 1542 } 1543 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 1544 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 1545 1546 aim_tx_enqueue(sess, newoft); 1547 free(fh); 1548 1549 return 0; 1550 } 1551 1552 /* We are sending a file, and the buddy sent us this header indicating 1553 * that he or she is ready for the raw data. 1554 */ 1555 static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) { 1556 struct aim_fileheader_t *fh; 1557 aim_msgcookie_t *cook; 1558 int ret = 1; 1559 struct aim_filetransfer_priv *ft; 1560 aim_rxcallback_t userfunc; 1561 1562 fh = aim_oft_getfh(bs); 1563 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1564 free(fh); 1565 return -1; 1566 } 1567 ft = (struct aim_filetransfer_priv *)cook->data; 1568 1569 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILESEND)) ) 1570 ret = userfunc(sess, NULL, conn, &(ft->fh)); 1571 1572 free(fh); 1573 1574 return ret; 1575 } 1576 1290 1577 static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1291 1578 { 1292 1579 #if 0 1293 1580 struct aim_fileheader_t *fh; 1294 struct aim_filetransfer_priv *ft;1295 1581 struct aim_msgcookie_t *cook; 1296 1582 int ret = 1; 1297 1583 aim_rxcallback_t userfunc; 1584 struct aim_filetransfer_priv *ft; 1298 1585 1299 1586 fh = aim_oft_getfh(hdr); … … 1319 1606 } 1320 1607 1608 /* We just sent the raw data of a file, and the buddy sent us back this 1609 * header indicating that the transfer is complete. 1610 */ 1611 static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 1612 { 1613 struct aim_fileheader_t *fh; 1614 aim_msgcookie_t *cook; 1615 aim_rxcallback_t userfunc; 1616 1617 fh = aim_oft_getfh(bs); 1618 1619 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1620 free(fh); 1621 return -1; 1622 } 1623 1624 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILECOMPLETE)) ) 1625 userfunc(sess, NULL, conn, fh->bcookie); 1626 1627 free(fh); 1628 return 0; 1629 } 1630 1321 1631 static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1322 1632 { … … 1338 1648 } 1339 1649 1340 /** 1341 * aim_get_command_rendezvous - OFT equivalent of aim_get_command 1342 * @sess: session to work on 1343 * @conn: conn to pull data from 1344 * 1345 * this reads and handles data from conn->fd. currently a little rough 1346 * around the edges 1347 */ 1348 faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn) 1349 { 1350 fu8_t hdrbuf1[6]; 1351 fu8_t *hdr = NULL; 1352 int hdrlen, hdrtype; 1650 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) 1651 { 1652 aim_conn_t *conn = fr->conn; 1653 aim_bstream_t *bs = &fr->data; 1353 1654 int ret = -1; 1354 1655 1355 if (!sess || !conn) 1356 return -1; 1357 1358 memset(hdrbuf1, 0, sizeof(hdrbuf1)); 1359 1360 /* I guess? I didn't understand any of that mess... */ 1361 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) 1656 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 1657 /* This should never happen. -- wtm */ 1362 1658 return getcommand_getfile(sess, conn); 1363 1659 1364 /* XXX fix all the error cases here */ 1365 if (aim_recv(conn->fd, hdrbuf1, 6) < 6) { 1366 1367 faimdprintf(sess, 2, "faim: rend: read error (fd: %i)\n", conn->fd); 1368 1369 aim_conn_close(conn); 1370 1371 return -1; 1372 } 1373 1374 hdrlen = aimutil_get16(hdrbuf1+4); 1375 hdrlen -= 6; 1376 1377 hdr = malloc(hdrlen); 1378 1379 if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) { 1380 faimdprintf(sess, 2, "faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen); 1381 free(hdr); 1382 aim_conn_close(conn); 1383 return -1; 1384 } 1385 1386 hdrtype = aimutil_get16(hdr); 1387 1388 if (hdrtype == 0x0001) 1389 ret = handlehdr_directim(sess, conn, hdr); 1390 else if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */ 1391 ret = handlehdr_getfile_listing(sess, conn, hdr); 1392 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */ 1393 ret = handlehdr_getfile_listing2(sess, conn, hdr); 1394 else if (hdrtype == 0x120b) /* get file listing rx confirm */ 1395 ret = handlehdr_getfile_listing3(sess, conn, hdr); 1396 else if (hdrtype == 0x120c) /* getfile request */ 1397 ret = handlehdr_getfile_request(sess, conn, hdr); 1398 else if (hdrtype == 0x0101) /* getfile sending data */ 1399 ret = handlehdr_getfile_sending(sess, conn, hdr); 1400 else if (hdrtype == 0x0202) /* getfile recv data */ 1401 ret = handlehdr_getfile_recv(sess, conn, hdr); 1402 else if (hdrtype == 0x0204) /* getfile finished */ 1403 ret = handlehdr_getfile_finish(sess, conn, hdr); 1404 else { 1405 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); 1406 ret = -1; 1660 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { 1661 switch(fr->hdr.rend.type) { 1662 case AIM_OFT_PROTO_OFFER: 1663 ret = handlehdr_sendfile_sending(sess, conn, bs); 1664 break; 1665 case AIM_OFT_PROTO_RESUME: 1666 ret = handlehdr_sendfile_resume(sess, conn, bs); 1667 break; 1668 case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */; 1669 case AIM_OFT_PROTO_ACCEPT: 1670 ret = handlehdr_sendfile_recv(sess, conn, bs); 1671 break; 1672 case AIM_OFT_PROTO_ACK: 1673 ret = handlehdr_sendfile_finish(sess, conn, bs); 1674 break; 1675 default: 1676 faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type); 1677 ret = -1; 1678 break; 1679 } 1680 1681 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 1682 if (fr->hdr.rend.type == 0x0001) 1683 ret = handlehdr_directim(sess, conn, bs); 1684 else 1685 faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type); 1686 1687 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 1688 /* This _really_ shouldn't happen. :) -- wtm */ 1689 char *hdr = NULL; 1690 int hdrtype = fr->hdr.rend.type; 1691 if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */ 1692 ret = handlehdr_getfile_listing(sess, conn, hdr); 1693 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */ 1694 ret = handlehdr_getfile_listing2(sess, conn, hdr); 1695 else if (hdrtype == 0x120b) /* get file listing rx confirm */ 1696 ret = handlehdr_getfile_listing3(sess, conn, hdr); 1697 else if (hdrtype == 0x120c) /* getfile request */ 1698 ret = handlehdr_getfile_request(sess, conn, hdr); 1699 else if (hdrtype == 0x0101) /* getfile sending data */ 1700 ret = handlehdr_getfile_sending(sess, conn, hdr); 1701 else if (hdrtype == 0x0202) /* getfile recv data */ 1702 ret = handlehdr_getfile_recv(sess, conn, hdr); 1703 else if (hdrtype == 0x0204) /* getfile finished */ 1704 ret = handlehdr_getfile_finish(sess, conn, hdr); 1705 else { 1706 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); 1707 ret = -1; 1708 } 1407 1709 } 1408 1710 1409 free(hdr);1410 1411 1711 if (ret == -1) 1412 1712 aim_conn_close(conn); … … 1415 1715 } 1416 1716 1417 #if 01418 1717 /** 1419 1718 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. 1420 * @hdr: buffer to extract header from 1421 * 1422 * returns pointer to new struct on success; %NULL on error. 1423 * 1424 */ 1425 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) 1426 { 1427 struct aim_fileheader_t *fh; 1428 int i, j; 1429 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) 1430 return NULL; 1431 1432 /* [0] and [1] are the type. we can ignore those here. */ 1433 i = 2; 1434 for(j = 0; j < 8; j++, i++) 1435 fh->bcookie[j] = hdr[i]; 1436 fh->encrypt = aimutil_get16(hdr+i); 1437 i += 2; 1438 fh->compress = aimutil_get16(hdr+i); 1439 i += 2; 1440 fh->totfiles = aimutil_get16(hdr+i); 1441 i += 2; 1442 fh->filesleft = aimutil_get16(hdr+i); 1443 i += 2; 1444 fh->totparts = aimutil_get16(hdr+i); 1445 i += 2; 1446 fh->partsleft = aimutil_get16(hdr+i); 1447 i += 2; 1448 fh->totsize = aimutil_get32(hdr+i); 1449 i += 4; 1450 fh->size = aimutil_get32(hdr+i); 1451 i += 4; 1452 fh->modtime = aimutil_get32(hdr+i); 1453 i += 4; 1454 fh->checksum = aimutil_get32(hdr+i); 1455 i += 4; 1456 fh->rfrcsum = aimutil_get32(hdr+i); 1457 i += 4; 1458 fh->rfsize = aimutil_get32(hdr+i); 1459 i += 4; 1460 fh->cretime = aimutil_get32(hdr+i); 1461 i += 4; 1462 fh->rfcsum = aimutil_get32(hdr+i); 1463 i += 4; 1464 fh->nrecvd = aimutil_get32(hdr+i); 1465 i += 4; 1466 fh->recvcsum = aimutil_get32(hdr+i); 1467 i += 4; 1468 memcpy(fh->idstring, hdr+i, 32); 1469 i += 32; 1470 fh->flags = aimutil_get8(hdr+i); 1471 i += 1; 1472 fh->lnameoffset = aimutil_get8(hdr+i); 1473 i += 1; 1474 fh->lsizeoffset = aimutil_get8(hdr+i); 1475 i += 1; 1476 memcpy(fh->dummy, hdr+i, 69); 1477 i += 69; 1478 memcpy(fh->macfileinfo, hdr+i, 16); 1479 i += 16; 1480 fh->nencode = aimutil_get16(hdr+i); 1481 i += 2; 1482 fh->nlanguage = aimutil_get16(hdr+i); 1483 i += 2; 1484 memcpy(fh->name, hdr+i, 64); 1485 i += 64; 1486 return fh; 1719 * @bs: bstream to extract header from 1720 * 1721 * returns pointer to new struct on success; %NULL on error. 1722 * 1723 */ 1724 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs) 1725 { 1726 struct aim_fileheader_t *fh; 1727 1728 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) 1729 return NULL; 1730 1731 /* The bstream should be positioned after the hdrtype. */ 1732 aimbs_getrawbuf(bs, fh->bcookie, 8); 1733 fh->encrypt = aimbs_get16(bs); 1734 fh->compress = aimbs_get16(bs); 1735 fh->totfiles = aimbs_get16(bs); 1736 fh->filesleft = aimbs_get16(bs); 1737 fh->totparts = aimbs_get16(bs); 1738 fh->partsleft = aimbs_get16(bs); 1739 fh->totsize = aimbs_get32(bs); 1740 fh->size = aimbs_get32(bs); 1741 fh->modtime = aimbs_get32(bs); 1742 fh->checksum = aimbs_get32(bs); 1743 fh->rfrcsum = aimbs_get32(bs); 1744 fh->rfsize = aimbs_get32(bs); 1745 fh->cretime = aimbs_get32(bs); 1746 fh->rfcsum = aimbs_get32(bs); 1747 fh->nrecvd = aimbs_get32(bs); 1748 fh->recvcsum = aimbs_get32(bs); 1749 aimbs_getrawbuf(bs, fh->idstring, 32); 1750 fh->flags = aimbs_get8(bs); 1751 fh->lnameoffset = aimbs_get8(bs); 1752 fh->lsizeoffset = aimbs_get8(bs); 1753 aimbs_getrawbuf(bs, fh->dummy, 69); 1754 aimbs_getrawbuf(bs, fh->macfileinfo, 16); 1755 fh->nencode = aimbs_get16(bs); 1756 fh->nlanguage = aimbs_get16(bs); 1757 aimbs_getrawbuf(bs, fh->name, 64); /* XXX */ 1758 1759 return fh; 1487 1760 } 1488 #endif1489 1761 1490 1762 /** … … 1492 1764 * @buffer: buffer of data to checksum 1493 1765 * @bufsize: size of buffer 1494 * @checksum: pointer to integer to place result in (pointer!) 1495 * 1496 * 1497 * Note that checksum is a pointer. Checksum should be filled with 1498 * 0xFFFF0000 for each new file; you can have this checksum chunks of 1499 * files in series if you just call it repeatedly in a for(; ; ) loop 1500 * and don't reset the checksum between each call. And you thought we 1501 * didn't care about you and your pathetic client's meomry footprint 1502 * ;^) 1503 * 1504 * 1505 * Also, it's been said that this is incorrect as currently 1506 * written. You were warned. 1507 */ 1508 faim_export fu32_t aim_oft_checksum(aim_session_t *sess, const char *buffer, int bufsize, fu32_t *checksum) 1509 { 1510 return 0xdeadbeef; 1511 #if 0 1512 fu16_t check0, check1; 1513 int i; 1514 1515 check0 = ((*checksum & 0xFF000000) >> 16); 1516 check1 = ((*checksum & 0x00ff0000) >> 16); 1517 for(i = 0; i < bufsize; i++) { 1518 if (i % 2) { /* use check1 -- second byte */ 1519 if ( (short)buffer[i] > check1 ) { /* wrapping */ 1520 check1 += 0x100; /* this is a cheap way to wrap */ 1521 1522 /* if we're wrapping, decrement the other one */ 1523 /* XXX: check this corner case */ 1524 if (check0 == 0) 1525 check0 = 0x00ff; 1526 else 1527 check0--; 1528 } 1529 check1 -= buffer[i]; 1530 } else { /* use check0 -- first byte */ 1531 if ( (short)buffer[i] > check0 ) { /* wrapping */ 1532 check0 += 0x100; /* this is a cheap way to wrap */ 1533 1534 /* if we're wrapping, decrement the other one */ 1535 /* XXX: check this corner case */ 1536 if (check1 == 0) 1537 check1 = 0x00ff; 1538 else 1539 check1--; 1540 } 1541 check0 -= buffer[i]; 1542 } 1543 } 1544 1545 if (check0 > 0xff || check1 > 0xff) { 1546 /* they shouldn't be able to do this. error! */ 1547 faimdprintf(sess, 2, "check0 or check1 is too high: 0x%04x, 0x%04x\n", check0, check1); 1548 return -1; 1549 } 1550 1551 /* grab just the lowest byte; this should be clean, but just in 1552 case */ 1553 check0 &= 0xff; 1554 check1 &= 0xff; 1555 1556 *checksum = ((check0 * 0x1000000) + (check1 * 0x10000)); 1557 return *checksum; 1558 #endif 1559 } 1560 1561 #if 0 1766 * @prevcheck: previous checksum 1767 * 1768 * Prevcheck should be 0xFFFF0000 for each new file; you can have this 1769 * checksum chunks of files in series if you just call it repeatedly in a 1770 * for(; ; ) loop and don't reset the checksum between each call. And you 1771 * thought we didn't care about you and your pathetic client's meomry 1772 * footprint ;^) 1773 * 1774 * Thanks to Graham Booker for providing this improved checksum 1775 * routine, which is simpler and should be more accurate than Josh 1776 * Myer's original code. -- wtm 1777 * 1778 * This algorithim works every time I have tried it. The other fails 1779 * sometimes. So, AOL who thought this up? It has got to be the weirdest 1780 * checksum I have ever seen. 1781 */ 1782 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) { 1783 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck; 1784 int i; 1785 unsigned short val; 1786 1787 for (i=0; i<bufferlen; i++) { 1788 oldcheck = check; 1789 if (i&1) { 1790 val = buffer[i]; 1791 } else { 1792 val = buffer[i] << 8; 1793 } 1794 check -= val; 1795 /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */ 1796 if (check > oldcheck) { 1797 check--; 1798 } 1799 } 1800 check = ((check & 0x0000ffff) + (check >> 16)); 1801 check = ((check & 0x0000ffff) + (check >> 16)); 1802 return check << 16; 1803 } 1804 1805 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn, 1806 const unsigned char *buffer, int len) { 1807 struct aim_filetransfer_priv *ft = conn->internal; 1808 1809 ft->fh.nrecvd += len; 1810 ft->fh.recvcsum = aim_oft_checksum(buffer, len, ft->fh.recvcsum); 1811 1812 return 0; 1813 } 1814 1562 1815 /** 1563 1816 * aim_oft_buildheader - fills a buffer with network-order fh data 1564 * @dest: buffer to fill -- pre-alloced 1565 * @fh: fh to get data from 1566 * 1567 * returns length written; -1 on error. 1568 * DOES NOT DO BOUNDS CHECKING! 1569 * 1570 */ 1571 static int oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) 1817 * @bs: bstream to fill -- automatically initialized 1818 * @fh: fh to get data from 1819 * 1820 * returns -1 on error. 1821 * 1822 */ 1823 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) 1572 1824 { 1573 int i, curbyte; 1574 if (!dest || !fh) 1575 return -1; 1576 curbyte = 0; 1577 for(i = 0; i < 8; i++) 1578 curbyte += aimutil_put8(dest+curbyte, fh->bcookie[i]); 1579 curbyte += aimutil_put16(dest+curbyte, fh->encrypt); 1580 curbyte += aimutil_put16(dest+curbyte, fh->compress); 1581 curbyte += aimutil_put16(dest+curbyte, fh->totfiles); 1582 curbyte += aimutil_put16(dest+curbyte, fh->filesleft); 1583 curbyte += aimutil_put16(dest+curbyte, fh->totparts); 1584 curbyte += aimutil_put16(dest+curbyte, fh->partsleft); 1585 curbyte += aimutil_put32(dest+curbyte, fh->totsize); 1586 curbyte += aimutil_put32(dest+curbyte, fh->size); 1587 curbyte += aimutil_put32(dest+curbyte, fh->modtime); 1588 curbyte += aimutil_put32(dest+curbyte, fh->checksum); 1589 curbyte += aimutil_put32(dest+curbyte, fh->rfrcsum); 1590 curbyte += aimutil_put32(dest+curbyte, fh->rfsize); 1591 curbyte += aimutil_put32(dest+curbyte, fh->cretime); 1592 curbyte += aimutil_put32(dest+curbyte, fh->rfcsum); 1593 curbyte += aimutil_put32(dest+curbyte, fh->nrecvd); 1594 curbyte += aimutil_put32(dest+curbyte, fh->recvcsum); 1595 memcpy(dest+curbyte, fh->idstring, 32); 1596 curbyte += 32; 1597 curbyte += aimutil_put8(dest+curbyte, fh->flags); 1598 curbyte += aimutil_put8(dest+curbyte, fh->lnameoffset); 1599 curbyte += aimutil_put8(dest+curbyte, fh->lsizeoffset); 1600 memcpy(dest+curbyte, fh->dummy, 69); 1601 curbyte += 69; 1602 memcpy(dest+curbyte, fh->macfileinfo, 16); 1603 curbyte += 16; 1604 curbyte += aimutil_put16(dest+curbyte, fh->nencode); 1605 curbyte += aimutil_put16(dest+curbyte, fh->nlanguage); 1606 memset(dest+curbyte, 0x00, 64); 1607 memcpy(dest+curbyte, fh->name, 64); 1608 1609 /* XXX: Filenames longer than 64B */ 1610 curbyte += 64; 1611 return curbyte; 1612 } 1613 #endif 1825 fu8_t *hdr; 1826 1827 if (!bs || !fh) 1828 return -1; 1829 1830 1831 1832 1833 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) { 1834 return -1; 1835 } 1836 aim_bstream_init(bs, hdr, 0x100 - 8); 1837 1838 aimbs_putraw(bs, fh->bcookie, 8); 1839 aimbs_put16(bs, fh->encrypt); 1840 aimbs_put16(bs, fh->compress); 1841 aimbs_put16(bs, fh->totfiles); 1842 aimbs_put16(bs, fh->filesleft); 1843 aimbs_put16(bs, fh->totparts); 1844 aimbs_put16(bs, fh->partsleft); 1845 aimbs_put32(bs, fh->totsize); 1846 aimbs_put32(bs, fh->size); 1847 aimbs_put32(bs, fh->modtime); 1848 aimbs_put32(bs, fh->checksum); 1849 aimbs_put32(bs, fh->rfrcsum); 1850 aimbs_put32(bs, fh->rfsize); 1851 aimbs_put32(bs, fh->cretime); 1852 aimbs_put32(bs, fh->rfcsum); 1853 aimbs_put32(bs, fh->nrecvd); 1854 aimbs_put32(bs, fh->recvcsum); 1855 aimbs_putraw(bs, fh->idstring, 32); 1856 aimbs_put8(bs, fh->flags); 1857 aimbs_put8(bs, fh->lnameoffset); 1858 aimbs_put8(bs, fh->lsizeoffset); 1859 aimbs_putraw(bs, fh->dummy, 69); 1860 aimbs_putraw(bs, fh->macfileinfo, 16); 1861 aimbs_put16(bs, fh->nencode); 1862 aimbs_put16(bs, fh->nlanguage); 1863 aimbs_putraw(bs, fh->name, 64); 1864 1865 /* XXX: Filenames longer than 64B */ 1866 return 0; 1867 } 1614 1868 1615 1869 /** … … 1625 1879 return NULL; 1626 1880 #if 0 1627 struct command_tx_struct *newpacket; 1628 struct aim_conn_t *newconn; 1629 struct aim_filetransfer_priv *priv; 1630 struct aim_msgcookie_t *cookie; 1631 int curbyte, i, listenfd; 1632 short port = 4443; 1633 struct hostent *hptr; 1634 struct utsname myname; 1635 char cap[16]; 1636 char d[4]; 1881 struct command_tx_struct *newpacket; 1882 struct aim_conn_t *newconn; 1883 struct aim_filetransfer_priv *priv; 1884 struct aim_msgcookie_t *cookie; 1885 int curbyte, i, listenfd; 1886 short port = 4443; 1887 struct hostent *hptr; 1888 struct utsname myname; 1889 char cap[16]; 1890 char d[4]; 1891 1892 /* Open our socket */ 1893 1894 if ( (listenfd = aim_listenestablish(port)) == -1) 1895 return NULL; 1896 1897 /* get our local IP */ 1898 1899 if (uname(&myname) < 0) 1900 return NULL; 1901 if ( (hptr = gethostbyname(myname.nodename)) == NULL) 1902 return NULL; 1903 memcpy(&d, hptr->h_addr_list[0], 4); 1904 1905 aim_putcap(cap, 16, AIM_CAPS_GETFILE); 1906 1907 /* create the OSCAR packet */ 1908 1909 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42))) 1910 return NULL; 1911 newpacket->lock = 1; 1912 1913 /* lock struct */ 1914 curbyte = 0; 1915 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid); 1916 1917 /* XXX: check the cookie before commiting to using it */ 1918 1919 /* Generate a random message cookie 1920 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */ 1921 for (i=0; i<7; i++) 1922 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10)); 1923 1924 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1925 1926 /* grab all the data for cookie caching. */ 1637 1927 1638 /* Open our socket */ 1639 1640 if ( (listenfd = aim_listenestablish(port)) == -1) 1641 return NULL; 1642 1643 /* get our local IP */ 1644 1645 if (uname(&myname) < 0) 1646 return NULL; 1647 if ( (hptr = gethostbyname(myname.nodename)) == NULL) 1648 return NULL; 1649 memcpy(&d, hptr->h_addr_list[0], 4); 1650 1651 aim_putcap(cap, 16, AIM_CAPS_GETFILE); 1652 1653 /* create the OSCAR packet */ 1654 1655 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42))) 1656 return NULL; 1657 newpacket->lock = 1; 1658 1659 /* lock struct */ 1660 curbyte = 0; 1661 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid); 1662 1663 /* XXX: check the cookie before commiting to using it */ 1664 1665 /* Generate a random message cookie 1666 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */ 1667 for (i=0; i<7; i++) 1668 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10)); 1669 1670 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1671 1672 /* grab all the data for cookie caching. */ 1928 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) 1929 return NULL; 1930 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8); 1931 cookie->type = AIM_COOKIETYPE_OFTGET; 1932 1933 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) 1934 return NULL; 1935 memcpy(priv->cookie, cookie, 8); 1936 memcpy(priv->sn, destsn, sizeof(priv->sn)); 1937 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt")); 1938 priv->state = 1; 1939 1940 cookie->data = priv; 1941 1942 aim_cachecookie(sess, cookie); 1943 1944 /* Channel ID */ 1945 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002); 1946 1947 /* Destination SN (prepended with byte length) */ 1948 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); 1949 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); 1950 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1951 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1952 1953 /* enTLV start */ 1954 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1955 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042); 1956 1957 /* Flag data / ICBM Parameters? */ 1958 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1959 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1960 1961 /* Cookie */ 1962 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8); 1963 1964 /* Capability String */ 1965 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10); 1966 1967 /* 000a/0002 : 0001 */ 1968 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); 1969 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1970 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); 1971 1972 /* 0003/0004: IP address */ 1973 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1974 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); 1975 for (i = 0; i < 4; i++) 1976 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); 1977 1978 /* already in network byte order */ 1673 1979 1674 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) 1675 return NULL; 1676 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8); 1677 cookie->type = AIM_COOKIETYPE_OFTGET; 1678 1679 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) 1680 return NULL; 1681 memcpy(priv->cookie, cookie, 8); 1682 memcpy(priv->sn, destsn, sizeof(priv->sn)); 1683 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt")); 1684 priv->state = 1; 1685 1686 cookie->data = priv; 1687 1688 aim_cachecookie(sess, cookie); 1689 1690 /* Channel ID */ 1691 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002); 1692 1693 /* Destination SN (prepended with byte length) */ 1694 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); 1695 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); 1696 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1697 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1698 1699 /* enTLV start */ 1700 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1701 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042); 1702 1703 /* Flag data / ICBM Parameters? */ 1704 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1705 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1706 1707 /* Cookie */ 1708 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8); 1709 1710 /* Capability String */ 1711 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10); 1712 1713 /* 000a/0002 : 0001 */ 1714 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); 1715 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1716 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); 1717 1718 /* 0003/0004: IP address */ 1719 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1720 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); 1721 for(i = 0; i < 4; i++) 1722 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); 1723 1724 /* already in network byte order */ 1725 1726 /* 0005/0002: Port */ 1727 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1728 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1729 curbyte += aimutil_put16(newpacket->data+curbyte, port); 1730 1731 /* 000f/0000: ?? */ 1732 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); 1733 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1734 1735 /* 2711/000c: ?? */ 1736 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); 1737 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c); 1738 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001); 1739 1740 for(i = 0; i < 0x000c - 4; i++) 1741 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1742 1743 newpacket->commandlen = curbyte; 1744 newpacket->lock = 0; 1745 aim_tx_enqueue(sess, newpacket); 1746 1747 /* allocate and set up our connection */ 1748 1749 i = fcntl(listenfd, F_GETFL, 0); 1750 fcntl(listenfd, F_SETFL, i | O_NONBLOCK); 1751 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL); 1752 1753 if (!newconn){ 1754 perror("aim_newconn"); 1755 return NULL; 1756 } 1757 1758 newconn->fd = listenfd; 1759 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 1760 newconn->priv = priv; 1761 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); 1762 1763 return newconn; 1980 /* 0005/0002: Port */ 1981 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1982 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1983 curbyte += aimutil_put16(newpacket->data+curbyte, port); 1984 1985 /* 000f/0000: ?? */ 1986 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); 1987 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1988 1989 /* 2711/000c: ?? */ 1990 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); 1991 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c); 1992 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001); 1993 1994 for (i = 0; i < 0x000c - 4; i++) 1995 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1996 1997 newpacket->commandlen = curbyte; 1998 newpacket->lock = 0; 1999 aim_tx_enqueue(sess, newpacket); 2000 2001 /* allocate and set up our connection */ 2002 2003 i = fcntl(listenfd, F_GETFL, 0); 2004 fcntl(listenfd, F_SETFL, i | O_NONBLOCK); 2005 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL); 2006 2007 if (!newconn){ 2008 perror("aim_newconn"); 2009 return NULL; 2010 } 2011 2012 newconn->fd = listenfd; 2013 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 2014 newconn->internal = priv; 2015 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); 2016 2017 return newconn; 1764 2018 #endif 1765 2019 } … … 1775 2029 * returns -1 on error, 0 on successful enqueuing 1776 2030 */ 2031 #if 0 1777 2032 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size) 1778 2033 { 1779 return -EINVAL; 1780 #if 0 1781 struct command_tx_struct *newoft; 1782 struct aim_filetransfer_priv *ft; 1783 if (!sess || !conn || !conn->priv || !name) 1784 return -1; 1785 1786 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) { 1787 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 1788 return -1; 1789 } 1790 1791 newoft->lock = 1; 1792 1793 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1794 newoft->hdr.oft.hdr2len = 0x100 - 8; 1795 1796 ft = (struct aim_filetransfer_priv *)conn->priv; 1797 ft->fh.filesleft = 1; 1798 ft->fh.totfiles = 1; 1799 ft->fh.totparts = 1; 1800 ft->fh.partsleft = 1; 1801 ft->fh.totsize = size; 1802 ft->fh.size = size; 1803 ft->fh.checksum = 0; 1804 memcpy(ft->fh.name, name, strlen(name)); 1805 memset(ft->fh.name+strlen(name), 0, 1); 1806 1807 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 1808 newoft->lock = 0; 1809 aim_frame_destroy(newoft); 1810 return -1; 1811 } 1812 1813 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { 1814 newoft->lock = 0; 1815 aim_frame_destroy(newoft); 1816 return -1; 1817 } 1818 1819 newoft->lock = 0; 1820 1821 aim_tx_enqueue(sess, newoft); 1822 return 0; 2034 aim_frame_t *newoft; 2035 struct aim_filetransfer_priv *ft; 2036 if (!sess || !conn || !conn->priv || !name) 2037 return -1; 2038 2039 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) { 2040 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2041 return -1; 2042 } 2043 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2044 newoft->hdr.oft.hdr2len = 0x100 - 8; 2045 2046 ft = (struct aim_filetransfer_priv *)conn->priv; 2047 ft->fh.filesleft = 1; 2048 ft->fh.totfiles = 1; 2049 ft->fh.totparts = 1; 2050 ft->fh.partsleft = 1; 2051 ft->fh.totsize = size; 2052 ft->fh.size = size; 2053 ft->fh.checksum = 0; 2054 memcpy(ft->fh.name, name, strlen(name)); 2055 memset(ft->fh.name+strlen(name), 0, 1); 2056 2057 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2058 aim_frame_destroy(newoft); 2059 return -1; 2060 } 2061 2062 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { 2063 aim_frame_destroy(newoft); 2064 return -1; 2065 } 2066 2067 aim_tx_enqueue(sess, newoft); 2068 return 0; 2069 } 1823 2070 #endif 2071 2072 /* Identify a file that we are about to send by transmitting the 2073 * appropriate header. 2074 */ 2075 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize) 2076 { 2077 aim_frame_t *newoft; 2078 aim_msgcookie_t *cook; 2079 struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal; 2080 struct aim_fileheader_t *fh; 2081 2082 if (!sess || !conn || !filename) 2083 return -1; 2084 2085 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 2086 return -1; 2087 2088 #ifdef DUMB_OFT_CHECKSUM 2089 /* Yes, we are supposed to checksum the whole file before sending, and 2090 * yes, it's dumb. This is the only way to get some clients (such as 2091 * Mac AIM v4.5.163) to successfully complete the transfer. With 2092 * the WinAIM clients, we seem to be able to get away with just 2093 * setting the checksum to zero. 2094 * -- wtm 2095 */ 2096 { 2097 int fd = open(filename, O_RDONLY); 2098 if (fd >= 0) { 2099 int bytes; 2100 char buf[1024]; 2101 fh->checksum = 0xffff0000; 2102 while ((bytes = aim_recv(fd, buf, 1024)) > 0) { 2103 fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum); 2104 } 2105 } 2106 close(fd); 2107 } 2108 #else 2109 fh->checksum = 0x00000000; 2110 #endif 2111 fh->encrypt = 0x0000; 2112 fh->compress = 0x0000; 2113 fh->totfiles = numfiles; 2114 fh->filesleft = numfiles - filesdone; 2115 fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */ 2116 fh->partsleft = 0x0001; 2117 fh->totsize = totsize; 2118 fh->size = size; 2119 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 2120 /* fh->checksum set above */ 2121 fh->rfcsum = 0x00000000; 2122 fh->rfsize = 0x00000000; 2123 fh->cretime = 0x00000000; 2124 fh->rfcsum = 0x00000000; 2125 fh->nrecvd = 0x00000000; /* always zero initially */ 2126 fh->recvcsum= 0x00000000; /* ditto */ 2127 2128 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 2129 fh->flags = 0x02; 2130 fh->lnameoffset = 0x1a; 2131 fh->lsizeoffset = 0x10; 2132 memset(fh->dummy, 0, sizeof(fh->dummy)); 2133 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 2134 2135 /* apparently 0 is ASCII, 2 is UCS-2 */ 2136 /* it is likely that 3 is ISO 8859-1 */ 2137 fh->nencode = 0x0000; 2138 fh->nlanguage = 0x0000; 2139 2140 /* Convert the directory separator to ^A for portability. */ 2141 strncpy(fh->name, filename, sizeof(fh->name)); 2142 oft_dirconvert(fh->name); 2143 2144 /* XXX we should normally send a null cookie here, and make 2145 * the receiver fill it in for authentication -- wtm 2146 */ 2147 memcpy(fh->bcookie, ft->cookie, 8); 2148 2149 if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) { 2150 return -1; 2151 } 2152 2153 /* Update both headers to be safe. */ 2154 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 2155 memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t)); 2156 2157 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) { 2158 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2159 free(fh); 2160 return -1; 2161 } 2162 2163 if (aim_oft_buildheader(&newoft->data, fh) == -1) { 2164 aim_frame_destroy(newoft); 2165 free(fh); 2166 return -1; 2167 } 2168 2169 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 2170 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 2171 2172 aim_tx_enqueue(sess, newoft); 2173 free(fh); 2174 return 0; 1824 2175 } 1825 2176 … … 1837 2188 return -EINVAL; 1838 2189 #if 0 1839 struct command_tx_struct *newoft;1840 struct aim_filetransfer_priv *ft;1841 1842 if (!sess || !conn || !conn->priv)1843 return -1;1844 1845 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {1846 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");1847 return -1;1848 }1849 1850 newoft->lock = 1;1851 1852 memcpy(newoft->hdr.oft.magic, "OFT2", 4);1853 newoft->hdr.oft.hdr2len = 0x100-8;1854 1855 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {1856 newoft->lock = 0;1857 aim_frame_destroy(newoft);1858 return -1;1859 }1860 1861 ft = (struct aim_filetransfer_priv *)conn->priv;1862 1863 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {1864 newoft->lock = 0;1865 aim_frame_destroy(newoft);1866 return -1;1867 }1868 1869 newoft->lock = 0;1870 aim_tx_enqueue(sess, newoft);1871 return 0;2190 struct command_tx_struct *newoft; 2191 struct aim_filetransfer_priv *ft; 2192 2193 if (!sess || !conn || !conn->priv) 2194 return -1; 2195 2196 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { 2197 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2198 return -1; 2199 } 2200 2201 newoft->lock = 1; 2202 2203 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2204 newoft->hdr.oft.hdr2len = 0x100-8; 2205 2206 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2207 newoft->lock = 0; 2208 aim_frame_destroy(newoft); 2209 return -1; 2210 } 2211 2212 ft = (struct aim_filetransfer_priv *)conn->priv; 2213 2214 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 2215 newoft->lock = 0; 2216 aim_frame_destroy(newoft); 2217 return -1; 2218 } 2219 2220 newoft->lock = 0; 2221 aim_tx_enqueue(sess, newoft); 2222 return 0; 1872 2223 #endif 1873 2224 } 1874 2225 1875 2226 /** 1876 * aim_oft_ getfile_end - end a getfile.2227 * aim_oft_end - end a getfile/sendfile. 1877 2228 * @sess: your session 1878 2229 * @conn: the getfile connection … … 1881 2232 * receiving/requesting end. 1882 2233 */ 1883 faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn) 1884 { 1885 return -EINVAL; 1886 #if 0 1887 struct command_tx_struct *newoft; 1888 struct aim_filetransfer_priv *ft; 1889 1890 if (!sess || !conn || !conn->priv) 1891 return -1; 1892 1893 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0204, 0))) { 1894 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 1895 return -1; 1896 } 1897 1898 newoft->lock = 1; 1899 1900 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1901 newoft->hdr.oft.hdr2len = 0x100 - 8; 1902 1903 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 1904 newoft->lock = 0; 1905 aim_frame_destroy(newoft); 1906 return -1; 1907 } 1908 1909 ft = (struct aim_filetransfer_priv *)conn->priv; 1910 ft->state = 4; /* no longer wanting data */ 1911 ft->fh.nrecvd = ft->fh.size; 1912 ft->fh.recvcsum = ft->fh.checksum; 1913 ft->fh.flags = 0x21; 1914 1915 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 1916 newoft->lock = 0; 1917 aim_frame_destroy(newoft); 1918 return -1; 1919 } 1920 1921 newoft->lock = 0; 1922 aim_tx_enqueue(sess, newoft); 1923 1924 return 0; 1925 #endif /* 0 */ 1926 } 1927 2234 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn) 2235 { 2236 aim_frame_t *newoft; 2237 struct aim_filetransfer_priv *ft; 2238 2239 if (!sess || !conn || !conn->internal) 2240 return -1; 2241 2242 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) { 2243 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2244 return -1; 2245 } 2246 2247 ft = (struct aim_filetransfer_priv *)conn->internal; 2248 ft->state = 4; /* no longer wanting data */ 2249 ft->fh.flags = 0x21; 2250 2251 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 2252 aim_frame_destroy(newoft); 2253 return -1; 2254 } 2255 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 2256 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 2257 2258 aim_tx_enqueue(sess, newoft); 2259 2260 return 0; 2261 } 2262 2263 /* 2264 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability. 2265 */ 2266 static void oft_dirconvert(char *name) { 2267 char *c = name; 2268 while ((c = strchr(c, G_DIR_SEPARATOR))) 2269 *c = 0x01; 2270 } -
libfaim/icq.c
r5e53c4a r862371b 1 1 /* 2 * Encapsulated ICQ.2 * Family 0x0015 - Encapsulated ICQ. 3 3 * 4 4 */ … … 263 263 return 0; 264 264 } 265 266 -
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; -
libfaim/info.c
r5e53c4a r862371b 1 1 /* 2 * aim_info.c2 * Family 0x0002 - Information. 3 3 * 4 4 * The functions here are responsible for requesting and parsing information- … … 15 15 }; 16 16 17 /* 18 * Subtype 0x0002 19 * 20 * Request Location services rights. 21 * 22 */ 23 faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn) 24 { 25 return aim_genericreq_n(sess, conn, 0x0002, 0x0002); 26 } 27 28 /* 29 * Subtype 0x0004 30 * 31 * Gives BOS your profile. 32 * 33 */ 34 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps) 35 { 36 static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; 37 aim_frame_t *fr; 38 aim_tlvlist_t *tl = NULL; 39 aim_snacid_t snacid; 40 41 /* Build to packet first to get real length */ 42 if (profile) { 43 aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding); 44 aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile); 45 } 46 47 /* 48 * So here's how this works: 49 * - You are away when you have a non-zero-length type 4 TLV stored. 50 * - You become unaway when you clear the TLV with a zero-length 51 * type 4 TLV. 52 * - If you do not send the type 4 TLV, your status does not change 53 * (that is, if you were away, you'll remain away). 54 */ 55 if (awaymsg) { 56 if (strlen(awaymsg)) { 57 aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding); 58 aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg); 59 } else 60 aim_addtlvtochain_noval(&tl, 0x0004); 61 } 62 63 aim_addtlvtochain_caps(&tl, 0x0005, caps); 64 65 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl)))) 66 return -ENOMEM; 67 68 snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0); 69 70 aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid); 71 aim_writetlvchain(&fr->data, &tl); 72 aim_freetlvchain(&tl); 73 74 aim_tx_enqueue(sess, fr); 75 76 return 0; 77 } 78 79 /* 80 * Subtype 0x0005 - Request info of another AIM user. 81 * 82 */ 17 83 faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype) 18 84 { … … 200 266 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 201 267 268 /* from ICQ2002a 269 {AIM_CAPS_ICQUNKNOWN2, 270 {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1, 271 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, */ 272 202 273 {AIM_CAPS_ICQRTF, 203 274 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 204 275 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}}, 205 276 277 /* supposed to be ICQRTF? 278 {AIM_CAPS_TRILLUNKNOWN, 279 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 280 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}}, */ 281 206 282 {AIM_CAPS_ICQUNKNOWN, 207 283 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, … … 217 293 218 294 {AIM_CAPS_APINFO, 219 {0xAA, 0x4A, 0x32, 0xB5, 220 0xF8, 0x84, 221 0x48, 0xc6, 222 0xA3, 0xD7, 223 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}}, 295 {0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6, 296 0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}}, 224 297 225 298 {AIM_CAPS_LAST} … … 376 449 } else if (type == 0x0002) { 377 450 /* 378 * Type = 0x0002: Account creation time. 451 * Type = 0x0002: Account creation time. 379 452 * 380 453 * The time/date that the user originally registered for … … 424 497 * This is sometimes sent instead of type 2 ("account 425 498 * creation time"), particularly in the self-info. 499 * And particularly for ICQ? 426 500 */ 427 501 outinfo->membersince = aimbs_get32(bs); … … 557 631 aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); 558 632 633 /* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */ 559 634 #if ICQ_OSCAR_SUPPORT 560 635 if (atoi(info->sn) != 0) { … … 568 643 if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) 569 644 aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities); 570 645 571 646 if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) 572 647 aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); … … 579 654 } 580 655 581 faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info) 582 { 583 aim_frame_t *fr; 584 aim_snacid_t snacid; 585 586 if (!sess || !conn || !info) 587 return -EINVAL; 588 589 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) 590 return -ENOMEM; 591 592 snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0); 593 594 aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid); 595 aim_putuserinfo(&fr->data, info); 596 597 aim_tx_enqueue(sess, fr); 598 599 return 0; 600 } 601 602 faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn) 603 { 604 aim_frame_t *fr; 605 aim_snacid_t snacid; 606 607 if (!sess || !conn || !sn) 608 return -EINVAL; 609 610 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) 611 return -ENOMEM; 612 613 snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0); 614 615 aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid); 616 aimbs_put8(&fr->data, strlen(sn)); 617 aimbs_putraw(&fr->data, sn, strlen(sn)); 618 619 aim_tx_enqueue(sess, fr); 620 621 return 0; 622 } 623 624 /* 625 * Huh? What is this? 656 /* 657 * Subtype 0x000b - Huh? What is this? 626 658 */ 627 659 faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn) … … 648 680 649 681 /* 682 * Subtype 0x0003 683 * 650 684 * Normally contains: 651 685 * t(0001) - short containing max profile length (value = 1024) 652 686 * t(0002) - short - unknown (value = 16) [max MIME type length?] 653 687 * t(0003) - short - unknown (value = 10) 688 * t(0004) - short - unknown (value = 2048) [ICQ only?] 654 689 */ 655 690 static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) … … 673 708 } 674 709 710 /* Subtype 0x0006 */ 675 711 static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 676 712 { … … 744 780 } 745 781 782 /* 783 * Subtype 0x0009 - Set directory profile data. 784 * 785 * This is not the same as aim_bos_setprofile! 786 * privacy: 1 to allow searching, 0 to disallow. 787 * 788 */ 789 faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy) 790 { 791 aim_frame_t *fr; 792 aim_snacid_t snacid; 793 aim_tlvlist_t *tl = NULL; 794 795 aim_addtlvtochain16(&tl, 0x000a, privacy); 796 797 if (first) 798 aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first); 799 if (last) 800 aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last); 801 if (middle) 802 aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle); 803 if (maiden) 804 aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden); 805 806 if (state) 807 aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state); 808 if (city) 809 aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city); 810 811 if (nickname) 812 aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname); 813 if (zip) 814 aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip); 815 816 if (street) 817 aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street); 818 819 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) 820 return -ENOMEM; 821 822 snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0); 823 824 aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid); 825 aim_writetlvchain(&fr->data, &tl); 826 aim_freetlvchain(&tl); 827 828 aim_tx_enqueue(sess, fr); 829 830 return 0; 831 } 832 833 /* 834 * Subtype 0x000f 835 * 836 * XXX pass these in better 837 * 838 */ 839 faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy) 840 { 841 aim_frame_t *fr; 842 aim_snacid_t snacid; 843 aim_tlvlist_t *tl = NULL; 844 845 /* ?? privacy ?? */ 846 aim_addtlvtochain16(&tl, 0x000a, privacy); 847 848 if (interest1) 849 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1); 850 if (interest2) 851 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2); 852 if (interest3) 853 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3); 854 if (interest4) 855 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4); 856 if (interest5) 857 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5); 858 859 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) 860 return -ENOMEM; 861 862 snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0); 863 864 aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0); 865 aim_writetlvchain(&fr->data, &tl); 866 aim_freetlvchain(&tl); 867 868 aim_tx_enqueue(sess, fr); 869 870 return 0; 871 } 872 746 873 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 747 874 { -
libfaim/invite.c
r5e53c4a r862371b 1 1 /* 2 * This isn't really ever used by anyone anymore.2 * Family 0x0006 - This isn't really ever used by anyone anymore. 3 3 * 4 4 * Once upon a time, there used to be a menu item in AIM clients that … … 33 33 return 0; 34 34 } 35 36 -
libfaim/meta.c
r5e53c4a r862371b 7 7 #define FAIM_INTERNAL 8 8 #include <aim.h> 9 10 #ifdef _WIN32 11 #include "win32dep.h" 12 #endif 9 13 10 14 faim_export char *aim_getbuilddate(void) … … 33 37 faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...) 34 38 { 39 return; /* kretch */ 40 35 41 if (!sess) { 36 42 fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); -
libfaim/misc.c
r5e53c4a r862371b 1 2 1 /* 3 * aim_misc.c2 * misc.c 4 3 * 5 * TODO: Seperate a lot of this into an aim_bos.c. 6 * 7 * Other things... 8 * 9 * - Idle setting 10 * 4 * Random stuff. Basically just a few functions for sending 5 * simple SNACs, and then the generic error handler. 11 6 * 12 7 */ … … 14 9 #define FAIM_INTERNAL 15 10 #include <aim.h> 16 17 /*18 * aim_bos_setbuddylist(buddylist)19 *20 * This just builds the "set buddy list" command then queues it.21 *22 * buddy_list = "Screen Name One&ScreenNameTwo&";23 *24 * TODO: Clean this up.25 *26 * XXX: I can't stress the TODO enough.27 *28 */29 faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list)30 {31 aim_frame_t *fr;32 aim_snacid_t snacid;33 int len = 0;34 char *localcpy = NULL;35 char *tmpptr = NULL;36 37 if (!buddy_list || !(localcpy = strdup(buddy_list)))38 return -EINVAL;39 40 for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {41 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));42 len += 1 + strlen(tmpptr);43 tmpptr = strtok(NULL, "&");44 }45 46 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len)))47 return -ENOMEM;48 49 snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0);50 aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);51 52 strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);53 54 for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {55 56 faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));57 58 aimbs_put8(&fr->data, strlen(tmpptr));59 aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr));60 tmpptr = strtok(NULL, "&");61 }62 63 aim_tx_enqueue(sess, fr);64 65 free(localcpy);66 67 return 0;68 }69 70 /*71 * aim_bos_setprofile(profile)72 *73 * Gives BOS your profile.74 *75 */76 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps)77 {78 static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""};79 aim_frame_t *fr;80 aim_tlvlist_t *tl = NULL;81 aim_snacid_t snacid;82 83 /* Build to packet first to get real length */84 if (profile) {85 aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding);86 aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile);87 }88 89 /*90 * So here's how this works:91 * - You are away when you have a non-zero-length type 4 TLV stored.92 * - You become unaway when you clear the TLV with a zero-length93 * type 4 TLV.94 * - If you do not send the type 4 TLV, your status does not change95 * (that is, if you were away, you'll remain away).96 */97 if (awaymsg) {98 if (strlen(awaymsg)) {99 aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding);100 aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg);101 } else102 aim_addtlvtochain_noval(&tl, 0x0004);103 }104 105 aim_addtlvtochain_caps(&tl, 0x0005, caps);106 107 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl))))108 return -ENOMEM;109 110 snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);111 112 aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);113 aim_writetlvchain(&fr->data, &tl);114 aim_freetlvchain(&tl);115 116 aim_tx_enqueue(sess, fr);117 118 return 0;119 }120 121 /*122 * aim_bos_reqbuddyrights()123 *124 * Request Buddy List rights.125 *126 */127 faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn)128 {129 return aim_genericreq_n(sess, conn, 0x0003, 0x0002);130 }131 132 /*133 * Send a warning to destsn.134 *135 * Flags:136 * AIM_WARN_ANON Send as an anonymous (doesn't count as much)137 *138 * returns -1 on error (couldn't alloc packet), 0 on success.139 *140 */141 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags)142 {143 aim_frame_t *fr;144 aim_snacid_t snacid;145 fu16_t outflags = 0x0000;146 147 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13)))148 return -ENOMEM;149 150 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1);151 152 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);153 154 if (flags & AIM_WARN_ANON)155 outflags |= 0x0001;156 157 aimbs_put16(&fr->data, outflags);158 aimbs_put8(&fr->data, strlen(destsn));159 aimbs_putraw(&fr->data, destsn, strlen(destsn));160 161 aim_tx_enqueue(sess, fr);162 163 return 0;164 }165 11 166 12 /* … … 250 96 251 97 /* 252 * aim_bos_reqlocaterights()253 *254 * Request Location services rights.255 *256 */257 faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn)258 {259 return aim_genericreq_n(sess, conn, 0x0002, 0x0002);260 }261 262 /*263 * Set directory profile data (not the same as aim_bos_setprofile!)264 *265 * privacy: 1 to allow searching, 0 to disallow.266 */267 faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy)268 {269 aim_frame_t *fr;270 aim_snacid_t snacid;271 aim_tlvlist_t *tl = NULL;272 273 274 aim_addtlvtochain16(&tl, 0x000a, privacy);275 276 if (first)277 aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first);278 if (last)279 aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last);280 if (middle)281 aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle);282 if (maiden)283 aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden);284 285 if (state)286 aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state);287 if (city)288 aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city);289 290 if (nickname)291 aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname);292 if (zip)293 aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip);294 295 if (street)296 aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street);297 298 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))299 return -ENOMEM;300 301 snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0);302 303 aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid);304 aim_writetlvchain(&fr->data, &tl);305 aim_freetlvchain(&tl);306 307 aim_tx_enqueue(sess, fr);308 309 return 0;310 }311 312 /* XXX pass these in better */313 faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy)314 {315 aim_frame_t *fr;316 aim_snacid_t snacid;317 aim_tlvlist_t *tl = NULL;318 319 /* ?? privacy ?? */320 aim_addtlvtochain16(&tl, 0x000a, privacy);321 322 if (interest1)323 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1);324 if (interest2)325 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2);326 if (interest3)327 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3);328 if (interest4)329 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4);330 if (interest5)331 aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5);332 333 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))334 return -ENOMEM;335 336 snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0);337 338 aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0);339 aim_writetlvchain(&fr->data, &tl);340 aim_freetlvchain(&tl);341 342 aim_tx_enqueue(sess, fr);343 344 return 0;345 }346 347 /*348 98 * Should be generic enough to handle the errors for all groups. 349 99 * … … 397 147 return 0; 398 148 } 399 400 -
libfaim/msgcookie.c
r5e53c4a r862371b 193 193 } 194 194 } 195 196 -
libfaim/popups.c
r5e53c4a r862371b 1 2 1 /* 2 * Family 0x0008 - Popups. 3 * 3 4 * Popups are just what it sounds like. They're a way for the server to 4 5 * open up an informative box on the client's screen. … … 62 63 return 0; 63 64 } 64 65 -
libfaim/rxhandlers.c
r5e53c4a r862371b 1 1 /* 2 * aim_rxhandlers.c2 * rxhandlers.c 3 3 * 4 4 * This file contains most all of the incoming packet handlers, along … … 69 69 (aim_module_t *)sess->modlistv = mod; 70 70 71 /* faimdprintf(sess, 1, "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion); */71 faimdprintf(sess, 1, "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion); 72 72 73 73 return 0; … … 547 547 cur->handled = 1; /* get rid of it */ 548 548 } else { 549 /* XXX: implement this */ 550 faimdprintf(sess, 0, "faim: OFT frame!\n"); 551 cur->handled = 1; /* get rid of it */ 549 aim_rxdispatch_rendezvous(sess, cur); 550 cur->handled = 1; 552 551 } 553 552 continue; … … 614 613 return 1; 615 614 } 616 617 618 -
libfaim/rxqueue.c
r5e53c4a r862371b 1 1 /* 2 * aim_rxqueue.c2 * rxqueue.c 3 3 * 4 4 * This file contains the management routines for the receive … … 64 64 } 65 65 66 faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len) 67 { 68 69 if (!bs) 70 return -1; 71 72 bs->data = data; 73 bs->len = len; 74 bs->offset = 0; 75 76 return 0; 77 } 78 79 faim_internal int aim_bstream_empty(aim_bstream_t *bs) 80 { 81 return bs->len - bs->offset; 82 } 83 84 faim_internal int aim_bstream_curpos(aim_bstream_t *bs) 85 { 86 return bs->offset; 87 } 88 89 faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off) 90 { 91 92 if (off > bs->len) 93 return -1; 94 95 bs->offset = off; 96 97 return off; 98 } 99 100 faim_internal void aim_bstream_rewind(aim_bstream_t *bs) 101 { 102 103 aim_bstream_setpos(bs, 0); 66 /** 67 * aim_frame_destroy - free aim_frame_t 68 * @frame: the frame to free 69 * 70 * returns -1 on error; 0 on success. 71 * 72 */ 73 faim_internal void aim_frame_destroy(aim_frame_t *frame) 74 { 75 76 free(frame->data.data); /* XXX aim_bstream_free */ 77 free(frame); 104 78 105 79 return; 106 80 } 107 81 108 faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n) 109 { 110 111 if (aim_bstream_empty(bs) < n) 112 return 0; /* XXX throw an exception */ 113 114 bs->offset += n; 115 116 return n; 117 } 118 119 faim_internal fu8_t aimbs_get8(aim_bstream_t *bs) 120 { 121 122 if (aim_bstream_empty(bs) < 1) 123 return 0; /* XXX throw an exception */ 124 125 bs->offset++; 126 127 return aimutil_get8(bs->data + bs->offset - 1); 128 } 129 130 faim_internal fu16_t aimbs_get16(aim_bstream_t *bs) 131 { 132 133 if (aim_bstream_empty(bs) < 2) 134 return 0; /* XXX throw an exception */ 135 136 bs->offset += 2; 137 138 return aimutil_get16(bs->data + bs->offset - 2); 139 } 140 141 faim_internal fu32_t aimbs_get32(aim_bstream_t *bs) 142 { 143 144 if (aim_bstream_empty(bs) < 4) 145 return 0; /* XXX throw an exception */ 146 147 bs->offset += 4; 148 149 return aimutil_get32(bs->data + bs->offset - 4); 150 } 151 152 faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs) 153 { 154 155 if (aim_bstream_empty(bs) < 1) 156 return 0; /* XXX throw an exception */ 157 158 bs->offset++; 159 160 return aimutil_getle8(bs->data + bs->offset - 1); 161 } 162 163 faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs) 164 { 165 166 if (aim_bstream_empty(bs) < 2) 167 return 0; /* XXX throw an exception */ 168 169 bs->offset += 2; 170 171 return aimutil_getle16(bs->data + bs->offset - 2); 172 } 173 174 faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs) 175 { 176 177 if (aim_bstream_empty(bs) < 4) 178 return 0; /* XXX throw an exception */ 179 180 bs->offset += 4; 181 182 return aimutil_getle32(bs->data + bs->offset - 4); 183 } 184 185 faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v) 186 { 187 188 if (aim_bstream_empty(bs) < 1) 189 return 0; /* XXX throw an exception */ 190 191 bs->offset += aimutil_put8(bs->data + bs->offset, v); 192 193 return 1; 194 } 195 196 faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v) 197 { 198 199 if (aim_bstream_empty(bs) < 2) 200 return 0; /* XXX throw an exception */ 201 202 bs->offset += aimutil_put16(bs->data + bs->offset, v); 203 204 return 2; 205 } 206 207 faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v) 208 { 209 210 if (aim_bstream_empty(bs) < 4) 211 return 0; /* XXX throw an exception */ 212 213 bs->offset += aimutil_put32(bs->data + bs->offset, v); 214 215 return 1; 216 } 217 218 faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v) 219 { 220 221 if (aim_bstream_empty(bs) < 1) 222 return 0; /* XXX throw an exception */ 223 224 bs->offset += aimutil_putle8(bs->data + bs->offset, v); 225 226 return 1; 227 } 228 229 faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v) 230 { 231 232 if (aim_bstream_empty(bs) < 2) 233 return 0; /* XXX throw an exception */ 234 235 bs->offset += aimutil_putle16(bs->data + bs->offset, v); 236 237 return 2; 238 } 239 240 faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v) 241 { 242 243 if (aim_bstream_empty(bs) < 4) 244 return 0; /* XXX throw an exception */ 245 246 bs->offset += aimutil_putle32(bs->data + bs->offset, v); 247 248 return 1; 249 } 250 251 faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len) 252 { 253 254 if (aim_bstream_empty(bs) < len) 255 return 0; 256 257 memcpy(buf, bs->data + bs->offset, len); 258 bs->offset += len; 259 260 return len; 261 } 262 263 faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len) 264 { 265 fu8_t *ob; 266 267 if (!(ob = malloc(len))) 268 return NULL; 269 270 if (aimbs_getrawbuf(bs, ob, len) < len) { 271 free(ob); 272 return NULL; 273 } 274 275 return ob; 276 } 277 278 faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len) 279 { 280 char *ob; 281 282 if (!(ob = malloc(len+1))) 283 return NULL; 284 285 if (aimbs_getrawbuf(bs, ob, len) < len) { 286 free(ob); 287 return NULL; 288 } 289 290 ob[len] = '\0'; 291 292 return ob; 293 } 294 295 faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len) 296 { 297 298 if (aim_bstream_empty(bs) < len) 299 return 0; /* XXX throw an exception */ 300 301 memcpy(bs->data + bs->offset, v, len); 302 bs->offset += len; 303 304 return len; 305 } 306 307 faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len) 308 { 309 310 if (aim_bstream_empty(srcbs) < len) 311 return 0; /* XXX throw exception (underrun) */ 312 313 if (aim_bstream_empty(bs) < len) 314 return 0; /* XXX throw exception (overflow) */ 315 316 memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len); 317 bs->offset += len; 318 srcbs->offset += len; 319 320 return len; 321 } 322 323 /** 324 * aim_frame_destroy - free aim_frame_t 325 * @frame: the frame to free 326 * 327 * returns -1 on error; 0 on success. 328 * 329 */ 330 faim_internal void aim_frame_destroy(aim_frame_t *frame) 331 { 332 333 free(frame->data.data); /* XXX aim_bstream_free */ 334 335 if (frame->hdrtype == AIM_FRAMETYPE_OFT) 336 free(frame->hdr.oft.hdr2); 337 free(frame); 338 339 return; 340 } 341 342 343 /* 344 * Grab a single command sequence off the socket, and enqueue 345 * it in the incoming event queue in a seperate struct. 346 */ 347 faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) 82 /* 83 * Read a FLAP header from conn into fr, and return the number of bytes in the payload. 84 */ 85 static faim_shortfunc int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) 348 86 { 349 87 fu8_t flaphdr_raw[6]; 350 88 aim_bstream_t flaphdr; 351 aim_frame_t *newrx;352 89 fu16_t payloadlen; 353 90 354 if (!sess || !conn)355 return 0;356 357 if (conn->fd == -1)358 return -1; /* its a aim_conn_close()'d connection */359 360 if (conn->fd < 3) /* can happen when people abuse the interface */361 return 0;362 363 if (conn->status & AIM_CONN_STATUS_INPROGRESS)364 return aim_conn_completeconnect(sess, conn);365 366 /*367 * Rendezvous (client-client) connections do not speak368 * FLAP, so this function will break on them.369 */370 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)371 return aim_get_command_rendezvous(sess, conn);372 else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {373 faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);374 return 0;375 }376 377 91 aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); 378 92 379 93 /* 380 94 * Read FLAP header. Six bytes: 381 *382 95 * 0 char -- Always 0x2a 383 96 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. 384 * 2 short -- Sequence number 97 * 2 short -- Sequence number 385 98 * 4 short -- Number of data bytes that follow. 386 99 */ … … 406 119 } 407 120 408 /* allocate a new struct */409 if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t))))410 return -1;411 memset(newrx, 0, sizeof(aim_frame_t));412 413 121 /* we're doing FLAP if we're here */ 414 newrx->hdrtype = AIM_FRAMETYPE_FLAP; 415 416 newrx->hdr.flap.type = aimbs_get8(&flaphdr); 417 newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr); 418 payloadlen = aimbs_get16(&flaphdr); 122 fr->hdrtype = AIM_FRAMETYPE_FLAP; 123 124 fr->hdr.flap.type = aimbs_get8(&flaphdr); 125 fr->hdr.flap.seqnum = aimbs_get16(&flaphdr); 126 payloadlen = aimbs_get16(&flaphdr); /* length of payload */ 127 128 return payloadlen; 129 } 130 131 /* 132 * Read a rendezvous header from conn into fr, and return the number of bytes in the payload. 133 */ 134 static int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) 135 { 136 fu8_t rendhdr_raw[8]; 137 aim_bstream_t rendhdr; 138 139 aim_bstream_init(&rendhdr, rendhdr_raw, sizeof(rendhdr_raw)); 140 141 if (aim_bstream_recv(&rendhdr, conn->fd, 8) < 8) { 142 aim_conn_close(conn); 143 return -1; 144 } 145 146 aim_bstream_rewind(&rendhdr); 147 148 fr->hdrtype = AIM_FRAMETYPE_OFT; /* a misnomer--rendezvous */ 149 150 aimbs_getrawbuf(&rendhdr, fr->hdr.rend.magic, 4); 151 fr->hdr.rend.hdrlen = aimbs_get16(&rendhdr) - 8; 152 fr->hdr.rend.type = aimbs_get16(&rendhdr); 153 154 return fr->hdr.rend.hdrlen; 155 } 156 157 /* 158 * Grab a single command sequence off the socket, and enqueue it in the incoming event queue 159 * in a separate struct. 160 */ 161 faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) 162 { 163 aim_frame_t *newrx; 164 fu16_t payloadlen; 165 166 if (!sess || !conn) 167 return -1; 168 169 if (conn->fd == -1) 170 return -1; /* it's an aim_conn_close()'d connection */ 171 172 if (conn->fd < 3) /* can happen when people abuse the interface */ 173 return -1; 174 175 if (conn->status & AIM_CONN_STATUS_INPROGRESS) 176 return aim_conn_completeconnect(sess, conn); 177 178 if (!(newrx = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1))) 179 return -1; 180 181 /* 182 * Rendezvous (client to client) connections do not speak FLAP, so this 183 * function will break on them. 184 */ 185 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 186 payloadlen = aim_get_command_rendezvous(sess, conn, newrx); 187 else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 188 faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd); 189 free(newrx); 190 return -1; 191 } else 192 payloadlen = aim_get_command_flap(sess, conn, newrx); 419 193 420 194 newrx->nofree = 0; /* free by default */ … … 508 282 return; 509 283 } 510 -
libfaim/search.c
r5e53c4a r862371b 1 2 1 /* 3 * aim_search.c2 * Family 0x000a - User Search. 4 3 * 5 4 * TODO: Add aim_usersearch_name() … … 10 9 #include <aim.h> 11 10 12 faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address) 13 { 14 aim_frame_t *fr; 15 aim_snacid_t snacid; 16 17 if (!sess || !conn || !address) 18 return -EINVAL; 19 20 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address)))) 21 return -ENOMEM; 22 23 snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1); 24 aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid); 25 26 aimbs_putraw(&fr->data, address, strlen(address)); 27 28 aim_tx_enqueue(sess, fr); 29 30 return 0; 31 } 32 33 /* XXX can this be integrated with the rest of the error handling? */ 11 /* 12 * Subtype 0x0001 13 * 14 * XXX can this be integrated with the rest of the error handling? 15 */ 34 16 static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 35 17 { … … 55 37 } 56 38 39 /* 40 * Subtype 0x0002 41 * 42 */ 43 faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address) 44 { 45 aim_frame_t *fr; 46 aim_snacid_t snacid; 47 48 if (!sess || !conn || !address) 49 return -EINVAL; 50 51 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address)))) 52 return -ENOMEM; 53 54 snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1); 55 aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid); 56 57 aimbs_putraw(&fr->data, address, strlen(address)); 58 59 aim_tx_enqueue(sess, fr); 60 61 return 0; 62 } 63 64 /* 65 * Subtype 0x0003 66 * 67 */ 57 68 static int reply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 58 69 { … … 119 130 return 0; 120 131 } 121 122 -
libfaim/service.c
r5e53c4a r862371b 1 1 /* 2 * Group 1.This is a very special group. All connections support2 * Family 0x0001 - This is a very special group. All connections support 3 3 * this group, as it does some particularly good things (like rate limiting). 4 4 */ … … 10 10 #include "md5.h" 11 11 12 /* Client Online (group 1, subtype 2)*/12 /* Subtype 0x0002 - Client Online */ 13 13 faim_export int aim_clientready(aim_session_t *sess, aim_conn_t *conn) 14 14 { … … 49 49 50 50 /* 51 * Host Online (group 1, type 3)51 * Subtype 0x0003 - Host Online 52 52 * 53 53 * See comments in conn.c about how the group associations are supposed … … 92 92 } 93 93 94 /* S ervice request (group 1, type 4)*/94 /* Subtype 0x0004 - Service request */ 95 95 faim_export int aim_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid) 96 96 { … … 98 98 } 99 99 100 /* Redirect (group 1, type 5)*/100 /* Subtype 0x0005 - Redirect */ 101 101 static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 102 102 { … … 148 148 } 149 149 150 /* Request Rate Information. (group 1, type 6)*/150 /* Subtype 0x0006 - Request Rate Information. */ 151 151 faim_internal int aim_reqrates(aim_session_t *sess, aim_conn_t *conn) 152 152 { … … 258 258 } 259 259 260 /* Rate Parameters (group 1, type 7)*/260 /* Subtype 0x0007 - Rate Parameters */ 261 261 static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 262 262 { … … 345 345 } 346 346 347 /* Add Rate Parameter (group 1, type 8)*/347 /* Subtype 0x0008 - Add Rate Parameter */ 348 348 faim_internal int aim_rates_addparam(aim_session_t *sess, aim_conn_t *conn) 349 349 { … … 367 367 } 368 368 369 /* Delete Rate Parameter (group 1, type 9)*/369 /* Subtype 0x0009 - Delete Rate Parameter */ 370 370 faim_internal int aim_rates_delparam(aim_session_t *sess, aim_conn_t *conn) 371 371 { … … 389 389 } 390 390 391 /* Rate Change (group 1, type 0x0a)*/391 /* Subtype 0x000a - Rate Change */ 392 392 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 393 393 { … … 414 414 415 415 /* 416 * How Migrations work. 416 * How Migrations work. 417 417 * 418 418 * The server sends a Server Pause message, which the client should respond to … … 426 426 */ 427 427 428 /* S ervice Pause (group 1, type 0x0b)*/428 /* Subtype 0x000b - Service Pause */ 429 429 static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 430 430 { … … 438 438 439 439 /* 440 * S ervice Pause Acknowledgement (group 1, type 0x0c)440 * Subtype 0x000c - Service Pause Acknowledgement 441 441 * 442 442 * It is rather important that aim_sendpauseack() gets called for the exact … … 474 474 } 475 475 476 /* S ervice Resume (group 1, type 0x0d)*/476 /* Subtype 0x000d - Service Resume */ 477 477 static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 478 478 { … … 485 485 } 486 486 487 /* Request self-info (group 1, type 0x0e)*/487 /* Subtype 0x000e - Request self-info */ 488 488 faim_export int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn) 489 489 { … … 491 491 } 492 492 493 /* S elf User Info (group 1, type 0x0f)*/493 /* Subtype 0x000f - Self User Info */ 494 494 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 495 495 { … … 505 505 } 506 506 507 /* Evil Notification (group 1, type 0x10)*/507 /* Subtype 0x0010 - Evil Notification */ 508 508 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 509 509 { … … 526 526 527 527 /* 528 * Idle Notification (group 1, type 0x11)528 * Subtype 0x0011 - Idle Notification 529 529 * 530 530 * Should set your current idle time in seconds. Note that this should … … 540 540 541 541 /* 542 * S ervice Migrate (group 1, type 0x12)542 * Subtype 0x0012 - Service Migrate 543 543 * 544 544 * This is the final SNAC sent on the original connection during a migration. … … 592 592 } 593 593 594 /* Message of the Day (group 1, type 0x13)*/594 /* Subtype 0x0013 - Message of the Day */ 595 595 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 596 596 { … … 632 632 633 633 /* 634 * S et privacy flags (group 1, type 0x14)634 * Subtype 0x0014 - Set privacy flags 635 635 * 636 636 * Normally 0x03. … … 646 646 647 647 /* 648 * No-op (group 1, type 0x16)648 * Subtype 0x0016 - No-op 649 649 * 650 650 * WinAIM sends these every 4min or so to keep the connection alive. Its not 651 * real necessary.651 * really necessary. 652 652 * 653 653 */ … … 658 658 659 659 /* 660 * S et client versions (group 1, subtype 0x17)660 * Subtype 0x0017 - Set client versions 661 661 * 662 662 * If you've seen the clientonline/clientready SNAC you're probably … … 705 705 } 706 706 707 /* Host versions (group 1, subtype 0x18)*/707 /* Subtype 0x0018 - Host versions */ 708 708 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 709 709 { … … 725 725 726 726 /* 727 * S et Extended Status (group 1, type 0x1e)727 * Subtype 0x001e - Set Extended Status 728 728 * 729 729 * Currently only works if using ICQ. … … 791 791 * 792 792 */ 793 /* Client verification (group 1, subtype 0x1f)*/793 /* Subtype 0x001f - Client verification */ 794 794 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 795 795 { … … 816 816 } 817 817 818 #if 0 818 #if 0 819 819 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len) 820 820 { … … 839 839 #endif 840 840 841 /* Client verification reply (group 1, subtype 0x20)*/841 /* Subtype 0x0020 - Client verification reply */ 842 842 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag) 843 843 { … … 970 970 return 0; 971 971 } 972 -
libfaim/snac.c
r5e53c4a r862371b 90 90 if (cur->id == id) { 91 91 *prev = cur->next; 92 if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) { 93 struct aim_snac_destructor *asd = cur->data; 94 cur->data = asd->data; 95 free(asd); 96 } 92 97 return cur; 93 98 } else … … 97 102 return cur; 98 103 } 104 105 /* Free a SNAC, and call the appropriate destructor if necessary. 106 */ 107 faim_internal faim_shortfunc void aim_cleansnac(aim_session_t *sess, aim_snac_t *snac) 108 { 109 aim_module_t *cur; 110 111 if (snac->flags & AIM_SNACFLAGS_DESTRUCTOR) { 112 struct aim_snac_destructor *d = snac->data; 113 aim_modsnac_t modsnac; 114 115 modsnac.id = snac->id; 116 modsnac.subtype = snac->type; 117 modsnac.family = snac->family; 118 modsnac.flags = snac->flags; 119 120 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) 121 { 122 if (!cur->snacdestructor) 123 continue; 124 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 125 (cur->family != modsnac.family)) 126 continue; 127 if (cur->snacdestructor(sess, d->conn, &modsnac, 128 d->data)) 129 break; 130 } 131 free(d->data); 132 } 133 134 free(snac->data); 135 free(snac); 136 } 137 99 138 100 139 /* … … 123 162 *prev = cur->next; 124 163 125 /* XXX should we have destructors here? */ 126 free(cur->data); 127 free(cur); 128 164 aim_cleansnac(sess, cur); 129 165 } else 130 166 prev = &cur->next; -
libfaim/ssi.c
r5e53c4a r862371b 6 6 * to be stored on the server, so that they can be accessed from any client. 7 7 * 8 * We keep a copy of the ssi data in sess->ssi, because the data needs to be 9 * accessed for various reasons. So all the "aim_ssi_itemlist_bleh" functions 10 * near the top just manage the local data. 11 * 12 * The SNAC sending and receiving functions are lower down in the file, and 13 * they're simpler. They are in the order of the subtypes they deal with, 14 * starting with the request rights function (subtype 0x0002), then parse 15 * rights (subtype 0x0003), then--well, you get the idea. 16 * 8 17 * This is entirely too complicated. 18 * You don't know the half of it. 19 * 20 * XXX - Test for memory leaks 21 * XXX - Better parsing of rights, and use the rights info to limit adds 9 22 * 10 23 */ … … 13 26 #include <aim.h> 14 27 28 /** 29 * Locally add a new item to the given item list. 30 * 31 * @param list A pointer to a pointer to the current list of items. 32 * @param parent A pointer to the parent group, or NULL if the item should have no 33 * parent group (ie. the group ID# should be 0). 34 * @param name A null terminated string of the name of the new item, or NULL if the 35 * item should have no name. 36 * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc. 37 * @return The newly created item. 38 */ 39 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, const char *name, fu16_t type) 40 { 41 int i; 42 struct aim_ssi_item *cur, *newitem; 43 44 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 45 return NULL; 46 47 /* Set the name */ 48 if (name) { 49 if (!(newitem->name = (char *)malloc((strlen(name)+1)*sizeof(char)))) { 50 free(newitem); 51 return NULL; 52 } 53 strcpy(newitem->name, name); 54 } else 55 newitem->name = NULL; 56 57 /* Set the group ID# and the buddy ID# */ 58 newitem->gid = 0x0000; 59 newitem->bid = 0x0000; 60 if (type == AIM_SSI_TYPE_GROUP) { 61 if (name) 62 do { 63 newitem->gid += 0x0001; 64 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 65 if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) 66 i=1; 67 } while (i); 68 } else { 69 if (parent) 70 newitem->gid = parent->gid; 71 do { 72 newitem->bid += 0x0001; 73 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 74 if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) 75 i=1; 76 } while (i); 77 } 78 79 /* Set the rest */ 80 newitem->type = type; 81 newitem->data = NULL; 82 newitem->next = *list; 83 *list = newitem; 84 85 return newitem; 86 } 87 88 /** 89 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. 90 * 91 * @param list A pointer to a pointer to the current list of items. 92 * @param parentgroup A pointer to the group who's additional data you want to rebuild. 93 * @return Return 0 if no errors, otherwise return the error number. 94 */ 95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) 96 { 97 int newlen; 98 struct aim_ssi_item *cur; 99 100 /* Free the old additional data */ 101 if (parentgroup->data) { 102 aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data); 103 parentgroup->data = NULL; 104 } 105 106 /* Find the length for the new additional data */ 107 newlen = 0; 108 if (parentgroup->gid == 0x0000) { 109 for (cur=*list; cur; cur=cur->next) 110 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) 111 newlen += 2; 112 } else { 113 for (cur=*list; cur; cur=cur->next) 114 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 115 newlen += 2; 116 } 117 118 /* Rebuild the additional data */ 119 if (newlen>0) { 120 fu8_t *newdata; 121 122 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) 123 return -ENOMEM; 124 newlen = 0; 125 if (parentgroup->gid == 0x0000) { 126 for (cur=*list; cur; cur=cur->next) 127 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) 128 newlen += aimutil_put16(newdata+newlen, cur->gid); 129 } else { 130 for (cur=*list; cur; cur=cur->next) 131 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 132 newlen += aimutil_put16(newdata+newlen, cur->bid); 133 } 134 aim_addtlvtochain_raw((aim_tlvlist_t **)&(parentgroup->data), 0x00c8, newlen, newdata); 135 136 free(newdata); 137 } 138 139 return 0; 140 } 141 142 /** 143 * Locally free all of the stored buddy list information. 144 * 145 * @param sess The oscar session. 146 * @return Return 0 if no errors, otherwise return the error number. 147 */ 148 static int aim_ssi_freelist(aim_session_t *sess) 149 { 150 struct aim_ssi_item *cur, *delitem; 151 152 cur = sess->ssi.items; 153 while (cur) { 154 if (cur->name) free(cur->name); 155 if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data); 156 delitem = cur; 157 cur = cur->next; 158 free(delitem); 159 } 160 161 sess->ssi.items = NULL; 162 sess->ssi.revision = 0; 163 sess->ssi.timestamp = (time_t)0; 164 165 return 0; 166 } 167 168 /** 169 * Locally find an item given a group ID# and a buddy ID#. 170 * 171 * @param list A pointer to the current list of items. 172 * @param gid The group ID# of the desired item. 173 * @param bid The buddy ID# of the desired item. 174 * @return Return a pointer to the item if found, else return NULL; 175 */ 176 faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid) 177 { 178 struct aim_ssi_item *cur; 179 for (cur=list; cur; cur=cur->next) 180 if ((cur->gid == gid) && (cur->bid == bid)) 181 return cur; 182 return NULL; 183 } 184 185 /** 186 * Locally find an item given a group name, screen name, and type. If group name 187 * and screen name are null, then just return the first item of the given type. 188 * 189 * @param list A pointer to the current list of items. 190 * @param gn The group name of the desired item. 191 * @param bn The buddy name of the desired item. 192 * @param type The type of the desired item. 193 * @return Return a pointer to the item if found, else return NULL; 194 */ 195 faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type) 196 { 197 struct aim_ssi_item *cur; 198 if (!list) 199 return NULL; 200 201 if (gn && sn) { /* For finding buddies in groups */ 202 for (cur=list; cur; cur=cur->next) 203 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) { 204 struct aim_ssi_item *curg; 205 for (curg=list; curg; curg=curg->next) 206 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn))) 207 return cur; 208 } 209 210 } else if (sn) { /* For finding groups, permits, denies, and ignores */ 211 for (cur=list; cur; cur=cur->next) 212 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) 213 return cur; 214 215 /* For stuff without names--permit deny setting, visibility mask, etc. */ 216 } else for (cur=list; cur; cur=cur->next) { 217 if (cur->type == type) 218 return cur; 219 } 220 221 return NULL; 222 } 223 224 /** 225 * Locally find the parent item of the given buddy name. 226 * 227 * @param list A pointer to the current list of items. 228 * @param bn The buddy name of the desired item. 229 * @return Return a pointer to the item if found, else return NULL; 230 */ 231 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn) 232 { 233 struct aim_ssi_item *cur, *curg; 234 if (!list || !sn) 235 return NULL; 236 if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY))) 237 return NULL; 238 for (curg=list; curg; curg=curg->next) 239 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid)) 240 return curg; 241 return NULL; 242 } 243 244 /** 245 * Locally find the permit/deny setting item, and return the setting. 246 * 247 * @param list A pointer to the current list of items. 248 * @return Return the current SSI permit deny setting, or 0 if no setting was found. 249 */ 250 faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list) 251 { 252 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO); 253 if (cur) { 254 aim_tlvlist_t *tlvlist = cur->data; 255 if (tlvlist) { 256 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1); 257 if (tlv && tlv->value) 258 return aimutil_get8(tlv->value); 259 } 260 } 261 return 0; 262 } 263 264 /** 265 * Locally find the presence flag item, and return the setting. The returned setting is a 266 * bitmask of the user flags that you are visible to. See the AIM_FLAG_* #defines 267 * in aim.h 268 * 269 * @param list A pointer to the current list of items. 270 * @return Return the current visibility mask. 271 */ 272 faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list) 273 { 274 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); 275 if (cur) { 276 aim_tlvlist_t *tlvlist = cur->data; 277 if (tlvlist) { 278 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00c9, 1); 279 if (tlv && tlv->length) 280 return aimutil_get32(tlv->value); 281 } 282 } 283 return 0xFFFFFFFF; 284 } 285 286 /** 287 * Add the given packet to the holding queue. We totally need to send SSI SNACs one at 288 * a time, so we have a local queue where packets get put before they are sent, and 289 * then we send stuff one at a time, nice and orderly-like. 290 * 291 * @param sess The oscar session. 292 * @param conn The bos connection for this session. 293 * @param fr The newly created SNAC that you want to send. 294 * @return Return 0 if no errors, otherwise return the error number. 295 */ 296 static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) 297 { 298 aim_frame_t *cur; 299 300 if (!sess || !conn || !fr) 301 return -EINVAL; 302 303 fr->next = NULL; 304 if (sess->ssi.holding_queue == NULL) { 305 sess->ssi.holding_queue = fr; 306 if (!sess->ssi.waiting_for_ack) 307 aim_ssi_modbegin(sess, conn); 308 } else { 309 for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) ; 310 cur->next = fr; 311 } 312 313 return 0; 314 } 315 316 /** 317 * Send the next SNAC from the holding queue. This is called 318 * automatically when an ack from an add, mod, or del is received. 319 * If the queue is empty, it sends the modend SNAC. 320 * 321 * @param sess The oscar session. 322 * @param conn The bos connection for this session. 323 * @return Return 0 if no errors, otherwise return the error number. 324 */ 325 static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn) 326 { 327 aim_frame_t *cur; 328 329 if (!sess || !conn) 330 return -EINVAL; 331 332 if (!sess->ssi.waiting_for_ack) { 333 if (sess->ssi.holding_queue) { 334 sess->ssi.waiting_for_ack = 1; 335 cur = sess->ssi.holding_queue->next; 336 sess->ssi.holding_queue->next = NULL; 337 aim_tx_enqueue(sess, sess->ssi.holding_queue); 338 sess->ssi.holding_queue = cur; 339 } else 340 aim_ssi_modend(sess, conn); 341 } 342 343 return 0; 344 } 345 346 /** 347 * Send SNACs necessary to remove all SSI data from the server list, 348 * and then free the local copy as well. 349 * 350 * @param sess The oscar session. 351 * @param conn The bos connection for this session. 352 * @return Return 0 if no errors, otherwise return the error number. 353 */ 354 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn) 355 { 356 int num; 357 struct aim_ssi_item *cur, **items; 358 359 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) 360 num++; 361 362 if (!(items = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 363 return -ENOMEM; 364 memset(items, 0, num*sizeof(struct aim_ssi_item *)); 365 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) { 366 items[num] = cur; 367 num++; 368 } 369 370 aim_ssi_addmoddel(sess, conn, items, num, AIM_CB_SSI_DEL); 371 free(items); 372 aim_ssi_dispatch(sess, conn); 373 aim_ssi_freelist(sess); 374 375 return 0; 376 } 377 378 /** 379 * This "cleans" the ssi list. It does a few things, with the intent of making 380 * sure there ain't nothin' wrong with your SSI. 381 * -Make sure all buddies are in a group, and all groups have the correct 382 * additional data. 383 * -Make sure there are no empty groups in the list. While there is nothing 384 * wrong empty groups in the SSI, it's wiser to not have them. 385 * 386 * @param sess The oscar session. 387 * @param conn The bos connection for this session. 388 * @return Return 0 if no errors, otherwise return the error number. 389 */ 390 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn) 391 { 392 unsigned int i; 393 struct aim_ssi_item *cur, *parentgroup; 394 395 /* Make sure we actually need to clean out the list */ 396 for (cur=sess->ssi.items, i=0; cur && !i; cur=cur->next) 397 /* Any buddies directly in the master group */ 398 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) 399 i++; 400 if (!i) 401 return 0; 402 403 /* Remove all the additional data from all groups */ 404 for (cur=sess->ssi.items; cur; cur=cur->next) 405 if ((cur->data) && (cur->type == AIM_SSI_TYPE_GROUP)) { 406 aim_freetlvchain((aim_tlvlist_t **)&cur->data); 407 cur->data = NULL; 408 } 409 410 /* If there are buddies directly in the master group, make sure */ 411 /* there is a group to put them in. Any group, any group at all. */ 412 for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next); 413 if (!cur) { 414 for (parentgroup=sess->ssi.items; ((parentgroup) && (parentgroup->type!=AIM_SSI_TYPE_GROUP) && (parentgroup->gid==0x0000)); parentgroup=parentgroup->next); 415 if (!parentgroup) { 416 char *newgroup; 417 newgroup = (char*)malloc(strlen("Unknown")*sizeof(char)); 418 strcpy(newgroup, "Unknown"); 419 aim_ssi_addgroups(sess, conn, (const char**)&newgroup, 1); 420 } 421 } 422 423 /* Set parentgroup equal to any arbitray group */ 424 for (parentgroup=sess->ssi.items; parentgroup->gid==0x0000 || parentgroup->type!=AIM_SSI_TYPE_GROUP; parentgroup=parentgroup->next); 425 426 /* If there are any buddies directly in the master group, put them in a real group */ 427 for (cur=sess->ssi.items; cur; cur=cur->next) 428 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) { 429 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_DEL); 430 cur->gid = parentgroup->gid; 431 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 432 } 433 434 /* Rebuild additional data for all groups */ 435 for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next) 436 if (parentgroup->type == AIM_SSI_TYPE_GROUP) 437 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); 438 439 /* Send a mod snac for all groups */ 440 i = 0; 441 for (cur=sess->ssi.items; cur; cur=cur->next) 442 if (cur->type == AIM_SSI_TYPE_GROUP) 443 i++; 444 if (i > 0) { 445 /* Allocate an array of pointers to each of the groups */ 446 struct aim_ssi_item **groups; 447 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) 448 return -ENOMEM; 449 450 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) 451 if (cur->type == AIM_SSI_TYPE_GROUP) 452 groups[i] = cur; 453 454 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_MOD); 455 free(groups); 456 } 457 458 /* Send a del snac for any empty groups */ 459 i = 0; 460 for (cur=sess->ssi.items; cur; cur=cur->next) 461 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) 462 i++; 463 if (i > 0) { 464 /* Allocate an array of pointers to each of the groups */ 465 struct aim_ssi_item **groups; 466 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) 467 return -ENOMEM; 468 469 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) 470 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) 471 groups[i] = cur; 472 473 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_DEL); 474 free(groups); 475 } 476 477 /* Begin sending SSI SNACs */ 478 aim_ssi_dispatch(sess, conn); 479 480 return 0; 481 } 482 483 /** 484 * Add an array of screen names to the given group. 485 * 486 * @param sess The oscar session. 487 * @param conn The bos connection for this session. 488 * @param gn The name of the group to which you want to add these names. 489 * @param sn An array of null terminated strings of the names you want to add. 490 * @param num The number of screen names you are adding (size of the sn array). 491 * @return Return 0 if no errors, otherwise return the error number. 492 */ 493 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num) 494 { 495 struct aim_ssi_item *parentgroup, **newitems; 496 fu16_t i; 497 498 if (!sess || !conn || !gn || !sn || !num) 499 return -EINVAL; 500 501 /* Look up the parent group */ 502 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) { 503 aim_ssi_addgroups(sess, conn, (const char **)&gn, 1); 504 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) 505 return -ENOMEM; 506 } 507 508 /* Allocate an array of pointers to each of the new items */ 509 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 510 return -ENOMEM; 511 512 /* Add items to the local list, and index them in the array */ 513 for (i=0; i<num; i++) 514 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) { 515 free(newitems); 516 return -ENOMEM; 517 } 518 519 /* Send the add item SNAC */ 520 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 521 free(newitems); 522 return -i; 523 } 524 525 /* Free the array of pointers to each of the new items */ 526 free(newitems); 527 528 /* Rebuild the additional data in the parent group */ 529 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) 530 return i; 531 532 /* Send the mod item SNAC */ 533 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) 534 return i; 535 536 /* Begin sending SSI SNACs */ 537 if (!(i = aim_ssi_dispatch(sess, conn))) 538 return i; 539 540 return 0; 541 } 542 543 /** 544 * Add the master group (the group containing all groups). This is called by 545 * aim_ssi_addgroups, if necessary. 546 * 547 * @param sess The oscar session. 548 * @param conn The bos connection for this session. 549 * @return Return 0 if no errors, otherwise return the error number. 550 */ 551 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) 552 { 553 struct aim_ssi_item *newitem; 554 555 if (!sess || !conn) 556 return -EINVAL; 557 558 /* Add the item to the local list, and keep a pointer to it */ 559 if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) 560 return -ENOMEM; 561 562 /* If there are any existing groups (technically there shouldn't be, but */ 563 /* just in case) then add their group ID#'s to the additional data */ 564 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem); 565 566 /* Send the add item SNAC */ 567 aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD); 568 569 /* Begin sending SSI SNACs */ 570 aim_ssi_dispatch(sess, conn); 571 572 return 0; 573 } 574 575 /** 576 * Add an array of groups to the list. 577 * 578 * @param sess The oscar session. 579 * @param conn The bos connection for this session. 580 * @param gn An array of null terminated strings of the names you want to add. 581 * @param num The number of groups names you are adding (size of the sn array). 582 * @return Return 0 if no errors, otherwise return the error number. 583 */ 584 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num) 585 { 586 struct aim_ssi_item *parentgroup, **newitems; 587 fu16_t i; 588 589 if (!sess || !conn || !gn || !num) 590 return -EINVAL; 591 592 /* Look up the parent group */ 593 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) { 594 aim_ssi_addmastergroup(sess, conn); 595 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) 596 return -ENOMEM; 597 } 598 599 /* Allocate an array of pointers to each of the new items */ 600 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 601 return -ENOMEM; 602 603 /* Add items to the local list, and index them in the array */ 604 for (i=0; i<num; i++) 605 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) { 606 free(newitems); 607 return -ENOMEM; 608 } 609 610 /* Send the add item SNAC */ 611 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 612 free(newitems); 613 return -i; 614 } 615 616 /* Free the array of pointers to each of the new items */ 617 free(newitems); 618 619 /* Rebuild the additional data in the parent group */ 620 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) 621 return i; 622 623 /* Send the mod item SNAC */ 624 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) 625 return i; 626 627 /* Begin sending SSI SNACs */ 628 if (!(i = aim_ssi_dispatch(sess, conn))) 629 return i; 630 631 return 0; 632 } 633 634 /** 635 * Add an array of a certain type of item to the list. This can be used for 636 * permit buddies, deny buddies, ICQ's ignore buddies, and probably other 637 * types, also. 638 * 639 * @param sess The oscar session. 640 * @param conn The bos connection for this session. 641 * @param sn An array of null terminated strings of the names you want to add. 642 * @param num The number of groups names you are adding (size of the sn array). 643 * @param type The type of item you want to add. See the AIM_SSI_TYPE_BLEH 644 * #defines in aim.h. 645 * @return Return 0 if no errors, otherwise return the error number. 646 */ 647 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) 648 { 649 struct aim_ssi_item **newitems; 650 fu16_t i; 651 652 if (!sess || !conn || !sn || !num) 653 return -EINVAL; 654 655 /* Allocate an array of pointers to each of the new items */ 656 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 657 return -ENOMEM; 658 659 /* Add items to the local list, and index them in the array */ 660 for (i=0; i<num; i++) 661 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) { 662 free(newitems); 663 return -ENOMEM; 664 } 665 666 /* Send the add item SNAC */ 667 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 668 free(newitems); 669 return -i; 670 } 671 672 /* Free the array of pointers to each of the new items */ 673 free(newitems); 674 675 /* Begin sending SSI SNACs */ 676 if (!(i = aim_ssi_dispatch(sess, conn))) 677 return i; 678 679 return 0; 680 } 681 682 /** 683 * Move a buddy from one group to another group. This basically just deletes the 684 * buddy and re-adds it. 685 * 686 * @param sess The oscar session. 687 * @param conn The bos connection for this session. 688 * @param oldgn The group that the buddy is currently in. 689 * @param newgn The group that the buddy should be moved in to. 690 * @param sn The name of the buddy to be moved. 691 * @return Return 0 if no errors, otherwise return the error number. 692 */ 693 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn) 694 { 695 struct aim_ssi_item **groups, *buddy, *cur; 696 fu16_t i; 697 698 if (!sess || !conn || !oldgn || !newgn || !sn) 699 return -EINVAL; 700 701 /* Look up the buddy */ 702 if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY))) 703 return -ENOMEM; 704 705 /* Allocate an array of pointers to the two groups */ 706 if (!(groups = (struct aim_ssi_item **)malloc(2*sizeof(struct aim_ssi_item *)))) 707 return -ENOMEM; 708 709 /* Look up the old parent group */ 710 if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) { 711 free(groups); 712 return -ENOMEM; 713 } 714 715 /* Look up the new parent group */ 716 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { 717 aim_ssi_addgroups(sess, conn, (const char**)&newgn, 1); 718 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { 719 free(groups); 720 return -ENOMEM; 721 } 722 } 723 724 /* Send the delete item SNAC */ 725 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL); 726 727 /* Put the buddy in the new group */ 728 buddy->gid = groups[1]->gid; 729 730 /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */ 731 buddy->bid = 0; 732 do { 733 buddy->bid += 0x0001; 734 for (cur=sess->ssi.items, i=0; ((cur) && (!i)); cur=cur->next) 735 if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && aim_sncmp(cur->name, buddy->name)) 736 i=1; 737 } while (i); 738 739 /* Rebuild the additional data in the two parent groups */ 740 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]); 741 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]); 742 743 /* Send the add item SNAC */ 744 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD); 745 746 /* Send the mod item SNAC */ 747 aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD); 748 749 /* Free the temporary array */ 750 free(groups); 751 752 /* Begin sending SSI SNACs */ 753 aim_ssi_dispatch(sess, conn); 754 755 return 0; 756 } 757 758 /** 759 * Rename a group. I really like how this is done. It turns me on. 760 * 761 * Did I say that out loud?... 762 * 763 * @param sess The oscar session. 764 * @param conn The bos connection for this session. 765 * @param oldgn The old group name. 766 * @param newgn The new group name. 767 * @return Return 0 if no errors, otherwise return the error number. 768 */ 769 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn) 770 { 771 struct aim_ssi_item *group; 772 773 if (!sess || !conn || !oldgn || !newgn) 774 return -EINVAL; 775 776 /* Look up the group */ 777 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) 778 return -ENOMEM; 779 780 /* Free the old group name and copy the new one in its place. */ 781 if (group->name) 782 free(group->name); 783 if (!(group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)))) { 784 group->name = NULL; 785 return -ENOMEM; 786 } 787 strcpy(group->name, newgn); 788 789 /* Send the mod item SNAC */ 790 aim_ssi_addmoddel(sess, conn, &group, 1, AIM_CB_SSI_MOD); 791 792 /* Begin sending SSI SNACs */ 793 aim_ssi_dispatch(sess, conn); 794 795 return 0; 796 } 797 798 /** 799 * Delete an array of screen names from the given group. 800 * 801 * @param sess The oscar session. 802 * @param conn The bos connection for this session. 803 * @param gn The name of the group from which you want to delete these names. 804 * @param sn An array of null terminated strings of the names you want to delete. 805 * @param num The number of screen names you are deleting (size of the sn array). 806 * @return Return 0 if no errors, otherwise return the error number. 807 */ 808 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num) 809 { 810 struct aim_ssi_item *cur, *parentgroup, **delitems; 811 int i; 812 813 if (!sess || !conn || !gn || !sn || !num) 814 return -EINVAL; 815 816 /* Look up the parent group */ 817 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) 818 return -EINVAL; 819 820 /* Allocate an array of pointers to each of the items to be deleted */ 821 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); 822 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); 823 824 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ 825 for (i=0; i<num; i++) { 826 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) { 827 free(delitems); 828 return -EINVAL; 829 } 830 831 /* Remove the delitems from the item list */ 832 if (sess->ssi.items == delitems[i]) { 833 sess->ssi.items = sess->ssi.items->next; 834 } else { 835 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); 836 if (cur->next) 837 cur->next = cur->next->next; 838 } 839 } 840 841 /* Send the del item SNAC */ 842 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); 843 844 /* Free the items */ 845 for (i=0; i<num; i++) { 846 if (delitems[i]->name) 847 free(delitems[i]->name); 848 if (delitems[i]->data) 849 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); 850 free(delitems[i]); 851 } 852 free(delitems); 853 854 /* Rebuild the additional data in the parent group */ 855 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); 856 857 /* Send the mod item SNAC */ 858 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); 859 860 /* Delete the group, but only if it's empty */ 861 if (!parentgroup->data) 862 aim_ssi_delgroups(sess, conn, &parentgroup->name, 1); 863 864 /* Begin sending SSI SNACs */ 865 aim_ssi_dispatch(sess, conn); 866 867 return 0; 868 } 869 870 /** 871 * Delete the master group from the item list. There can be only one. 872 * Er, so just find the one master group and delete it. 873 * 874 * @param sess The oscar session. 875 * @param conn The bos connection for this session. 876 * @return Return 0 if no errors, otherwise return the error number. 877 */ 878 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn) 879 { 880 struct aim_ssi_item *cur, *delitem; 881 882 if (!sess || !conn) 883 return -EINVAL; 884 885 /* Make delitem a pointer to the aim_ssi_item to be deleted */ 886 if (!(delitem = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) 887 return -EINVAL; 888 889 /* Remove delitem from the item list */ 890 if (sess->ssi.items == delitem) { 891 sess->ssi.items = sess->ssi.items->next; 892 } else { 893 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitem)); cur=cur->next); 894 if (cur->next) 895 cur->next = cur->next->next; 896 } 897 898 /* Send the del item SNAC */ 899 aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL); 900 901 /* Free the item */ 902 if (delitem->name) 903 free(delitem->name); 904 if (delitem->data) 905 aim_freetlvchain((aim_tlvlist_t **)&delitem->data); 906 free(delitem); 907 908 /* Begin sending SSI SNACs */ 909 aim_ssi_dispatch(sess, conn); 910 911 return 0; 912 } 913 914 /** 915 * Delete an array of groups. 916 * 917 * @param sess The oscar session. 918 * @param conn The bos connection for this session. 919 * @param gn An array of null terminated strings of the groups you want to delete. 920 * @param num The number of groups you are deleting (size of the gn array). 921 * @return Return 0 if no errors, otherwise return the error number. 922 */ 923 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) { 924 struct aim_ssi_item *cur, *parentgroup, **delitems; 925 int i; 926 927 if (!sess || !conn || !gn || !num) 928 return -EINVAL; 929 930 /* Look up the parent group */ 931 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) 932 return -EINVAL; 933 934 /* Allocate an array of pointers to each of the items to be deleted */ 935 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); 936 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); 937 938 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ 939 for (i=0; i<num; i++) { 940 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) { 941 free(delitems); 942 return -EINVAL; 943 } 944 945 /* Remove the delitems from the item list */ 946 if (sess->ssi.items == delitems[i]) { 947 sess->ssi.items = sess->ssi.items->next; 948 } else { 949 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); 950 if (cur->next) 951 cur->next = cur->next->next; 952 } 953 } 954 955 /* Send the del item SNAC */ 956 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); 957 958 /* Free the items */ 959 for (i=0; i<num; i++) { 960 if (delitems[i]->name) 961 free(delitems[i]->name); 962 if (delitems[i]->data) 963 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); 964 free(delitems[i]); 965 } 966 free(delitems); 967 968 /* Rebuild the additional data in the parent group */ 969 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); 970 971 /* Send the mod item SNAC */ 972 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); 973 974 /* Delete the group, but only if it's empty */ 975 if (!parentgroup->data) 976 aim_ssi_delmastergroup(sess, conn); 977 978 /* Begin sending SSI SNACs */ 979 aim_ssi_dispatch(sess, conn); 980 981 return 0; 982 } 983 984 /** 985 * Delete an array of a certain type of item from the list. This can be 986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and 987 * probably other types, also. 988 * 989 * @param sess The oscar session. 990 * @param conn The bos connection for this session. 991 * @param sn An array of null terminated strings of the items you want to delete. 992 * @param num The number of items you are deleting (size of the sn array). 993 * @return Return 0 if no errors, otherwise return the error number. 994 */ 995 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) { 996 struct aim_ssi_item *cur, **delitems; 997 int i; 998 999 if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY)) 1000 return -EINVAL; 1001 1002 /* Allocate an array of pointers to each of the items to be deleted */ 1003 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); 1004 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); 1005 1006 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ 1007 for (i=0; i<num; i++) { 1008 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) { 1009 free(delitems); 1010 return -EINVAL; 1011 } 1012 1013 /* Remove the delitems from the item list */ 1014 if (sess->ssi.items == delitems[i]) { 1015 sess->ssi.items = sess->ssi.items->next; 1016 } else { 1017 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); 1018 if (cur->next) 1019 cur->next = cur->next->next; 1020 } 1021 } 1022 1023 /* Send the del item SNAC */ 1024 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); 1025 1026 /* Free the items */ 1027 for (i=0; i<num; i++) { 1028 if (delitems[i]->name) 1029 free(delitems[i]->name); 1030 if (delitems[i]->data) 1031 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); 1032 free(delitems[i]); 1033 } 1034 free(delitems); 1035 1036 /* Begin sending SSI SNACs */ 1037 aim_ssi_dispatch(sess, conn); 1038 1039 return 0; 1040 } 1041 1042 /** 1043 * Stores your permit/deny setting on the server, and starts using it. 1044 * 1045 * @param sess The oscar session. 1046 * @param conn The bos connection for this session. 1047 * @param permdeny Your permit/deny setting. Can be one of the following: 1048 * 1 - Allow all users 1049 * 2 - Block all users 1050 * 3 - Allow only the users below 1051 * 4 - Block only the users below 1052 * 5 - Allow only users on my buddy list 1053 * @param vismask A bitmask of the class of users to whom you want to be 1054 * visible. See the AIM_FLAG_BLEH #defines in aim.h 1055 * @return Return 0 if no errors, otherwise return the error number. 1056 */ 1057 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) { 1058 struct aim_ssi_item *cur; 1059 aim_tlv_t *tlv; 1060 1061 if (!sess || !conn) 1062 return -EINVAL; 1063 1064 /* Look up the permit/deny settings item */ 1065 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO); 1066 1067 if (cur) { 1068 /* The permit/deny item exists */ 1069 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00ca, 1))) { 1070 /* Just change the value of the x00ca TLV */ 1071 if (tlv->length != 1) { 1072 tlv->length = 1; 1073 free(tlv->value); 1074 tlv->value = (fu8_t *)malloc(sizeof(fu8_t)); 1075 } 1076 tlv->value[0] = permdeny; 1077 } else { 1078 /* Need to add the x00ca TLV to the TLV chain */ 1079 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); 1080 } 1081 1082 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00cb, 1))) { 1083 /* Just change the value of the x00cb TLV */ 1084 if (tlv->length != 4) { 1085 tlv->length = 4; 1086 free(tlv->value); 1087 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); 1088 } 1089 aimutil_put32(tlv->value, vismask); 1090 } else { 1091 /* Need to add the x00cb TLV to the TLV chain */ 1092 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); 1093 } 1094 1095 /* Send the mod item SNAC */ 1096 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); 1097 } else { 1098 /* Need to add the permit/deny item */ 1099 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO))) 1100 return -ENOMEM; 1101 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); 1102 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); 1103 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 1104 } 1105 1106 /* Begin sending SSI SNACs */ 1107 aim_ssi_dispatch(sess, conn); 1108 1109 return 0; 1110 } 1111 1112 /** 1113 * Stores your setting for whether you should show up as idle or not. 1114 * 1115 * @param sess The oscar session. 1116 * @param conn The bos connection for this session. 1117 * @param presence I think it's a bitmask, but I only know what one of the bits is: 1118 * 0x00000400 - Allow others to see your idle time 1119 * @return Return 0 if no errors, otherwise return the error number. 1120 */ 1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { 1122 struct aim_ssi_item *cur; 1123 aim_tlv_t *tlv; 1124 1125 if (!sess || !conn) 1126 return -EINVAL; 1127 1128 /* Look up the item */ 1129 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); 1130 1131 if (cur) { 1132 /* The item exists */ 1133 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00c9, 1))) { 1134 /* Just change the value of the x00c9 TLV */ 1135 if (tlv->length != 4) { 1136 tlv->length = 4; 1137 free(tlv->value); 1138 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); 1139 } 1140 aimutil_put32(tlv->value, presence); 1141 } else { 1142 /* Need to add the x00c9 TLV to the TLV chain */ 1143 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); 1144 } 1145 1146 /* Send the mod item SNAC */ 1147 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); 1148 } else { 1149 /* Need to add the item */ 1150 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) 1151 return -ENOMEM; 1152 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); 1153 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 1154 } 1155 1156 /* Begin sending SSI SNACs */ 1157 aim_ssi_dispatch(sess, conn); 1158 1159 return 0; 1160 } 1161 15 1162 /* 16 1163 * Request SSI Rights. … … 18 1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) 19 1166 { 20 return aim_genericreq_n(sess, conn, 0x0013, 0x0002);1167 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 21 1168 } 22 1169 … … 55 1202 return -ENOMEM; 56 1203 57 snacid = aim_cachesnac(sess, 0x0013, 0x0005, 0x0000, NULL, 0);58 59 aim_putsnac(&fr->data, 0x0013, 0x0005, 0x0000, snacid);1204 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, NULL, 0); 1205 1206 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, snacid); 60 1207 aimbs_put32(&fr->data, localstamp); 61 1208 aimbs_put16(&fr->data, localrev); … … 73 1220 int ret = 0; 74 1221 aim_rxcallback_t userfunc; 75 struct aim_ssi_item * list= NULL;1222 struct aim_ssi_item *cur = NULL; 76 1223 fu8_t fmtver; /* guess */ 77 fu16_t itemcount; 78 fu32_t stamp; 79 80 fmtver = aimbs_get8(bs); 81 itemcount = aimbs_get16(bs); 1224 fu16_t revision; 1225 fu32_t timestamp; 1226 1227 /* When you set the version for the SSI family to 2-4, the beginning of this changes. 1228 * Instead of the version and then the revision, there is "0x0006" and then a type 1229 * 0x0001 TLV containing the 2 byte SSI family version that you sent earlier. Also, 1230 * the SNAC flags go from 0x0000 to 0x8000. I guess the 0x0006 is the length of the 1231 * TLV(s) that follow. The rights SNAC does the same thing, with the differing flag 1232 * and everything. 1233 */ 1234 1235 fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */ 1236 revision = aimbs_get16(bs); /* # of times ssi data has been modified */ 1237 if (revision != 0) 1238 sess->ssi.revision = revision; 1239 1240 for (cur = sess->ssi.items; cur && cur->next; cur=cur->next) ; 82 1241 83 1242 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */ 84 1243 fu16_t namelen, tbslen; 85 struct aim_ssi_item *nl, *el; 86 87 if (!(nl = malloc(sizeof(struct aim_ssi_item)))) 88 break; 89 memset(nl, 0, sizeof(struct aim_ssi_item)); 1244 1245 if (!sess->ssi.items) { 1246 if (!(sess->ssi.items = malloc(sizeof(struct aim_ssi_item)))) 1247 return -ENOMEM; 1248 cur = sess->ssi.items; 1249 } else { 1250 if (!(cur->next = malloc(sizeof(struct aim_ssi_item)))) 1251 return -ENOMEM; 1252 cur = cur->next; 1253 } 1254 memset(cur, 0, sizeof(struct aim_ssi_item)); 90 1255 91 1256 if ((namelen = aimbs_get16(bs))) 92 nl->name = aimbs_getstr(bs, namelen);93 nl->gid = aimbs_get16(bs);94 nl->bid = aimbs_get16(bs);95 nl->type = aimbs_get16(bs);1257 cur->name = aimbs_getstr(bs, namelen); 1258 cur->gid = aimbs_get16(bs); 1259 cur->bid = aimbs_get16(bs); 1260 cur->type = aimbs_get16(bs); 96 1261 97 1262 if ((tbslen = aimbs_get16(bs))) { … … 99 1264 100 1265 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen); 101 nl->data = (void *)aim_readtlvchain(&tbs);1266 cur->data = (void *)aim_readtlvchain(&tbs); 102 1267 aim_bstream_advance(bs, tbslen); 103 1268 } 104 105 for (el = list; el && el->next; el = el->next) 106 ; 107 if (el) 108 el->next = nl; 109 else 110 list = nl; 111 } 112 113 stamp = aimbs_get32(bs); 1269 } 1270 1271 timestamp = aimbs_get32(bs); 1272 if (timestamp != 0) 1273 sess->ssi.timestamp = timestamp; 1274 sess->ssi.received_data = 1; 114 1275 115 1276 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 116 ret = userfunc(sess, rx, fmtver, itemcount, stamp, list); 117 118 while (list) { 119 struct aim_ssi_item *tmp; 120 121 tmp = list->next; 122 aim_freetlvchain((aim_tlvlist_t **)&list->data); 123 free(list); 124 list = tmp; 125 } 1277 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items); 126 1278 127 1279 return ret; … … 139 1291 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn) 140 1292 { 141 return aim_genericreq_n(sess, conn, 0x0013, 0x0007); 1293 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); 1294 } 1295 1296 /* 1297 * SSI Add/Mod/Del Item(s). 1298 * 1299 * Sends the SNAC to add, modify, or delete an item from the server-stored 1300 * information. These 3 SNACs all have an identical structure. The only 1301 * difference is the subtype that is set for the SNAC. 1302 * 1303 */ 1304 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype) 1305 { 1306 aim_frame_t *fr; 1307 aim_snacid_t snacid; 1308 int i, snaclen; 1309 1310 if (!sess || !conn || !items || !num) 1311 return -EINVAL; 1312 1313 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ 1314 for (i=0; i<num; i++) { 1315 snaclen += 10; /* For length, GID, BID, type, and length */ 1316 if (items[i]->name) 1317 snaclen += strlen(items[i]->name); 1318 if (items[i]->data) 1319 snaclen += aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data); 1320 } 1321 1322 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) 1323 return -ENOMEM; 1324 1325 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, NULL, 0); 1326 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid); 1327 1328 for (i=0; i<num; i++) { 1329 aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0); 1330 if (items[i]->name) 1331 aimbs_putraw(&fr->data, items[i]->name, strlen(items[i]->name)); 1332 aimbs_put16(&fr->data, items[i]->gid); 1333 aimbs_put16(&fr->data, items[i]->bid); 1334 aimbs_put16(&fr->data, items[i]->type); 1335 aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data) : 0); 1336 if (items[i]->data) 1337 aim_writetlvchain(&fr->data, (aim_tlvlist_t **)&items[i]->data); 1338 } 1339 1340 aim_ssi_enqueue(sess, conn, fr); 1341 1342 return 0; 1343 } 1344 1345 /* 1346 * SSI Add/Mod/Del Ack. 1347 * 1348 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). 1349 * 1350 */ 1351 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1352 { 1353 int ret = 0; 1354 aim_rxcallback_t userfunc; 1355 1356 sess->ssi.waiting_for_ack = 0; 1357 aim_ssi_dispatch(sess, rx->conn); 1358 1359 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1360 ret = userfunc(sess, rx); 1361 1362 return ret; 142 1363 } 143 1364 … … 150 1371 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) 151 1372 { 152 return aim_genericreq_n(sess, conn, 0x0013, 0x0011);1373 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); 153 1374 } 154 1375 … … 161 1382 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) 162 1383 { 163 return aim_genericreq_n(sess, conn, 0x0013, 0x0012);1384 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); 164 1385 } 165 1386 … … 176 1397 aim_rxcallback_t userfunc; 177 1398 1399 sess->ssi.received_data = 1; 1400 178 1401 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 179 1402 ret = userfunc(sess, rx); … … 185 1408 { 186 1409 187 if (snac->subtype == 0x0003)1410 if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) 188 1411 return parserights(sess, mod, rx, snac, bs); 189 else if (snac->subtype == 0x006)1412 else if (snac->subtype == AIM_CB_SSI_LIST) 190 1413 return parsedata(sess, mod, rx, snac, bs); 191 else if (snac->subtype == 0x00f) 1414 else if (snac->subtype == AIM_CB_SSI_SRVACK) 1415 return parseack(sess, mod, rx, snac, bs); 1416 else if (snac->subtype == AIM_CB_SSI_NOLIST) 192 1417 return parsedataunchanged(sess, mod, rx, snac, bs); 193 1418 … … 195 1420 } 196 1421 1422 static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod) 1423 { 1424 aim_ssi_freelist(sess); 1425 1426 return; 1427 } 1428 197 1429 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod) 198 1430 { 199 1431 200 mod->family = 0x0013;1432 mod->family = AIM_CB_FAM_SSI; 201 1433 mod->version = 0x0001; 202 1434 mod->toolid = 0x0110; … … 205 1437 strncpy(mod->name, "ssi", sizeof(mod->name)); 206 1438 mod->snachandler = snachandler; 207 208 return 0; 209 } 210 211 1439 mod->shutdown = ssi_shutdown; 1440 1441 return 0; 1442 } -
libfaim/stats.c
r5e53c4a r862371b 1 /* 2 * Family 0x000b - Statistics. 3 * 4 */ 1 5 2 6 #define FAIM_INTERNAL -
libfaim/tlv.c
r5e53c4a r862371b 29 29 /** 30 30 * aim_readtlvchain - Read a TLV chain from a buffer. 31 * @buf: Input buffer 32 * @maxlen: Length of input buffer 31 * @param bs Input bstream 33 32 * 34 33 * Reads and parses a series of TLV patterns from a data buffer; the … … 47 46 { 48 47 aim_tlvlist_t *list = NULL, *cur; 49 48 50 49 while (aim_bstream_empty(bs) > 0) { 51 50 fu16_t type, length; … … 71 70 else { 72 71 73 if (length > aim_bstream_empty(bs)) 74 goto errout; 72 if (length > aim_bstream_empty(bs)) { 73 aim_freetlvchain(&list); 74 return NULL; 75 } 75 76 76 77 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); 77 if (!cur) 78 goto errout; 78 if (!cur) { 79 aim_freetlvchain(&list); 80 return NULL; 81 } 79 82 80 83 memset(cur, 0, sizeof(aim_tlvlist_t)); 81 84 82 cur->tlv = createtlv(); 85 cur->tlv = createtlv(); 83 86 if (!cur->tlv) { 84 87 free(cur); 85 goto errout; 88 aim_freetlvchain(&list); 89 return NULL; 86 90 } 87 91 cur->tlv->type = type; … … 91 95 freetlv(&cur->tlv); 92 96 free(cur); 93 goto errout; 97 aim_freetlvchain(&list); 98 return NULL; 94 99 } 95 100 } … … 101 106 102 107 return list; 103 104 errout: 105 aim_freetlvchain(&list); 106 return NULL; 108 } 109 110 /** 111 * aim_readtlvchain_num - Read a TLV chain from a buffer. 112 * @param bs Input bstream 113 * @param num The max number of TLVs that will be read, or -1 if unlimited. 114 * There are a number of places where you want to read in a tlvchain, 115 * but the chain is not at the end of the SNAC, and the chain is 116 * preceeded by the number of TLVs. So you can limit that. 117 * 118 * Reads and parses a series of TLV patterns from a data buffer; the 119 * returned structure is manipulatable with the rest of the TLV 120 * routines. When done with a TLV chain, aim_freetlvchain() should 121 * be called to free the dynamic substructures. 122 * 123 * XXX There should be a flag setable here to have the tlvlist contain 124 * bstream references, so that at least the ->value portion of each 125 * element doesn't need to be malloc/memcpy'd. This could prove to be 126 * just as effecient as the in-place TLV parsing used in a couple places 127 * in libfaim. 128 * 129 */ 130 faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num) 131 { 132 aim_tlvlist_t *list = NULL, *cur; 133 134 while ((aim_bstream_empty(bs) > 0) && (num != 0)) { 135 fu16_t type, length; 136 137 type = aimbs_get16(bs); 138 length = aimbs_get16(bs); 139 140 if (length > aim_bstream_empty(bs)) { 141 aim_freetlvchain(&list); 142 return NULL; 143 } 144 145 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); 146 if (!cur) { 147 aim_freetlvchain(&list); 148 return NULL; 149 } 150 151 memset(cur, 0, sizeof(aim_tlvlist_t)); 152 153 cur->tlv = createtlv(); 154 if (!cur->tlv) { 155 free(cur); 156 aim_freetlvchain(&list); 157 return NULL; 158 } 159 cur->tlv->type = type; 160 if ((cur->tlv->length = length)) { 161 cur->tlv->value = aimbs_getraw(bs, length); 162 if (!cur->tlv->value) { 163 freetlv(&cur->tlv); 164 free(cur); 165 aim_freetlvchain(&list); 166 return NULL; 167 } 168 } 169 170 num--; 171 cur->next = list; 172 list = cur; 173 } 174 175 return list; 107 176 } 108 177 … … 182 251 183 252 /** 184 * aim_addtlvtochain_ str- Add a string to a TLV chain253 * aim_addtlvtochain_raw - Add a string to a TLV chain 185 254 * @list: Desination chain (%NULL pointer if empty) 186 * @t ype: TLV type187 * @ str: String to add188 * @ len: Length of string to add (not including %NULL)255 * @t: TLV type 256 * @l: Length of string to add (not including %NULL) 257 * @v: String to add 189 258 * 190 259 * Adds the passed string as a TLV element of the passed type … … 245 314 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain 246 315 * @list: Destination chain 247 * @t ype: TLV type to add248 * @v al: Value to add316 * @t: TLV type to add 317 * @v: Value to add 249 318 * 250 319 * Adds a two-byte unsigned integer to a TLV chain. … … 607 676 } 608 677 #endif 609 -
libfaim/translate.c
r5e53c4a r862371b 1 1 /* 2 * Family 0x000c - Translation. 3 * 2 4 * I have no idea why this group was issued. I have never seen anything 3 5 * that uses it. From what I remember, the last time I tried to poke at … … 24 26 return 0; 25 27 } 26 27 -
libfaim/txqueue.c
r5e53c4a r862371b 1 1 /* 2 * aim_txqueue.c2 * txqueue.c 3 3 * 4 4 * Herein lies all the mangement routines for the transmit (Tx) queue. … … 11 11 #ifndef _WIN32 12 12 #include <sys/socket.h> 13 #else 14 #include "win32dep.h" 13 15 #endif 14 16 … … 25 27 * 26 28 */ 27 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu 8_t chan, int datalen)29 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen) 28 30 { 29 31 aim_frame_t *fr; … … 62 64 } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) { 63 65 64 fr->hdr.oft.type = chan; 65 fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */ 66 fr->hdr.rend.type = chan; 66 67 67 68 } else … … 231 232 { 232 233 int wrote = 0; 233 234 234 if (!bs || !conn || (count < 0)) 235 235 return -EINVAL; … … 238 238 count = aim_bstream_empty(bs); /* truncate to remaining space */ 239 239 240 if (count) 241 wrote = aim_send(conn->fd, bs->data + bs->offset, count); 240 if (count) { 241 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) && 242 (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { 243 /* I strongly suspect that this is a horrible thing to do 244 * and I feel really guilty doing it. */ 245 const char *sn = aim_directim_getsn(conn); 246 aim_rxcallback_t userfunc; 247 while (count - wrote > 1024) { 248 wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, 1024); 249 if ((userfunc=aim_callhandler(conn->sessv, conn, 250 AIM_CB_FAM_SPECIAL, 251 AIM_CB_SPECIAL_IMAGETRANSFER))) 252 userfunc(conn->sessv, NULL, sn, 253 count-wrote>1024 ? ((double)wrote / count) : 1); 254 } 255 } 256 if (count - wrote) { 257 wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote); 258 } 259 260 } 261 242 262 243 263 if (((aim_session_t *)conn->sessv)->debug >= 2) { … … 285 305 obslen = aim_bstream_curpos(&obs); 286 306 aim_bstream_rewind(&obs); 287 288 307 if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) 289 308 err = -errno; … … 297 316 } 298 317 299 static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr) 300 { 301 aim_bstream_t hbs; 302 fu8_t *hbs_raw; 303 int hbslen; 318 static int sendframe_rendezvous(aim_session_t *sess, aim_frame_t *fr) 319 { 320 aim_bstream_t bs; 321 fu8_t *bs_raw; 304 322 int err = 0; 305 306 hbslen = 8 + fr->hdr.oft.hdr2len; 307 308 if (!(hbs_raw = malloc(hbslen))) 323 int totlen = 8 + aim_bstream_curpos(&fr->data); 324 325 if (!(bs_raw = malloc(totlen))) 309 326 return -1; 310 327 311 aim_bstream_init(&hbs, hbs_raw, hbslen); 312 313 aimbs_putraw(&hbs, fr->hdr.oft.magic, 4); 314 aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8); 315 aimbs_put16(&hbs, fr->hdr.oft.type); 316 aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); 317 318 aim_bstream_rewind(&hbs); 319 320 if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) { 321 328 aim_bstream_init(&bs, bs_raw, totlen); 329 330 aimbs_putraw(&bs, fr->hdr.rend.magic, 4); 331 aimbs_put16(&bs, 8 + fr->hdr.rend.hdrlen); 332 aimbs_put16(&bs, fr->hdr.rend.type); 333 334 /* payload */ 335 aim_bstream_rewind(&fr->data); 336 aimbs_putbs(&bs, &fr->data, totlen - 8); 337 338 aim_bstream_rewind(&bs); 339 340 if (aim_bstream_send(&bs, fr->conn, totlen) != totlen) 322 341 err = -errno; 323 324 } else if (aim_bstream_curpos(&fr->data)) { 325 int len; 326 327 len = aim_bstream_curpos(&fr->data); 328 aim_bstream_rewind(&fr->data); 329 330 if (aim_bstream_send(&fr->data, fr->conn, len) != len) 331 err = -errno; 332 } 333 334 free(hbs_raw); /* XXX aim_bstream_free */ 342 343 free(bs_raw); /* XXX aim_bstream_free */ 335 344 336 345 fr->handled = 1; 337 346 fr->conn->lastactivity = time(NULL); 338 339 347 340 348 return err; … … 346 354 return sendframe_flap(sess, fr); 347 355 else if (fr->hdrtype == AIM_FRAMETYPE_OFT) 348 return sendframe_ oft(sess, fr);356 return sendframe_rendezvous(sess, fr); 349 357 return -1; 350 358 } … … 422 430 * 423 431 */ 424 faim_ exportvoid aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)432 faim_internal void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn) 425 433 { 426 434 aim_frame_t *cur; … … 433 441 return; 434 442 } 435 436 -
libfaim/util.c
r5e53c4a r862371b 139 139 * 140 140 */ 141 142 141 faim_export int aim_sncmp(const char *sn1, const char *sn2) 143 142 { … … 205 204 return p; 206 205 } 207 208
Note: See TracChangeset
for help on using the changeset viewer.
