- Timestamp:
- Oct 10, 2003, 5:12:30 PM (22 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:
- fe6f1d3
- Parents:
- f4d0975
- Location:
- libfaim
- Files:
-
- 32 edited
Legend:
- Unmodified
- Added
- Removed
-
libfaim/admin.c
r862371b re374dee 4 4 * Used for stuff like changing the formating of your screen name, changing your 5 5 * email address, requesting an account confirmation email, getting account info, 6 * 6 * 7 7 */ 8 8 … … 197 197 static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 198 198 { 199 int ret = 0; 199 200 aim_rxcallback_t userfunc; 200 201 fu16_t status; … … 207 208 208 209 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 209 ret urnuserfunc(sess, rx, status);210 211 return 0;210 ret = userfunc(sess, rx, status); 211 212 return ret; 212 213 } 213 214 … … 228 229 mod->family = 0x0007; 229 230 mod->version = 0x0001; 230 mod->toolid = AIM_TOOL_NEWWIN;231 mod->toolversion = 0x0 361; /* XXX this and above aren't right */231 mod->toolid = 0x0010; 232 mod->toolversion = 0x0629; 232 233 mod->flags = 0; 233 234 strncpy(mod->name, "admin", sizeof(mod->name)); -
libfaim/aim.h
r862371b re374dee 3 3 * 4 4 * "come on, i turned a chick lesbian; i think this is the hackish equivalent" 5 * -- Josh M eyer5 * -- Josh Myer 6 6 * 7 7 */ … … 29 29 #include <sys/time.h> 30 30 #include <unistd.h> 31 #include <netdb.h> 31 32 #include <netinet/in.h> 32 33 #include <sys/socket.h> … … 35 36 #endif 36 37 38 #ifdef __cplusplus 39 extern "C" { 40 #endif 41 37 42 /* XXX adjust these based on autoconf-detected platform */ 38 43 typedef unsigned char fu8_t; 39 44 typedef unsigned short fu16_t; 40 typedef unsigned longfu32_t;45 typedef unsigned int fu32_t; 41 46 typedef fu32_t aim_snacid_t; 42 47 typedef fu16_t flap_seqnum_t; … … 44 49 #if defined(mach) && defined(__APPLE__) 45 50 #define gethostbyname(x) gethostbyname2(x, AF_INET) 46 #endif47 48 #if defined(_WIN32) || defined(STRICT_ANSI)49 #define faim_shortfunc50 #else51 #define faim_shortfunc inline52 51 #endif 53 52 … … 73 72 #endif 74 73 74 #ifndef FALSE 75 #define FALSE (0) 76 #endif 77 78 #ifndef TRUE 79 #define TRUE (!FALSE) 80 #endif 81 75 82 /* 76 83 * Current Maximum Length for Screen Names (not including NULL) … … 79 86 * however it is aparently legal for them to be larger. 80 87 */ 81 #define MAXSNLEN 3288 #define MAXSNLEN 97 82 89 83 90 /* … … 114 121 #define MAXCHATMSGLEN 512 115 122 116 /* 117 * Standard size of an AIM authorization cookie118 */ 119 #define AIM_COOKIELEN 0x100123 /** 124 * Maximum length for the password of an ICQ account 125 */ 126 #define MAXICQPASSLEN 8 120 127 121 128 #define AIM_MD5_STRING "AOL Instant Messenger (SM)" … … 130 137 const char *clientstring; 131 138 fu16_t clientid; 132 int major; 133 int minor; 134 int point; 135 int build; 139 fu16_t major; 140 fu16_t minor; 141 fu16_t point; 142 fu16_t build; 143 fu32_t distrib; 136 144 const char *country; /* two-letter abbrev */ 137 145 const char *lang; /* two-letter abbrev */ 138 146 }; 139 147 148 /* Needs to be checked */ 140 149 #define CLIENTINFO_AIM_3_5_1670 { \ 141 150 "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ 142 151 0x0004, \ 143 0x0003, \ 144 0x0005, \ 145 0x0000, \ 146 0x0686, \ 147 "us", \ 148 "en", \ 152 0x0003, 0x0005, \ 153 0x0000, 0x0686, \ 154 0x0000002a, \ 155 "us", "en", \ 149 156 } 150 157 158 /* Needs to be checked */ 159 /* Latest winaim without ssi */ 151 160 #define CLIENTINFO_AIM_4_1_2010 { \ 152 "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ 153 0x0004, \ 154 0x0004, \ 155 0x0001, \ 156 0x0000, \ 157 0x07da, \ 158 "us", \ 159 "en", \ 161 "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ 162 0x0004, \ 163 0x0004, 0x0001, \ 164 0x0000, 0x07da, \ 165 0x0000004b, \ 166 "us", "en", \ 160 167 } 161 168 169 /* Needs to be checked */ 170 #define CLIENTINFO_AIM_4_3_2188 { \ 171 "AOL Instant Messenger (SM), version 4.3.2188/WIN32", \ 172 0x0109, \ 173 0x0400, 0x0003, \ 174 0x0000, 0x088c, \ 175 0x00000086, \ 176 "us", "en", \ 177 } 178 179 /* Needs to be checked */ 180 #define CLIENTINFO_AIM_4_8_2540 { \ 181 "AOL Instant Messenger (SM), version 4.8.2540/WIN32", \ 182 0x0109, \ 183 0x0004, 0x0008, \ 184 0x0000, 0x09ec, \ 185 0x000000af, \ 186 "us", "en", \ 187 } 188 189 /* Needs to be checked */ 162 190 #define CLIENTINFO_AIM_5_0_2938 { \ 163 "AOL Instant Messenger, version 5.0.2938/WIN32", \ 164 0x0109, \ 165 0x0005, \ 166 0x0000, \ 167 0x0000, \ 168 0x0b7a, \ 169 "us", \ 170 "en", \ 191 "AOL Instant Messenger, version 5.0.2938/WIN32", \ 192 0x0109, \ 193 0x0005, 0x0000, \ 194 0x0000, 0x0b7a, \ 195 0x00000000, \ 196 "us", "en", \ 171 197 } 172 198 199 #define CLIENTINFO_AIM_5_1_3036 { \ 200 "AOL Instant Messenger, version 5.1.3036/WIN32", \ 201 0x0109, \ 202 0x0005, 0x0001, \ 203 0x0000, 0x0bdc, \ 204 0x000000d2, \ 205 "us", "en", \ 206 } 207 208 #define CLIENTINFO_ICHAT_1_0 { \ 209 "Apple iChat", \ 210 0x311a, \ 211 0x0001, 0x0000, \ 212 0x0000, 0x003c, \ 213 0x000000c6, \ 214 "us", "en", \ 215 } 216 217 /* Needs to be checked */ 173 218 #define CLIENTINFO_ICQ_4_65_3281 { \ 174 219 "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \ 175 220 0x010a, \ 176 0x0004, \ 177 0x0041, \ 178 0x0001, \ 179 0x0cd1, \ 180 "us", \ 181 "en", \ 221 0x0004, 0x0041, \ 222 0x0001, 0x0cd1, \ 223 0x00000055, \ 224 "us", "en", \ 182 225 } 183 226 227 /* Needs to be checked */ 184 228 #define CLIENTINFO_ICQ_5_34_3728 { \ 185 229 "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \ 186 230 0x010a, \ 187 0x0005, \ 188 0x0022, \ 189 0x0001, \ 190 0x0e8f, \ 191 "us", \ 192 "en", \ 231 0x0005, 0x0022, \ 232 0x0001, 0x0e8f, \ 233 0x00000055, \ 234 "us", "en", \ 193 235 } 194 236 195 /* 196 * I would make 4.1.2010 the default, but they seem to have found 197 * an alternate way of breaking that one. 198 * 199 * 3.5.1670 should work fine, however, you will be subjected to the 200 * memory test, which may require you to have a WinAIM binary lying 201 * around. (see login.c::memrequest()) 202 */ 203 #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_3_5_1670 204 #define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_4_65_3281 205 206 #ifndef TRUE 207 #define TRUE 1 208 #define FALSE 0 209 #endif 237 #define CLIENTINFO_ICQ_5_45_3777 { \ 238 "ICQ Inc. - Product of ICQ (TM).2003a.5.45.1.3777.85", \ 239 0x010a, \ 240 0x0005, 0x002d, \ 241 0x0001, 0x0ec1, \ 242 0x00000055, \ 243 "us", "en", \ 244 } 245 246 #define CLIENTINFO_ICQBasic_14_3_1068 { \ 247 "ICQBasic", \ 248 0x010a, \ 249 0x0014, 0x0003, \ 250 0x0000, 0x042c, \ 251 0x0000043d, \ 252 "us", "en", \ 253 } 254 255 #define CLIENTINFO_Netscape_7_0_1 { \ 256 "Netscape 2000 an approved user of AOL Instant Messenger (SM)", \ 257 0x1d0d, \ 258 0x0007, 0x0000, \ 259 0x0001, 0x0000, \ 260 0x00000058, \ 261 "us", "en", \ 262 } 263 264 #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036 265 #define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_5_45_3777 210 266 211 267 /* 212 268 * These could be arbitrary, but its easier to use the actual AIM values 213 269 */ 214 #define AIM_CONN_TYPE_AUTH 0x0007 215 #define AIM_CONN_TYPE_ADS 0x0005 216 #define AIM_CONN_TYPE_BOS 0x0002 217 #define AIM_CONN_TYPE_CHAT 0x000e 218 #define AIM_CONN_TYPE_CHATNAV 0x000d 219 #define AIM_CONN_TYPE_SEARCH 0x000f 220 #define AIM_CONN_TYPE_EMAIL 0x0018 221 222 /* they start getting arbitrary in rendezvous stuff =) */ 223 #define AIM_CONN_TYPE_RENDEZVOUS 0x0101 /* these do not speak FLAP! */ 224 #define AIM_CONN_TYPE_RENDEZVOUS_OUT 0x0102 /* socket waiting for accept() */ 270 #define AIM_CONN_TYPE_BOS 0x0002 271 #define AIM_CONN_TYPE_ADS 0x0005 272 #define AIM_CONN_TYPE_AUTH 0x0007 273 #define AIM_CONN_TYPE_CHATNAV 0x000d 274 #define AIM_CONN_TYPE_CHAT 0x000e 275 #define AIM_CONN_TYPE_SEARCH 0x000f 276 #define AIM_CONN_TYPE_ICON 0x0010 277 #define AIM_CONN_TYPE_EMAIL 0x0018 278 279 /* they start getting arbitrary for rendezvous stuff =) */ 280 #define AIM_CONN_TYPE_RENDEZVOUS 0xfffe /* these do not speak FLAP! */ 281 #define AIM_CONN_TYPE_LISTENER 0xffff /* socket waiting for accept() */ 225 282 226 283 /* 227 284 * Subtypes, we need these for OFT stuff. 228 285 */ 229 #define AIM_CONN_SUBTYPE_OFT_DIRECTIM 230 #define AIM_CONN_SUBTYPE_OFT_GETFILE 231 #define AIM_CONN_SUBTYPE_OFT_SENDFILE 232 #define AIM_CONN_SUBTYPE_OFT_BUDDYICON 233 #define AIM_CONN_SUBTYPE_OFT_VOICE 286 #define AIM_CONN_SUBTYPE_OFT_DIRECTIM 0x0001 287 #define AIM_CONN_SUBTYPE_OFT_GETFILE 0x0002 288 #define AIM_CONN_SUBTYPE_OFT_SENDFILE 0x0003 289 #define AIM_CONN_SUBTYPE_OFT_BUDDYICON 0x0004 290 #define AIM_CONN_SUBTYPE_OFT_VOICE 0x0005 234 291 235 292 /* 236 293 * Status values returned from aim_conn_new(). ORed together. 237 294 */ 238 #define AIM_CONN_STATUS_READY 239 #define AIM_CONN_STATUS_INTERNALERR 240 #define AIM_CONN_STATUS_RESOLVERR 241 #define AIM_CONN_STATUS_CONNERR 242 #define AIM_CONN_STATUS_INPROGRESS 243 244 #define AIM_FRAMETYPE_FLAP 245 #define AIM_FRAMETYPE_OFT 295 #define AIM_CONN_STATUS_READY 0x0001 296 #define AIM_CONN_STATUS_INTERNALERR 0x0002 297 #define AIM_CONN_STATUS_RESOLVERR 0x0040 298 #define AIM_CONN_STATUS_CONNERR 0x0080 299 #define AIM_CONN_STATUS_INPROGRESS 0x0100 300 301 #define AIM_FRAMETYPE_FLAP 0x0000 302 #define AIM_FRAMETYPE_OFT 0x0001 246 303 247 304 typedef struct aim_conn_s { … … 289 346 } flap; 290 347 struct { 291 fu8_t magic[4]; /* ODC2 OFT2 */348 fu8_t magic[4]; /* ODC2 or OFT2 */ 292 349 fu16_t hdrlen; 293 350 fu16_t type; … … 297 354 fu8_t handled; /* 0 = new, !0 = been handled */ 298 355 fu8_t nofree; /* 0 = free data on purge, 1 = only unlink */ 299 aim_conn_t *conn; 356 aim_conn_t *conn; /* the connection it came in on... */ 300 357 struct aim_frame_s *next; 301 358 } aim_frame_t; 302 359 303 360 typedef struct aim_msgcookie_s { 304 unsigned charcookie[8];361 fu8_t cookie[8]; 305 362 int type; 306 363 void *data; … … 308 365 struct aim_msgcookie_s *next; 309 366 } aim_msgcookie_t; 367 368 /* Values for sess->flags */ 369 #define AIM_SESS_FLAGS_SNACLOGIN 0x00000001 370 #define AIM_SESS_FLAGS_XORLOGIN 0x00000002 371 #define AIM_SESS_FLAGS_NONBLOCKCONNECT 0x00000004 372 #define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008 310 373 311 374 /* … … 331 394 332 395 /* ---- 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;345 396 346 397 /* Connection information */ … … 368 419 int (*tx_enqueue)(struct aim_session_s *, aim_frame_t *); 369 420 421 void *modlistv; 422 423 struct { 424 char server[128]; 425 char username[128]; 426 char password[128]; 427 } socksproxy; 428 429 fu32_t flags; /* AIM_SESS_FLAGS_ */ 430 431 int debug; 432 void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ 433 370 434 /* 371 435 * Outstanding snac handling … … 376 440 aim_snacid_t snacid_next; 377 441 442 aim_msgcookie_t *msgcookies; 443 struct aim_icq_info *icq_info; 444 struct aim_oft_info *oft_info; 445 struct aim_authresp_info *authinfo; 446 struct aim_emailinfo *emailinfo; 447 448 /* Server-stored information (ssi) */ 378 449 struct { 379 char server[128]; 380 char username[128]; 381 char password[128]; 382 } socksproxy; 383 384 fu32_t flags; /* AIM_SESS_FLAGS_ */ 385 386 int debug; 387 void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ 388 389 aim_msgcookie_t *msgcookies; 390 391 void *modlistv; 450 int received_data; 451 fu16_t numitems; 452 struct aim_ssi_item *official; 453 struct aim_ssi_item *local; 454 struct aim_ssi_tmp *pending; 455 time_t timestamp; 456 int waiting_for_ack; 457 } ssi; 392 458 } aim_session_t; 393 459 394 /* Values for sess->flags */395 #define AIM_SESS_FLAGS_SNACLOGIN 0x00000001396 #define AIM_SESS_FLAGS_XORLOGIN 0x00000002397 #define AIM_SESS_FLAGS_NONBLOCKCONNECT 0x00000004398 #define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008399 400 460 /* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */ 401 #define AIM_ICQ_STATE_NORMAL 0x00000000 402 #define AIM_ICQ_STATE_AWAY 0x00000001 403 #define AIM_ICQ_STATE_DND 0x00000002 404 #define AIM_ICQ_STATE_OUT 0x00000004 405 #define AIM_ICQ_STATE_BUSY 0x00000010 406 #define AIM_ICQ_STATE_CHAT 0x00000020 407 #define AIM_ICQ_STATE_INVISIBLE 0x00000100 408 #define AIM_ICQ_STATE_WEBAWARE 0x00010000 409 410 /* 411 * AIM User Info, Standard Form. 412 */ 413 typedef struct { 414 char sn[MAXSNLEN+1]; 415 fu16_t warnlevel; /* evil percent * 10 (999 = 99.9%) */ 416 fu16_t idletime; /* in seconds */ 417 fu16_t flags; 418 fu32_t createtime; /* time_t */ 419 fu32_t membersince; /* time_t */ 420 fu32_t onlinesince; /* time_t */ 421 fu32_t sessionlen; /* in seconds */ 422 fu32_t capabilities; 423 struct { 424 fu32_t status; 425 fu32_t ipaddr; 426 fu8_t crap[0x25]; /* until we figure it out... */ 427 } icqinfo; 428 fu32_t present; 429 } aim_userinfo_t; 430 431 #define AIM_USERINFO_PRESENT_FLAGS 0x00000001 432 #define AIM_USERINFO_PRESENT_MEMBERSINCE 0x00000002 433 #define AIM_USERINFO_PRESENT_ONLINESINCE 0x00000004 434 #define AIM_USERINFO_PRESENT_IDLE 0x00000008 435 #define AIM_USERINFO_PRESENT_ICQEXTSTATUS 0x00000010 436 #define AIM_USERINFO_PRESENT_ICQIPADDR 0x00000020 437 #define AIM_USERINFO_PRESENT_ICQDATA 0x00000040 438 #define AIM_USERINFO_PRESENT_CAPABILITIES 0x00000080 439 #define AIM_USERINFO_PRESENT_SESSIONLEN 0x00000100 440 #define AIM_USERINFO_PRESENT_CREATETIME 0x00000200 441 442 faim_export const char *aim_userinfo_sn(aim_userinfo_t *ui); 443 faim_export fu16_t aim_userinfo_flags(aim_userinfo_t *ui); 444 faim_export fu16_t aim_userinfo_idle(aim_userinfo_t *ui); 445 faim_export float aim_userinfo_warnlevel(aim_userinfo_t *ui); 446 faim_export time_t aim_userinfo_createtime(aim_userinfo_t *ui); 447 faim_export time_t aim_userinfo_membersince(aim_userinfo_t *ui); 448 faim_export time_t aim_userinfo_onlinesince(aim_userinfo_t *ui); 449 faim_export fu32_t aim_userinfo_sessionlen(aim_userinfo_t *ui); 450 faim_export int aim_userinfo_hascap(aim_userinfo_t *ui, fu32_t cap); 451 452 #define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */ 453 #define AIM_FLAG_ADMINISTRATOR 0x0002 454 #define AIM_FLAG_AOL 0x0004 455 #define AIM_FLAG_OSCAR_PAY 0x0008 456 #define AIM_FLAG_FREE 0x0010 457 #define AIM_FLAG_AWAY 0x0020 458 #define AIM_FLAG_ICQ 0x0040 459 #define AIM_FLAG_WIRELESS 0x0080 460 #define AIM_FLAG_UNKNOWN100 0x0100 461 #define AIM_FLAG_UNKNOWN200 0x0200 462 #define AIM_FLAG_ACTIVEBUDDY 0x0400 463 #define AIM_FLAG_UNKNOWN800 0x0800 464 #define AIM_FLAG_ABINTERNAL 0x1000 465 466 #define AIM_FLAG_ALLUSERS 0x001f 467 468 469 #if defined(FAIM_INTERNAL) || defined(FAIM_NEED_TLV) 470 /* 471 * TLV handling 472 */ 473 474 /* Generic TLV structure. */ 475 typedef struct aim_tlv_s { 476 fu16_t type; 477 fu16_t length; 478 fu8_t *value; 479 } aim_tlv_t; 480 481 /* List of above. */ 482 typedef struct aim_tlvlist_s { 483 aim_tlv_t *tlv; 484 struct aim_tlvlist_s *next; 485 } aim_tlvlist_t; 486 487 /* TLV-handling functions */ 488 489 #if 0 490 /* Very, very raw TLV handling. */ 491 faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v); 492 faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v); 493 faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v); 494 faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v); 495 #endif 496 497 /* TLV list handling. */ 498 faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs); 499 faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num); 500 faim_internal void aim_freetlvchain(aim_tlvlist_t **list); 501 faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n); 502 faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n); 503 faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num); 504 faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n); 505 faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n); 506 faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list); 507 faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v); 508 faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v); 509 faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v); 510 faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v); 511 faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu32_t caps); 512 faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type); 513 faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *ui); 514 faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl); 515 faim_internal int aim_counttlvchain(aim_tlvlist_t **list); 516 faim_internal int aim_sizetlvchain(aim_tlvlist_t **list); 517 #endif /* FAIM_INTERNAL */ 461 #define AIM_ICQ_STATE_NORMAL 0x00000000 462 #define AIM_ICQ_STATE_AWAY 0x00000001 463 #define AIM_ICQ_STATE_DND 0x00000002 464 #define AIM_ICQ_STATE_OUT 0x00000004 465 #define AIM_ICQ_STATE_BUSY 0x00000010 466 #define AIM_ICQ_STATE_CHAT 0x00000020 467 #define AIM_ICQ_STATE_INVISIBLE 0x00000100 468 #define AIM_ICQ_STATE_WEBAWARE 0x00010000 469 #define AIM_ICQ_STATE_HIDEIP 0x00020000 470 #define AIM_ICQ_STATE_BIRTHDAY 0x00080000 471 #define AIM_ICQ_STATE_DIRECTDISABLED 0x00100000 472 #define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000 473 #define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000 474 #define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000 475 518 476 519 477 /* … … 542 500 typedef int (*aim_rxcallback_t)(aim_session_t *, aim_frame_t *, ...); 543 501 502 503 /* auth.c */ 544 504 struct aim_clientrelease { 545 505 char *name; … … 556 516 char *email; 557 517 char *bosip; 518 fu16_t cookielen; 558 519 fu8_t *cookie; 559 520 char *chpassurl; … … 566 527 fu16_t group; 567 528 const char *ip; 529 fu16_t cookielen; 568 530 const fu8_t *cookie; 569 531 struct { /* group == AIM_CONN_TYPE_CHAT */ … … 578 540 faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn); 579 541 faim_export int aim_send_login(aim_session_t *, aim_conn_t *, const char *, const char *, struct client_info_s *, const char *key); 580 faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char*digest);542 faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest); 581 543 faim_export void aim_purge_rxqueue(aim_session_t *); 544 faim_export void aim_cleansnacs(aim_session_t *, int maxage); 582 545 583 546 #define AIM_TX_QUEUED 0 /* default */ … … 591 554 faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval); 592 555 593 faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags);556 faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags); 594 557 faim_export int aim_clearhandlers(aim_conn_t *conn); 595 558 … … 600 563 faim_export int aim_conngetmaxfd(aim_session_t *); 601 564 faim_export aim_conn_t *aim_select(aim_session_t *, struct timeval *, int *); 565 faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn); 602 566 faim_export int aim_conn_isready(aim_conn_t *); 603 567 faim_export int aim_conn_setstatus(aim_conn_t *, int); … … 607 571 typedef void (*faim_debugging_callback_t)(aim_session_t *sess, int level, const char *format, va_list va); 608 572 faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t); 609 faim_export void aim_session_init(aim_session_t *, unsigned longflags, int debuglevel);573 faim_export void aim_session_init(aim_session_t *, fu32_t flags, int debuglevel); 610 574 faim_export void aim_session_kill(aim_session_t *); 611 575 faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password); … … 614 578 faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd); 615 579 580 581 582 /* service.c */ 583 faim_export int aim_srv_setavailmsg(aim_session_t *sess, char *msg); 584 585 586 616 587 /* misc.c */ 617 588 … … 627 598 628 599 faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn); 629 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags);630 600 faim_export int aim_nop(aim_session_t *, aim_conn_t *); 631 601 faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn); … … 633 603 faim_export int aim_bos_changevisibility(aim_session_t *, aim_conn_t *, int, const char *); 634 604 faim_export int aim_bos_setbuddylist(aim_session_t *, aim_conn_t *, const char *); 635 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile , const char *awaymsg, fu32_t caps);605 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile_encoding, const char *profile, const int profile_len, const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len, fu32_t caps); 636 606 faim_export int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, fu32_t mask); 637 607 faim_export int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, fu32_t); … … 643 613 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); 644 614 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); 645 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status); 646 647 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *); 615 faim_export int aim_setextstatus(aim_session_t *sess, fu32_t status); 648 616 649 617 #define AIM_CLIENTTYPE_UNKNOWN 0x0000 … … 652 620 #define AIM_CLIENTTYPE_WINAIM41 0x0003 653 621 #define AIM_CLIENTTYPE_AOL_TOC 0x0004 654 faim_export unsigned short aim_fingerprintclient(unsigned char*msghdr, int len);622 faim_export fu16_t aim_im_fingerprint(const fu8_t *msghdr, int len); 655 623 656 624 #define AIM_RATE_CODE_CHANGE 0x0001 … … 660 628 faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn); 661 629 630 631 662 632 /* im.c */ 663 664 struct aim_fileheader_t { 665 #if 0 666 char magic[4]; /* 0 */ 667 short hdrlen; /* 4 */ 668 short hdrtype; /* 6 */ 669 #endif 670 char bcookie[8]; /* 8 */ 671 short encrypt; /* 16 */ 672 short compress; /* 18 */ 673 short totfiles; /* 20 */ 674 short filesleft; /* 22 */ 675 short totparts; /* 24 */ 676 short partsleft; /* 26 */ 677 long totsize; /* 28 */ 678 long size; /* 32 */ 679 long modtime; /* 36 */ 680 long checksum; /* 40 */ 681 long rfrcsum; /* 44 */ 682 long rfsize; /* 48 */ 683 long cretime; /* 52 */ 684 long rfcsum; /* 56 */ 685 long nrecvd; /* 60 */ 686 long recvcsum; /* 64 */ 687 char idstring[32]; /* 68 */ 688 char flags; /* 100 */ 689 char lnameoffset; /* 101 */ 690 char lsizeoffset; /* 102 */ 691 char dummy[69]; /* 103 */ 692 char macfileinfo[16]; /* 172 */ 693 short nencode; /* 188 */ 694 short nlanguage; /* 190 */ 695 char name[64]; /* 192 */ 696 /* 256 */ 697 }; 698 699 #define AIM_OFT_SUBTYPE_SEND_FILE 0x0001 700 #define AIM_OFT_SUBTYPE_SEND_DIR 0x0002 701 #define AIM_OFT_SUBTYPE_GET_FILE 0x0011 702 #define AIM_OPT_SUBTYPE_GET_LIST 0x0012 633 #define AIM_OFT_SUBTYPE_SEND_FILE 0x0001 634 #define AIM_OFT_SUBTYPE_SEND_DIR 0x0002 635 #define AIM_OFT_SUBTYPE_GET_FILE 0x0011 636 #define AIM_OPT_SUBTYPE_GET_LIST 0x0012 637 638 #define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000 639 #define AIM_TRANSFER_DENY_DECLINE 0x0001 640 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 641 642 #define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED 0x00000001 643 #define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED 0x00000002 644 645 /* This is what the server will give you if you don't set them yourself. */ 646 #define AIM_IMPARAM_DEFAULTS { \ 647 0, \ 648 AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \ 649 512, /* !! Note how small this is. */ \ 650 (99.9)*10, (99.9)*10, \ 651 1000 /* !! And how large this is. */ \ 652 } 653 654 /* This is what most AIM versions use. */ 655 #define AIM_IMPARAM_REASONABLE { \ 656 0, \ 657 AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \ 658 8000, \ 659 (99.9)*10, (99.9)*10, \ 660 0 \ 661 } 662 663 struct aim_icbmparameters { 664 fu16_t maxchan; 665 fu32_t flags; /* AIM_IMPARAM_FLAG_ */ 666 fu16_t maxmsglen; /* message size that you will accept */ 667 fu16_t maxsenderwarn; /* this and below are *10 (999=99.9%) */ 668 fu16_t maxrecverwarn; 669 fu32_t minmsginterval; /* in milliseconds? */ 670 }; 703 671 704 672 struct aim_chat_roominfo { 705 unsigned short exchange;673 fu16_t exchange; 706 674 char *name; 707 unsigned short instance;675 fu16_t instance; 708 676 }; 709 677 … … 717 685 #define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */ 718 686 #define AIM_IMFLAGS_EXTDATA 0x0100 719 #define AIM_IMFLAGS_ CUSTOMCHARSET 0x0200 /* charset fields set */687 #define AIM_IMFLAGS_X 0x0200 720 688 #define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */ 721 689 #define AIM_IMFLAGS_OFFLINE 0x0800 /* send to offline user */ … … 829 797 830 798 /* Valid values for channel 2 args->status */ 831 #define AIM_RENDEZVOUS_PROPOSE 832 #define AIM_RENDEZVOUS_CANCEL 833 #define AIM_RENDEZVOUS_ACCEPT 799 #define AIM_RENDEZVOUS_PROPOSE 0x0000 800 #define AIM_RENDEZVOUS_CANCEL 0x0001 801 #define AIM_RENDEZVOUS_ACCEPT 0x0002 834 802 835 803 struct aim_incomingim_ch2_args { 804 fu16_t status; 836 805 fu8_t cookie[8]; 837 fu16_t reqclass; 838 fu16_t status; 839 fu16_t errorcode; 806 int reqclass; 807 const char *proxyip; 840 808 const char *clientip; 841 const char *clientip2;842 809 const char *verifiedip; 843 810 fu16_t port; 811 fu16_t errorcode; 844 812 const char *msg; /* invite message or file description */ 845 813 const char *encoding; … … 871 839 872 840 /* Valid values for channel 4 args->type */ 873 #define AIM_ICQMSG_AUTHREQUEST 874 #define AIM_ICQMSG_AUTHDENIED 875 #define AIM_ICQMSG_AUTHGRANTED 841 #define AIM_ICQMSG_AUTHREQUEST 0x0006 842 #define AIM_ICQMSG_AUTHDENIED 0x0007 843 #define AIM_ICQMSG_AUTHGRANTED 0x0008 876 844 877 845 struct aim_incomingim_ch4_args { 878 846 fu32_t uin; /* Of the sender of the ICBM */ 879 fu16_t type; 847 fu8_t type; 848 fu8_t flags; 880 849 char *msg; /* Reason for auth request, deny, or accept */ 881 }; 882 883 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args); 884 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args); 885 faim_export int aim_send_im(aim_session_t *, const char *destsn, unsigned short flags, const char *msg); 886 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum); 887 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen); 888 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing); 889 faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg, int len, int encoding); 890 faim_export const char *aim_directim_getsn(aim_conn_t *conn); 891 faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, const char *destsn); 892 faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie); 893 894 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type); 895 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret); 896 faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message); 897 898 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2); 899 900 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn); 901 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size); 902 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, 903 const char *name, int filesdone, int numfiles, int size, 904 int totsize); 905 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn); 906 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn); 850 int msglen; 851 }; 852 853 /* SNAC sending functions */ 854 /* 0x0002 */ faim_export int aim_im_setparams(aim_session_t *sess, struct aim_icbmparameters *params); 855 /* 0x0004 */ faim_export int aim_im_reqparams(aim_session_t *sess); 856 /* 0x0006 */ faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args); 857 /* 0x0006 */ faim_export int aim_im_sendch1(aim_session_t *, const char *destsn, fu16_t flags, const char *msg); 858 /* 0x0006 */ faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum); 859 /* 0x0006 */ faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args); 860 /* 0x0006 */ faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port); 861 /* 0x0006 */ faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info); 862 /* 0x0006 */ faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *info); 863 /* 0x0006 */ faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info); 864 /* 0x0006 */ faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type); 865 /* 0x0006 */ faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message); 866 /* 0x0008 */ faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags); 867 /* 0x000b */ faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code); 868 /* 0x0014 */ faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2); 869 870 871 872 /* ft.c */ 873 struct aim_fileheader_t { 874 #if 0 875 char magic[4]; /* 0 */ 876 fu16_t hdrlen; /* 4 */ 877 fu16_t hdrtype; /* 6 */ 878 #endif 879 char bcookie[8]; /* 8 */ 880 fu16_t encrypt; /* 16 */ 881 fu16_t compress; /* 18 */ 882 fu16_t totfiles; /* 20 */ 883 fu16_t filesleft; /* 22 */ 884 fu16_t totparts; /* 24 */ 885 fu16_t partsleft; /* 26 */ 886 fu32_t totsize; /* 28 */ 887 fu32_t size; /* 32 */ 888 fu32_t modtime; /* 36 */ 889 fu32_t checksum; /* 40 */ 890 fu32_t rfrcsum; /* 44 */ 891 fu32_t rfsize; /* 48 */ 892 fu32_t cretime; /* 52 */ 893 fu32_t rfcsum; /* 56 */ 894 fu32_t nrecvd; /* 60 */ 895 fu32_t recvcsum; /* 64 */ 896 fu8_t idstring[32]; /* 68 */ 897 fu8_t flags; /* 100 */ 898 fu8_t lnameoffset; /* 101 */ 899 fu8_t lsizeoffset; /* 102 */ 900 char dummy[69]; /* 103 */ 901 char macfileinfo[16]; /* 172 */ 902 fu16_t nencode; /* 188 */ 903 fu16_t nlanguage; /* 190 */ 904 char name[64]; /* 192 */ 905 /* 256 */ 906 }; 907 908 struct aim_oft_info { 909 char cookie[8]; 910 char *sn; 911 char *proxyip; 912 char *clientip; 913 char *verifiedip; 914 fu16_t port; 915 aim_conn_t *conn; 916 aim_session_t *sess; 917 struct aim_fileheader_t fh; 918 struct aim_oft_info *next; 919 }; 920 921 faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck); 922 faim_export fu32_t aim_oft_checksum_file(char *filename); 923 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur); 924 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing); 925 faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg); 926 faim_export const char *aim_odc_getsn(aim_conn_t *conn); 927 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn); 928 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn); 929 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie); 930 931 faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename); 932 faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info); 933 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info); 934 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info); 935 936 907 937 908 938 /* info.c */ 909 #define AIM_CAPS_BUDDYICON 0x00000001 910 #define AIM_CAPS_VOICE 0x00000002 911 #define AIM_CAPS_IMIMAGE 0x00000004 912 #define AIM_CAPS_CHAT 0x00000008 913 #define AIM_CAPS_GETFILE 0x00000010 914 #define AIM_CAPS_SENDFILE 0x00000020 915 #define AIM_CAPS_GAMES 0x00000040 916 #define AIM_CAPS_SAVESTOCKS 0x00000080 917 #define AIM_CAPS_SENDBUDDYLIST 0x00000100 918 #define AIM_CAPS_GAMES2 0x00000200 919 #define AIM_CAPS_ICQ 0x00000400 920 #define AIM_CAPS_APINFO 0x00000800 939 /* 940 * AIM User Info, Standard Form. 941 */ 942 #define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */ 943 #define AIM_FLAG_ADMINISTRATOR 0x0002 944 #define AIM_FLAG_AOL 0x0004 945 #define AIM_FLAG_OSCAR_PAY 0x0008 946 #define AIM_FLAG_FREE 0x0010 947 #define AIM_FLAG_AWAY 0x0020 948 #define AIM_FLAG_ICQ 0x0040 949 #define AIM_FLAG_WIRELESS 0x0080 950 #define AIM_FLAG_UNKNOWN100 0x0100 951 #define AIM_FLAG_UNKNOWN200 0x0200 952 #define AIM_FLAG_ACTIVEBUDDY 0x0400 953 #define AIM_FLAG_UNKNOWN800 0x0800 954 #define AIM_FLAG_ABINTERNAL 0x1000 955 #define AIM_FLAG_ALLUSERS 0x001f 956 957 #define AIM_USERINFO_PRESENT_FLAGS 0x00000001 958 #define AIM_USERINFO_PRESENT_MEMBERSINCE 0x00000002 959 #define AIM_USERINFO_PRESENT_ONLINESINCE 0x00000004 960 #define AIM_USERINFO_PRESENT_IDLE 0x00000008 961 #define AIM_USERINFO_PRESENT_ICQEXTSTATUS 0x00000010 962 #define AIM_USERINFO_PRESENT_ICQIPADDR 0x00000020 963 #define AIM_USERINFO_PRESENT_ICQDATA 0x00000040 964 #define AIM_USERINFO_PRESENT_CAPABILITIES 0x00000080 965 #define AIM_USERINFO_PRESENT_SESSIONLEN 0x00000100 966 #define AIM_USERINFO_PRESENT_CREATETIME 0x00000200 967 968 typedef struct { 969 char sn[MAXSNLEN+1]; 970 fu16_t warnlevel; /* evil percent * 10 (999 = 99.9%) */ 971 fu16_t idletime; /* in seconds */ 972 fu16_t flags; 973 fu32_t createtime; /* time_t */ 974 fu32_t membersince; /* time_t */ 975 fu32_t onlinesince; /* time_t */ 976 fu32_t sessionlen; /* in seconds */ 977 fu32_t capabilities; 978 struct { 979 fu32_t status; 980 fu32_t ipaddr; 981 fu8_t crap[0x25]; /* until we figure it out... */ 982 } icqinfo; 983 fu32_t present; 984 fu16_t iconcsumlen; 985 fu8_t *iconcsum; 986 char *availmsg_encoding; 987 char *availmsg; 988 int availmsg_len; 989 } aim_userinfo_t; 990 991 faim_export const char *aim_userinfo_sn(aim_userinfo_t *ui); 992 faim_export fu16_t aim_userinfo_flags(aim_userinfo_t *ui); 993 faim_export fu16_t aim_userinfo_idle(aim_userinfo_t *ui); 994 faim_export float aim_userinfo_warnlevel(aim_userinfo_t *ui); 995 faim_export time_t aim_userinfo_createtime(aim_userinfo_t *ui); 996 faim_export time_t aim_userinfo_membersince(aim_userinfo_t *ui); 997 faim_export time_t aim_userinfo_onlinesince(aim_userinfo_t *ui); 998 faim_export fu32_t aim_userinfo_sessionlen(aim_userinfo_t *ui); 999 faim_export int aim_userinfo_hascap(aim_userinfo_t *ui, fu32_t cap); 1000 1001 #define AIM_CAPS_BUDDYICON 0x00000001 1002 #define AIM_CAPS_VOICE 0x00000002 1003 #define AIM_CAPS_DIRECTIM 0x00000004 1004 #define AIM_CAPS_CHAT 0x00000008 1005 #define AIM_CAPS_GETFILE 0x00000010 1006 #define AIM_CAPS_SENDFILE 0x00000020 1007 #define AIM_CAPS_GAMES 0x00000040 1008 #define AIM_CAPS_SAVESTOCKS 0x00000080 1009 #define AIM_CAPS_SENDBUDDYLIST 0x00000100 1010 #define AIM_CAPS_GAMES2 0x00000200 1011 #define AIM_CAPS_ICQ 0x00000400 1012 #define AIM_CAPS_APINFO 0x00000800 921 1013 #define AIM_CAPS_ICQRTF 0x00001000 922 1014 #define AIM_CAPS_EMPTY 0x00002000 923 #define AIM_CAPS_ICQSERVERRELAY 0x00004000 924 #define AIM_CAPS_ICQUNKNOWN 0x00008000 925 #define AIM_CAPS_TRILLIANCRYPT 0x00010000 926 #define AIM_CAPS_LAST 0x00020000 1015 #define AIM_CAPS_ICQSERVERRELAY 0x00004000 1016 #define AIM_CAPS_ICQUTF8OLD 0x00008000 1017 #define AIM_CAPS_TRILLIANCRYPT 0x00010000 1018 #define AIM_CAPS_ICQUTF8 0x00020000 1019 #define AIM_CAPS_INTEROPERATE 0x00040000 1020 #define AIM_CAPS_ICHAT 0x00080000 1021 #define AIM_CAPS_HIPTOP 0x00100000 1022 #define AIM_CAPS_SECUREIM 0x00200000 1023 #define AIM_CAPS_LAST 0x00400000 927 1024 928 1025 faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn); … … 931 1028 #define AIM_SENDMEMBLOCK_FLAG_ISHASH 1 932 1029 933 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned charflag);1030 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); 934 1031 935 1032 #define AIM_GETINFO_GENERALINFO 0x00001 … … 961 1058 #define AIM_COOKIETYPE_OFTICON 0x15 962 1059 963 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur); 964 965 #define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000 966 #define AIM_TRANSFER_DENY_DECLINE 0x0001 967 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 968 faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, unsigned short code); 969 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t port, fu16_t rendid, ...); 970 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn, 971 const char *cookie, const char *sn, int rendid); 972 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn, 973 const unsigned char *buffer, int bufferlen); 974 975 faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short); 976 faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info); 977 faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn); 978 979 #define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED 0x00000001 980 #define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED 0x00000002 981 982 /* This is what the server will give you if you don't set them yourself. */ 983 #define AIM_IMPARAM_DEFAULTS { \ 984 0, \ 985 AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \ 986 512, /* !! Note how small this is. */ \ 987 (99.9)*10, (99.9)*10, \ 988 1000 /* !! And how large this is. */ \ 989 } 990 991 /* This is what most AIM versions use. */ 992 #define AIM_IMPARAM_REASONABLE { \ 993 0, \ 994 AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \ 995 8000, \ 996 (99.9)*10, (99.9)*10, \ 997 0 \ 998 } 999 1000 1001 struct aim_icbmparameters { 1002 fu16_t maxchan; 1003 fu32_t flags; /* AIM_IMPARAM_FLAG_ */ 1004 fu16_t maxmsglen; /* message size that you will accept */ 1005 fu16_t maxsenderwarn; /* this and below are *10 (999=99.9%) */ 1006 fu16_t maxrecverwarn; 1007 fu32_t minmsginterval; /* in milliseconds? */ 1008 }; 1009 1010 faim_export int aim_reqicbmparams(aim_session_t *sess); 1011 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params); 1012 1013 1014 /* auth.c */ 1015 faim_export int aim_sendcookie(aim_session_t *, aim_conn_t *, const fu8_t *); 1016 1017 faim_export int aim_admin_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw); 1018 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn); 1019 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info); 1020 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail); 1021 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick); 1022 1023 /* buddylist.c */ 1024 faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *); 1025 faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *); 1026 1027 /* search.c */ 1028 faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *); 1029 1030 /* newsearch.c */ 1031 struct aim_usersearch { 1060 /* 0x0005 */ faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, fu16_t); 1061 1062 1063 1064 /* 0x0003 - buddylist.c */ 1065 /* 0x0004 */ faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *); 1066 /* 0x0005 */ faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *); 1067 /* 0x000b */ faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info); 1068 /* 0x000c */ faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn); 1069 1070 1071 1072 /* 0x000a - search.c */ 1073 faim_export int aim_search_address(aim_session_t *, aim_conn_t *, const char *); 1074 1075 1076 1077 /* 0x000d - chatnav.c */ 1078 /* 0x000e - chat.c */ 1079 /* These apply to exchanges as well. */ 1080 #define AIM_CHATROOM_FLAG_EVILABLE 0x0001 1081 #define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002 1082 #define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004 1083 #define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008 1084 1085 struct aim_chat_exchangeinfo { 1086 fu16_t number; 1087 fu16_t flags; 1088 char *name; 1089 char *charset1; 1090 char *lang1; 1091 char *charset2; 1092 char *lang2; 1093 }; 1094 1095 #define AIM_CHATFLAGS_NOREFLECT 0x0001 1096 #define AIM_CHATFLAGS_AWAY 0x0002 1097 faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen); 1098 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); 1099 faim_export int aim_chat_attachname(aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); 1100 faim_export char *aim_chat_getname(aim_conn_t *conn); 1101 faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name); 1102 1103 faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn); 1104 1105 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); 1106 1107 faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange); 1108 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name); 1109 1110 1111 1112 /* 0x000f - odir.c */ 1113 struct aim_odir { 1032 1114 char *first; 1033 1115 char *last; … … 1044 1126 char *region; 1045 1127 char *address; 1046 struct aim_usersearch *next; 1047 }; 1048 1049 faim_export int aim_usersearch_email(aim_session_t *, const char *, const char *); 1050 faim_export int aim_usersearch_name(aim_session_t *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); 1051 faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *); 1052 1053 1054 /* These apply to exchanges as well. */ 1055 #define AIM_CHATROOM_FLAG_EVILABLE 0x0001 1056 #define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002 1057 #define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004 1058 #define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008 1059 1060 struct aim_chat_exchangeinfo { 1061 fu16_t number; 1062 fu16_t flags; 1063 char *name; 1064 char *charset1; 1065 char *lang1; 1066 char *charset2; 1067 char *lang2; 1068 }; 1069 1070 #define AIM_CHATFLAGS_NOREFLECT 0x0001 1071 #define AIM_CHATFLAGS_AWAY 0x0002 1072 faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen); 1073 faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); 1074 faim_export int aim_chat_attachname(aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); 1075 faim_export char *aim_chat_getname(aim_conn_t *conn); 1076 faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name); 1077 1078 faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn); 1079 1080 faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance); 1081 1082 faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange); 1083 faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name); 1084 1085 1086 #define AIM_SSI_TYPE_BUDDY 0x0000 1087 #define AIM_SSI_TYPE_GROUP 0x0001 1088 #define AIM_SSI_TYPE_PERMIT 0x0002 1089 #define AIM_SSI_TYPE_DENY 0x0003 1090 #define AIM_SSI_TYPE_PDINFO 0x0004 1091 #define AIM_SSI_TYPE_PRESENCEPREFS 0x0005 1128 struct aim_odir *next; 1129 }; 1130 1131 faim_export int aim_odir_email(aim_session_t *, const char *, const char *); 1132 faim_export int aim_odir_name(aim_session_t *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); 1133 faim_export int aim_odir_interest(aim_session_t *, const char *, const char *); 1134 1135 1136 1137 /* 0x0010 - icon.c */ 1138 faim_export int aim_bart_upload(aim_session_t *sess, const fu8_t *icon, fu16_t iconlen); 1139 faim_export int aim_bart_request(aim_session_t *sess, const char *sn, const fu8_t *iconstr, fu16_t iconstrlen); 1140 1141 1142 1143 /* 0x0013 - ssi.c */ 1144 #define AIM_SSI_TYPE_BUDDY 0x0000 1145 #define AIM_SSI_TYPE_GROUP 0x0001 1146 #define AIM_SSI_TYPE_PERMIT 0x0002 1147 #define AIM_SSI_TYPE_DENY 0x0003 1148 #define AIM_SSI_TYPE_PDINFO 0x0004 1149 #define AIM_SSI_TYPE_PRESENCEPREFS 0x0005 1150 #define AIM_SSI_TYPE_ICONINFO 0x0014 1151 1152 #define AIM_SSI_ACK_SUCCESS 0x0000 1153 #define AIM_SSI_ACK_ITEMNOTFOUND 0x0002 1154 #define AIM_SSI_ACK_IDNUMINUSE 0x000a 1155 #define AIM_SSI_ACK_ATMAX 0x000c 1156 #define AIM_SSI_ACK_INVALIDNAME 0x000d 1157 #define AIM_SSI_ACK_AUTHREQUIRED 0x000e 1092 1158 1093 1159 struct aim_ssi_item { … … 1096 1162 fu16_t bid; 1097 1163 fu16_t type; 1098 void*data;1164 struct aim_tlvlist_s *data; 1099 1165 struct aim_ssi_item *next; 1100 1166 }; 1101 1167 1168 struct aim_ssi_tmp { 1169 fu16_t action; 1170 fu16_t ack; 1171 char *name; 1172 struct aim_ssi_item *item; 1173 struct aim_ssi_tmp *next; 1174 }; 1175 1102 1176 /* These build the actual SNACs and queue them to be sent */ 1103 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn); 1104 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev); 1105 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn); 1106 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype); 1107 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn); 1108 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn); 1109 1110 /* These handle the local variables */ 1177 /* 0x0002 */ faim_export int aim_ssi_reqrights(aim_session_t *sess); 1178 /* 0x0004 */ faim_export int aim_ssi_reqdata(aim_session_t *sess); 1179 /* 0x0005 */ faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t localstamp, fu16_t localrev); 1180 /* 0x0007 */ faim_export int aim_ssi_enable(aim_session_t *sess); 1181 /* 0x0008 */ faim_export int aim_ssi_addmoddel(aim_session_t *sess); 1182 /* 0x0011 */ faim_export int aim_ssi_modbegin(aim_session_t *sess); 1183 /* 0x0012 */ faim_export int aim_ssi_modend(aim_session_t *sess); 1184 /* 0x0014 */ faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg); 1185 /* 0x0018 */ faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg); 1186 /* 0x001a */ faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg); 1187 1188 /* Client functions for retrieving SSI data */ 1111 1189 faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid); 1112 1190 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); 1191 faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn); 1192 faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn); 1114 1193 faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list); 1115 1194 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); 1195 faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn); 1196 faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn); 1197 1198 /* Client functions for changing SSI data */ 1199 faim_export int aim_ssi_addbuddy(aim_session_t *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth); 1200 faim_export int aim_ssi_addpermit(aim_session_t *sess, const char *name); 1201 faim_export int aim_ssi_adddeny(aim_session_t *sess, const char *name); 1202 faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group); 1203 faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name); 1204 faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name); 1205 faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn); 1206 faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias); 1207 faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn); 1208 faim_export int aim_ssi_cleanlist(aim_session_t *sess); 1209 faim_export int aim_ssi_deletelist(aim_session_t *sess); 1210 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask); 1211 faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence); 1212 faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen); 1213 1214 1215 1216 /* 0x0015 - icq.c */ 1217 #define AIM_ICQ_INFO_SIMPLE 0x001 1218 #define AIM_ICQ_INFO_SUMMARY 0x002 1219 #define AIM_ICQ_INFO_EMAIL 0x004 1220 #define AIM_ICQ_INFO_PERSONAL 0x008 1221 #define AIM_ICQ_INFO_ADDITIONAL 0x010 1222 #define AIM_ICQ_INFO_WORK 0x020 1223 #define AIM_ICQ_INFO_INTERESTS 0x040 1224 #define AIM_ICQ_INFO_ORGS 0x080 1225 #define AIM_ICQ_INFO_UNKNOWN 0x100 1226 #define AIM_ICQ_INFO_HAVEALL 0x1ff 1130 1227 1131 1228 struct aim_icq_offlinemsg { … … 1133 1230 fu16_t year; 1134 1231 fu8_t month, day, hour, minute; 1135 fu16_t type; 1232 fu8_t type; 1233 fu8_t flags; 1136 1234 char *msg; 1137 }; 1138 1139 struct aim_icq_simpleinfo { 1235 int msglen; 1236 }; 1237 1238 struct aim_icq_info { 1239 fu16_t reqid; 1240 1241 /* simple */ 1140 1242 fu32_t uin; 1243 1244 /* general and "home" information (0x00c8) */ 1141 1245 char *nick; 1142 1246 char *first; 1143 1247 char *last; 1144 1248 char *email; 1249 char *homecity; 1250 char *homestate; 1251 char *homephone; 1252 char *homefax; 1253 char *homeaddr; 1254 char *mobile; 1255 char *homezip; 1256 fu16_t homecountry; 1257 /* fu8_t timezone; 1258 fu8_t hideemail; */ 1259 1260 /* personal (0x00dc) */ 1261 fu8_t age; 1262 fu8_t unknown; 1263 fu8_t gender; 1264 char *personalwebpage; 1265 fu16_t birthyear; 1266 fu8_t birthmonth; 1267 fu8_t birthday; 1268 fu8_t language1; 1269 fu8_t language2; 1270 fu8_t language3; 1271 1272 /* work (0x00d2) */ 1273 char *workcity; 1274 char *workstate; 1275 char *workphone; 1276 char *workfax; 1277 char *workaddr; 1278 char *workzip; 1279 fu16_t workcountry; 1280 char *workcompany; 1281 char *workdivision; 1282 char *workposition; 1283 char *workwebpage; 1284 1285 /* additional personal information (0x00e6) */ 1286 char *info; 1287 1288 /* email (0x00eb) */ 1289 fu16_t numaddresses; 1290 char **email2; 1291 1292 /* we keep track of these in a linked list because we're 1337 */ 1293 struct aim_icq_info *next; 1145 1294 }; 1146 1295 1147 1296 faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess); 1148 1297 faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess); 1298 faim_export int aim_icq_hideip(aim_session_t *sess); 1299 faim_export int aim_icq_changepasswd(aim_session_t *sess, const char *passwd); 1149 1300 faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin); 1150 1151 /* email.c */ 1301 faim_export int aim_icq_getalias(aim_session_t *sess, const char *uin); 1302 faim_export int aim_icq_getallinfo(aim_session_t *sess, const char *uin); 1303 1304 1305 1306 /* 0x0017 - auth.c */ 1307 faim_export int aim_sendcookie(aim_session_t *, aim_conn_t *, const fu16_t length, const fu8_t *); 1308 faim_export int aim_admin_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw); 1309 faim_export int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn); 1310 faim_export int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info); 1311 faim_export int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail); 1312 faim_export int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick); 1313 1314 1315 1316 /* 0x0018 - email.c */ 1152 1317 struct aim_emailinfo { 1153 1318 fu8_t *cookie16; … … 1164 1329 faim_export int aim_email_activate(aim_session_t *sess, aim_conn_t *conn); 1165 1330 1331 1332 1333 /* tlv.c - TLV handling */ 1334 #if defined(FAIM_INTERNAL) || defined(FAIM_NEED_TLV) 1335 /* Generic TLV structure. */ 1336 typedef struct aim_tlv_s { 1337 fu16_t type; 1338 fu16_t length; 1339 fu8_t *value; 1340 } aim_tlv_t; 1341 1342 /* List of above. */ 1343 typedef struct aim_tlvlist_s { 1344 aim_tlv_t *tlv; 1345 struct aim_tlvlist_s *next; 1346 } aim_tlvlist_t; 1347 1348 /* TLV-handling functions */ 1349 1350 #if 0 1351 /* Very, very raw TLV handling. */ 1352 faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v); 1353 faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v); 1354 faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v); 1355 faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v); 1356 #endif 1357 1358 /* TLV list handling. */ 1359 faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs); 1360 faim_internal aim_tlvlist_t *aim_readtlvchain_num(aim_bstream_t *bs, fu16_t num); 1361 faim_internal aim_tlvlist_t *aim_readtlvchain_len(aim_bstream_t *bs, fu16_t len); 1362 faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig); 1363 faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two); 1364 faim_internal void aim_freetlvchain(aim_tlvlist_t **list); 1365 faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n); 1366 faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n); 1367 faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num); 1368 faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n); 1369 faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n); 1370 faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list); 1371 faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v); 1372 faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v); 1373 faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v); 1374 faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v); 1375 faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu32_t caps); 1376 faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type); 1377 faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *ui); 1378 faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl); 1379 faim_internal int aim_counttlvchain(aim_tlvlist_t **list); 1380 faim_internal int aim_sizetlvchain(aim_tlvlist_t **list); 1381 #endif /* FAIM_INTERNAL */ 1382 1383 1384 1166 1385 /* util.c */ 1167 1386 /* … … 1172 1391 * 1173 1392 */ 1174 #define aimutil_put8(buf, data) ((*(buf) = ( u_char)(data)&0xff),1)1393 #define aimutil_put8(buf, data) ((*(buf) = (fu8_t)(data)&0xff),1) 1175 1394 #define aimutil_get8(buf) ((*(buf))&0xff) 1176 1395 #define aimutil_put16(buf, data) ( \ 1177 (*(buf) = ( u_char)((data)>>8)&0xff), \1178 (*((buf)+1) = ( u_char)(data)&0xff), \1396 (*(buf) = (fu8_t)((data)>>8)&0xff), \ 1397 (*((buf)+1) = (fu8_t)(data)&0xff), \ 1179 1398 2) 1180 1399 #define aimutil_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff)) 1181 1400 #define aimutil_put32(buf, data) ( \ 1182 (*((buf)) = ( u_char)((data)>>24)&0xff), \1183 (*((buf)+1) = ( u_char)((data)>>16)&0xff), \1184 (*((buf)+2) = ( u_char)((data)>>8)&0xff), \1185 (*((buf)+3) = ( u_char)(data)&0xff), \1401 (*((buf)) = (fu8_t)((data)>>24)&0xff), \ 1402 (*((buf)+1) = (fu8_t)((data)>>16)&0xff), \ 1403 (*((buf)+2) = (fu8_t)((data)>>8)&0xff), \ 1404 (*((buf)+3) = (fu8_t)(data)&0xff), \ 1186 1405 4) 1187 1406 #define aimutil_get32(buf) ((((*(buf))<<24)&0xff000000) + \ … … 1192 1411 /* Little-endian versions (damn ICQ) */ 1193 1412 #define aimutil_putle8(buf, data) ( \ 1194 (*(buf) = ( unsigned char)(data) & 0xff), \1413 (*(buf) = (fu8_t)(data) & 0xff), \ 1195 1414 1) 1196 1415 #define aimutil_getle8(buf) ( \ … … 1198 1417 ) 1199 1418 #define aimutil_putle16(buf, data) ( \ 1200 (*((buf)+0) = ( unsigned char)((data) >> 0) & 0xff), \1201 (*((buf)+1) = ( unsigned char)((data) >> 8) & 0xff), \1419 (*((buf)+0) = (fu8_t)((data) >> 0) & 0xff), \ 1420 (*((buf)+1) = (fu8_t)((data) >> 8) & 0xff), \ 1202 1421 2) 1203 1422 #define aimutil_getle16(buf) ( \ … … 1206 1425 ) 1207 1426 #define aimutil_putle32(buf, data) ( \ 1208 (*((buf)+0) = ( unsigned char)((data) >> 0) & 0xff), \1209 (*((buf)+1) = ( unsigned char)((data) >> 8) & 0xff), \1210 (*((buf)+2) = ( unsigned char)((data) >> 16) & 0xff), \1211 (*((buf)+3) = ( unsigned char)((data) >> 24) & 0xff), \1427 (*((buf)+0) = (fu8_t)((data) >> 0) & 0xff), \ 1428 (*((buf)+1) = (fu8_t)((data) >> 8) & 0xff), \ 1429 (*((buf)+2) = (fu8_t)((data) >> 16) & 0xff), \ 1430 (*((buf)+3) = (fu8_t)((data) >> 24) & 0xff), \ 1212 1431 4) 1213 1432 #define aimutil_getle32(buf) ( \ … … 1218 1437 1219 1438 1220 faim_export int aimutil_putstr(u_char *, const char *, int); 1221 faim_export int aimutil_tokslen(char *toSearch, int index, char dl); 1439 faim_export int aimutil_putstr(char *, const char *, int); 1440 faim_export fu16_t aimutil_iconsum(const fu8_t *buf, int buflen); 1441 faim_export int aim_util_getlocalip(fu8_t *ip); 1442 faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl); 1222 1443 faim_export int aimutil_itemcnt(char *toSearch, char dl); 1223 faim_export char *aimutil_itemi dx(char *toSearch, intindex, char dl);1444 faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl); 1224 1445 1225 1446 faim_export int aim_snlen(const char *sn); 1226 1447 faim_export int aim_sncmp(const char *sn1, const char *sn2); 1227 1448 1228 /* for libc's that dont have it */1229 faim_export char *aim_strsep(char **pp, const char *delim);1230 1231 /* meta.c */1232 faim_export char *aim_getbuilddate(void);1233 faim_export char *aim_getbuildtime(void);1234 faim_export int aim_getbuildstring(char *buf, int buflen);1235 1236 1449 #include <aim_internal.h> 1237 1450 1451 #ifdef __cplusplus 1452 } 1453 #endif 1454 1238 1455 #endif /* __AIM_H__ */ 1239 -
libfaim/aim_cbtypes.h
r862371b re374dee 25 25 #define AIM_CB_FAM_CHT 0x000e /* Chat */ 26 26 #define AIM_CB_FAM_SCH 0x000f /* "New" search */ 27 #define AIM_CB_FAM_ICO 0x0010 /* Used for uploading buddy icons */ 27 28 #define AIM_CB_FAM_SSI 0x0013 /* Server stored information */ 28 29 #define AIM_CB_FAM_ICQ 0x0015 … … 179 180 /* 180 181 * SNAC Family: "New" Search 181 *182 * Most of these are actually special.183 182 */ 184 183 #define AIM_CB_SCH_ERROR 0x0001 … … 187 186 188 187 /* 188 * SNAC Family: Buddy icons 189 */ 190 #define AIM_CB_ICO_ERROR 0x0001 191 #define AIM_CB_ICO_REQUEST 0x0004 192 #define AIM_CB_ICO_RESPONSE 0x0005 193 194 /* 189 195 * SNAC Family: ICQ 190 196 * … … 194 200 #define AIM_CB_ICQ_OFFLINEMSG 0x00f0 195 201 #define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1 196 #define AIM_CB_ICQ_SIMPLEINFO 0x00f2 202 #define AIM_CB_ICQ_INFO 0x00f2 203 #define AIM_CB_ICQ_ALIAS 0x00f3 197 204 #define AIM_CB_ICQ_DEFAULT 0xffff 198 205 … … 203 210 #define AIM_CB_SSI_REQRIGHTS 0x0002 204 211 #define AIM_CB_SSI_RIGHTSINFO 0x0003 205 #define AIM_CB_SSI_REQLIST 0x0005 212 #define AIM_CB_SSI_REQDATA 0x0004 213 #define AIM_CB_SSI_REQIFCHANGED 0x0005 206 214 #define AIM_CB_SSI_LIST 0x0006 207 215 #define AIM_CB_SSI_ACTIVATE 0x0007 … … 213 221 #define AIM_CB_SSI_EDITSTART 0x0011 214 222 #define AIM_CB_SSI_EDITSTOP 0x0012 223 #define AIM_CB_SSI_SENDAUTH 0x0014 224 #define AIM_CB_SSI_RECVAUTH 0x0015 225 #define AIM_CB_SSI_SENDAUTHREQ 0x0018 226 #define AIM_CB_SSI_RECVAUTHREQ 0x0019 227 #define AIM_CB_SSI_SENDAUTHREP 0x001a 228 #define AIM_CB_SSI_RECVAUTHREP 0x001b 229 #define AIM_CB_SSI_ADDED 0x001c 215 230 216 231 /* … … 241 256 * OFT Services 242 257 * 243 * See non-SNAC note below. 244 */ 245 #define AIM_CB_OFT_DIRECTIMCONNECTREQ 0x0001/* connect request -- actually an OSCAR CAP*/ 258 * For all of the above #defines, the number is the subtype 259 * of the SNAC. For OFT #defines, the number is the 260 * "hdrtype" which comes after the magic string and OFT 261 * packet length. 262 * 263 * I'm pretty sure the ODC ones are arbitrary right now, 264 * that should be changed. 265 */ 266 #define AIM_CB_OFT_DIRECTIMCONNECTREQ 0x0001 /* connect request -- actually an OSCAR CAP */ 246 267 #define AIM_CB_OFT_DIRECTIMINCOMING 0x0002 247 268 #define AIM_CB_OFT_DIRECTIMDISCONNECT 0x0003 248 269 #define AIM_CB_OFT_DIRECTIMTYPING 0x0004 249 #define AIM_CB_OFT_DIRECTIMINITIATE 0x0005 250 251 /* had been removed, put back by kretch */ 252 #define AIM_CB_OFT_GETFILECONNECTREQ 0x0006 /* connect request -- actually an OSCAR CAP*/ 253 #define AIM_CB_OFT_GETFILELISTINGREQ 0x0007 /* OFT listing.txt request */ 254 #define AIM_CB_OFT_GETFILEFILEREQ 0x0008 /* received file request */ 255 #define AIM_CB_OFT_GETFILEFILESEND 0x0009 /* received file request confirm -- send data */ 256 #define AIM_CB_OFT_GETFILECOMPLETE 0x000a /* received file send complete*/ 257 #define AIM_CB_OFT_GETFILEINITIATE 0x000b /* request for file get acknowledge */ 258 #define AIM_CB_OFT_GETFILEDISCONNECT 0x000c /* OFT connection disconnected.*/ 259 #define AIM_CB_OFT_GETFILELISTING 0x000d /* OFT listing.txt received.*/ 260 #define AIM_CB_OFT_GETFILERECEIVE 0x000e /* OFT file incoming.*/ 261 #define AIM_CB_OFT_GETFILELISTINGRXCONFIRM 0x000f 262 #define AIM_CB_OFT_GETFILESTATE4 0x0010 263 264 #define AIM_CB_OFT_SENDFILEFILEREQ 0x0011 /* started receiving file */ 265 #define AIM_CB_OFT_SENDFILEFILESEND 0x0012 /* buddy ready to for us to send */ 266 #define AIM_CB_OFT_SENDFILECOMPLETE 0x0013 /* send to buddy complete */ 267 #define AIM_CB_OFT_SENDFILEINITIATE 0x0014 /* connection to buddy initiated */ 268 270 #define AIM_CB_OFT_DIRECTIM_ESTABLISHED 0x0005 271 272 #define AIM_CB_OFT_PROMPT 0x0101 /* "I am going to send you this file, is that ok?" */ 273 #define AIM_CB_OFT_RESUMESOMETHING 0x0106 /* I really don't know */ 274 #define AIM_CB_OFT_ACK 0x0202 /* "Yes, it is ok for you to send me that file" */ 275 #define AIM_CB_OFT_DONE 0x0204 /* "I received that file with no problems, thanks a bunch" */ 276 #define AIM_CB_OFT_RESUME 0x0205 /* Resume transferring, sent by whoever paused? */ 277 #define AIM_CB_OFT_RESUMEACK 0x0207 /* Not really sure */ 278 279 #define AIM_CB_OFT_GETFILE_REQUESTLISTING 0x1108 /* "I have a listing.txt file, do you want it?" */ 280 #define AIM_CB_OFT_GETFILE_RECEIVELISTING 0x1209 /* "Yes, please send me your listing.txt file" */ 281 #define AIM_CB_OFT_GETFILE_RECEIVEDLISTING 0x120a /* received corrupt listing.txt file? */ /* I'm just guessing about this one... */ 282 #define AIM_CB_OFT_GETFILE_ACKLISTING 0x120b /* "I received the listing.txt file successfully" */ 283 #define AIM_CB_OFT_GETFILE_REQUESTFILE 0x120c /* "Please send me this file" */ 284 285 #define AIM_CB_OFT_ESTABLISHED 0xFFFF /* connection to buddy initiated */ 269 286 270 287 /* … … 282 299 #define AIM_CB_SPECIAL_FLAPVER 0x0005 283 300 #define AIM_CB_SPECIAL_CONNINITDONE 0x0006 284 #define AIM_CB_SPECIAL_IMAGETRANSFER 0x007 285 #define AIM_CB_SPECIAL_MSGTIMEOUT 0x008 301 #define AIM_CB_SPECIAL_IMAGETRANSFER 0x0007 302 #define AIM_CB_SPECIAL_MSGTIMEOUT 0x0008 303 #define AIM_CB_SPECIAL_CONNDEAD 0x0009 286 304 #define AIM_CB_SPECIAL_UNKNOWN 0xffff 287 305 #define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN -
libfaim/aim_internal.h
r862371b re374dee 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 28 void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod); … … 37 36 faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name); 38 37 38 faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod); 39 39 faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod); 40 faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod);41 40 faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod); 42 41 faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod); … … 49 48 faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod); 50 49 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod); 51 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);52 50 faim_internal int invite_modfirst(aim_session_t *sess, aim_module_t *mod); 53 51 faim_internal int translate_modfirst(aim_session_t *sess, aim_module_t *mod); 54 52 faim_internal int popups_modfirst(aim_session_t *sess, aim_module_t *mod); 55 53 faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod); 54 faim_internal int odir_modfirst(aim_session_t *sess, aim_module_t *mod); 55 faim_internal int bart_modfirst(aim_session_t *sess, aim_module_t *mod); 56 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod); 56 57 faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod); 57 58 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);59 59 60 60 faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); … … 97 97 98 98 /* rxhandlers.c */ 99 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type);99 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type); 100 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 101 faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...); … … 130 130 } aim_snac_t; 131 131 132 struct aim_snac_destructor {133 aim_conn_t *conn;134 void *data;135 };136 137 132 /* snac.c */ 138 133 faim_internal void aim_initsnachash(aim_session_t *sess); … … 140 135 faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen); 141 136 faim_internal aim_snac_t *aim_remsnac(aim_session_t *, aim_snacid_t id); 142 faim_internal void aim_cleansnacs(aim_session_t *, int maxage);143 137 faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id); 144 138 … … 148 142 char name[128]; 149 143 fu16_t instance; 150 };151 152 /* these are used by aim_*_clientready */153 #define AIM_TOOL_JAVA 0x0001154 #define AIM_TOOL_MAC 0x0002155 #define AIM_TOOL_WIN16 0x0003156 #define AIM_TOOL_WIN32 0x0004157 #define AIM_TOOL_MAC68K 0x0005158 #define AIM_TOOL_MACPPC 0x0006159 #define AIM_TOOL_NEWWIN 0x0010160 struct aim_tool_version {161 fu16_t group;162 fu16_t version;163 fu16_t tool;164 fu16_t toolversion;165 144 }; 166 145 … … 221 200 faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie); 222 201 223 faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *); 202 faim_internal void aim_info_free(aim_userinfo_t *); 203 faim_internal int aim_info_extract(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *); 224 204 faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info); 225 205 … … 227 207 228 208 faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...); 229 230 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret);231 faim_internal int aim_request_sendfile(aim_session_t *sess, const char *sn, const char *filename, fu16_t numfiles, fu32_t totsize, fu8_t *ip, fu16_t port, fu8_t *ckret);232 faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn);233 faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn);234 209 235 210 faim_internal void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn); -
libfaim/auth.c
r862371b re374dee 8 8 9 9 #define FAIM_INTERNAL 10 #include <aim.h> 10 #include <aim.h> 11 11 12 12 #include "md5.h" 13 13 14 static int aim_encode_password(const char *password, unsigned char*encoded);14 static int aim_encode_password(const char *password, fu8_t *encoded); 15 15 16 16 /* … … 22 22 * 23 23 */ 24 faim_export int aim_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu 8_t *chipsahoy)24 faim_export int aim_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu16_t length, const fu8_t *chipsahoy) 25 25 { 26 26 aim_frame_t *fr; 27 27 aim_tlvlist_t *tl = NULL; 28 28 29 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+ AIM_COOKIELEN)))29 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+length))) 30 30 return -ENOMEM; 31 31 32 32 aimbs_put32(&fr->data, 0x00000001); 33 aim_addtlvtochain_raw(&tl, 0x0006, AIM_COOKIELEN, chipsahoy);33 aim_addtlvtochain_raw(&tl, 0x0006, length, chipsahoy); 34 34 aim_writetlvchain(&fr->data, &tl); 35 35 aim_freetlvchain(&tl); … … 157 157 aim_frame_t *fr; 158 158 aim_tlvlist_t *tl = NULL; 159 char *password_encoded; 160 161 if (!(password_encoded = (char *) malloc(strlen(password)))) 159 int passwdlen; 160 fu8_t *password_encoded; 161 162 passwdlen = strlen(password); 163 if (!(password_encoded = (char *)malloc(passwdlen+1))) 162 164 return -ENOMEM; 165 if (passwdlen > MAXICQPASSLEN) 166 passwdlen = MAXICQPASSLEN; 163 167 164 168 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) { … … 171 175 aimbs_put32(&fr->data, 0x00000001); /* FLAP Version */ 172 176 aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); 173 aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded);177 aim_addtlvtochain_raw(&tl, 0x0002, passwdlen, password_encoded); 174 178 175 179 if (ci->clientstring) … … 180 184 aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point); 181 185 aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build); 182 aim_addtlvtochain32(&tl, 0x0014, 0x00000055); /* distribution chan */186 aim_addtlvtochain32(&tl, 0x0014, (fu32_t)ci->distrib); /* distribution chan */ 183 187 aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang); 184 188 aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country); … … 202 206 * then the client information you send here must exactly match the 203 207 * executable that you're pulling the data from. 204 *205 * WinAIM 4.8.2540206 * clientstring = "AOL Instant Messenger (SM), version 4.8.2540/WIN32"207 * clientid = 0x0109208 * major = 0x0004209 * minor = 0x0008210 * point = 0x0000211 * build = 0x09ec212 * t(0x0014) = 0x000000af213 * t(0x004a) = 0x01214 *215 * WinAIM 4.3.2188:216 * clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"217 * clientid = 0x0109218 * major = 0x0400219 * minor = 0x0003220 * point = 0x0000221 * build = 0x088c222 * unknown = 0x00000086223 * lang = "en"224 * country = "us"225 * unknown4a = 0x01226 *227 * Latest WinAIM that libfaim can emulate without server-side buddylists:228 * clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32"229 * clientid = 0x0004230 * major = 0x0004231 * minor = 0x0001232 * point = 0x0000233 * build = 0x07da234 * unknown= 0x0000004b235 *236 * WinAIM 3.5.1670:237 * clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32"238 * clientid = 0x0004239 * major = 0x0003240 * minor = 0x0005241 * point = 0x0000242 * build = 0x0686243 * unknown =0x0000002a244 208 * 245 209 * Java AIM 1.1.19: … … 304 268 aim_addtlvtochain16(&tl, 0x0019, (fu16_t)ci->point); 305 269 aim_addtlvtochain16(&tl, 0x001a, (fu16_t)ci->build); 270 aim_addtlvtochain32(&tl, 0x0014, (fu32_t)ci->distrib); 306 271 aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), ci->country); 307 272 aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), ci->lang); 308 273 274 #ifndef NOSSI 309 275 /* 310 276 * If set, old-fashioned buddy lists will not work. You will need … … 312 278 */ 313 279 aim_addtlvtochain8(&tl, 0x004a, 0x01); 280 #endif 314 281 315 282 aim_writetlvchain(&fr->data, &tl); … … 388 355 aim_tlvlist_t *tlvlist; 389 356 aim_rxcallback_t userfunc; 390 struct aim_authresp_info info;357 struct aim_authresp_info *info; 391 358 int ret = 0; 392 359 393 memset(&info, 0, sizeof(info)); 360 info = (struct aim_authresp_info *)malloc(sizeof(struct aim_authresp_info)); 361 memset(info, 0, sizeof(struct aim_authresp_info)); 394 362 395 363 /* … … 404 372 memset(sess->sn, 0, sizeof(sess->sn)); 405 373 if (aim_gettlv(tlvlist, 0x0001, 1)) { 406 info .sn = aim_gettlv_str(tlvlist, 0x0001, 1);407 strncpy(sess->sn, info .sn, sizeof(sess->sn));374 info->sn = aim_gettlv_str(tlvlist, 0x0001, 1); 375 strncpy(sess->sn, info->sn, sizeof(sess->sn)); 408 376 } 409 377 … … 413 381 */ 414 382 if (aim_gettlv(tlvlist, 0x0008, 1)) 415 info .errorcode = aim_gettlv16(tlvlist, 0x0008, 1);383 info->errorcode = aim_gettlv16(tlvlist, 0x0008, 1); 416 384 if (aim_gettlv(tlvlist, 0x0004, 1)) 417 info .errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);385 info->errorurl = aim_gettlv_str(tlvlist, 0x0004, 1); 418 386 419 387 /* … … 421 389 */ 422 390 if (aim_gettlv(tlvlist, 0x0005, 1)) 423 info .bosip = aim_gettlv_str(tlvlist, 0x0005, 1);391 info->bosip = aim_gettlv_str(tlvlist, 0x0005, 1); 424 392 425 393 /* … … 431 399 tmptlv = aim_gettlv(tlvlist, 0x0006, 1); 432 400 433 info.cookie = tmptlv->value; 401 info->cookielen = tmptlv->length; 402 info->cookie = tmptlv->value; 434 403 } 435 404 436 405 /* 437 406 * The email address attached to this account 438 * Not available for ICQ logins. 407 * Not available for ICQ or @mac.com logins. 408 * If you receive this TLV, then you are allowed to use 409 * family 0x0018 to check the status of your email. 410 * XXX - Not really true! 439 411 */ 440 412 if (aim_gettlv(tlvlist, 0x0011, 1)) 441 info .email = aim_gettlv_str(tlvlist, 0x0011, 1);413 info->email = aim_gettlv_str(tlvlist, 0x0011, 1); 442 414 443 415 /* 444 416 * The registration status. (Not real sure what it means.) 445 * Not available for ICQ logins.417 * Not available for ICQ or @mac.com logins. 446 418 * 447 419 * 1 = No disclosure … … 452 424 * to other users or not. AFAIK, this feature is no longer used. 453 425 * 426 * Means you can use the admin family? (0x0007) 427 * 454 428 */ 455 429 if (aim_gettlv(tlvlist, 0x0013, 1)) 456 info .regstatus = aim_gettlv16(tlvlist, 0x0013, 1);430 info->regstatus = aim_gettlv16(tlvlist, 0x0013, 1); 457 431 458 432 if (aim_gettlv(tlvlist, 0x0040, 1)) 459 info .latestbeta.build = aim_gettlv32(tlvlist, 0x0040, 1);433 info->latestbeta.build = aim_gettlv32(tlvlist, 0x0040, 1); 460 434 if (aim_gettlv(tlvlist, 0x0041, 1)) 461 info .latestbeta.url = aim_gettlv_str(tlvlist, 0x0041, 1);435 info->latestbeta.url = aim_gettlv_str(tlvlist, 0x0041, 1); 462 436 if (aim_gettlv(tlvlist, 0x0042, 1)) 463 info .latestbeta.info = aim_gettlv_str(tlvlist, 0x0042, 1);437 info->latestbeta.info = aim_gettlv_str(tlvlist, 0x0042, 1); 464 438 if (aim_gettlv(tlvlist, 0x0043, 1)) 465 info .latestbeta.name = aim_gettlv_str(tlvlist, 0x0043, 1);439 info->latestbeta.name = aim_gettlv_str(tlvlist, 0x0043, 1); 466 440 if (aim_gettlv(tlvlist, 0x0048, 1)) 467 441 ; /* no idea what this is */ 468 442 469 443 if (aim_gettlv(tlvlist, 0x0044, 1)) 470 info .latestrelease.build = aim_gettlv32(tlvlist, 0x0044, 1);444 info->latestrelease.build = aim_gettlv32(tlvlist, 0x0044, 1); 471 445 if (aim_gettlv(tlvlist, 0x0045, 1)) 472 info .latestrelease.url = aim_gettlv_str(tlvlist, 0x0045, 1);446 info->latestrelease.url = aim_gettlv_str(tlvlist, 0x0045, 1); 473 447 if (aim_gettlv(tlvlist, 0x0046, 1)) 474 info .latestrelease.info = aim_gettlv_str(tlvlist, 0x0046, 1);448 info->latestrelease.info = aim_gettlv_str(tlvlist, 0x0046, 1); 475 449 if (aim_gettlv(tlvlist, 0x0047, 1)) 476 info .latestrelease.name = aim_gettlv_str(tlvlist, 0x0047, 1);450 info->latestrelease.name = aim_gettlv_str(tlvlist, 0x0047, 1); 477 451 if (aim_gettlv(tlvlist, 0x0049, 1)) 478 452 ; /* no idea what this is */ … … 482 456 */ 483 457 if (aim_gettlv(tlvlist, 0x0054, 1)) 484 info.chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1); 458 info->chpassurl = aim_gettlv_str(tlvlist, 0x0054, 1); 459 460 /* 461 * Unknown. Seen on an @mac.com screen name with value of 0x003f 462 */ 463 if (aim_gettlv(tlvlist, 0x0055, 1)) 464 ; 465 466 sess->authinfo = info; 485 467 486 468 if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) 487 ret = userfunc(sess, rx, &info); 488 489 free(info.sn); 490 free(info.bosip); 491 free(info.errorurl); 492 free(info.email); 493 free(info.chpassurl); 494 free(info.latestrelease.name); 495 free(info.latestrelease.url); 496 free(info.latestrelease.info); 497 free(info.latestbeta.name); 498 free(info.latestbeta.url); 499 free(info.latestbeta.info); 469 ret = userfunc(sess, rx, info); 500 470 501 471 aim_freetlvchain(&tlvlist); … … 520 490 keystr = aimbs_getstr(bs, keylen); 521 491 492 /* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register 493 * for the netscape network. This SNAC had a type 0x0058 TLV with length 10. 494 * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */ 495 522 496 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 523 497 ret = userfunc(sess, rx, keystr); … … 526 500 527 501 return ret; 502 } 503 504 static void auth_shutdown(aim_session_t *sess, aim_module_t *mod) 505 { 506 if (sess->authinfo) { 507 free(sess->authinfo->sn); 508 free(sess->authinfo->bosip); 509 free(sess->authinfo->errorurl); 510 free(sess->authinfo->email); 511 free(sess->authinfo->chpassurl); 512 free(sess->authinfo->latestrelease.name); 513 free(sess->authinfo->latestrelease.url); 514 free(sess->authinfo->latestrelease.info); 515 free(sess->authinfo->latestbeta.name); 516 free(sess->authinfo->latestbeta.url); 517 free(sess->authinfo->latestbeta.info); 518 free(sess->authinfo); 519 } 528 520 } 529 521 … … 547 539 strncpy(mod->name, "auth", sizeof(mod->name)); 548 540 mod->snachandler = snachandler; 549 550 return 0; 551 } 541 mod->shutdown = auth_shutdown; 542 543 return 0; 544 } -
libfaim/bos.c
r862371b re374dee 2 2 * Family 0x0009 - Basic Oscar Service. 3 3 * 4 * The functionality of this family has been replaced by SSI. 4 5 */ 5 6 6 7 #define FAIM_INTERNAL 7 8 #include <aim.h> 9 10 #include <string.h> 8 11 9 12 /* Subtype 0x0002 - Request BOS rights. */ … … 127 130 128 131 for (i = 0; (i < (listcount - 1)) && (i < 99); i++) { 129 tmpptr = aimutil_itemi dx(localcpy, i, '&');132 tmpptr = aimutil_itemindex(localcpy, i, '&'); 130 133 131 134 aimbs_put8(&fr->data, strlen(tmpptr)); … … 156 159 mod->version = 0x0001; 157 160 mod->toolid = 0x0110; 158 mod->toolversion = 0x0 47b;161 mod->toolversion = 0x0629; 159 162 mod->flags = 0; 160 163 strncpy(mod->name, "bos", sizeof(mod->name)); -
libfaim/bstream.c
r862371b re374dee 231 231 return NULL; 232 232 } 233 233 234 234 ob[len] = '\0'; 235 235 -
libfaim/buddylist.c
r862371b re374dee 6 6 #define FAIM_INTERNAL 7 7 #include <aim.h> 8 9 #include <string.h> 8 10 9 11 /* … … 233 235 * 234 236 * Oncoming Buddy notifications contain a subset of the 235 * user information structure. It s close enough to run236 * through aim_ extractuserinfo() however.237 * user information structure. It's close enough to run 238 * through aim_info_extract() however. 237 239 * 238 240 * Although the offgoing notification contains no information, 239 * it is still in a format parsable by extractuserinfo.241 * it is still in a format parsable by aim_info_extract(). 240 242 * 241 243 */ 242 244 static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 243 245 { 246 int ret = 0; 244 247 aim_userinfo_t userinfo; 245 248 aim_rxcallback_t userfunc; 246 249 247 aim_ extractuserinfo(sess, bs, &userinfo);250 aim_info_extract(sess, bs, &userinfo); 248 251 249 252 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 250 return userfunc(sess, rx, &userinfo); 251 252 return 0; 253 ret = userfunc(sess, rx, &userinfo); 254 255 aim_info_free(&userinfo); 256 257 return ret; 253 258 } 254 259 … … 270 275 mod->version = 0x0001; 271 276 mod->toolid = 0x0110; 272 mod->toolversion = 0x0 47b;277 mod->toolversion = 0x0629; 273 278 mod->flags = 0; 274 279 strncpy(mod->name, "buddylist", sizeof(mod->name)); -
libfaim/chat.c
r862371b re374dee 6 6 #define FAIM_INTERNAL 7 7 #include <aim.h> 8 9 #include <string.h> 8 10 9 11 /* Stored in the ->priv of chat connections */ … … 205 207 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 206 208 207 208 209 /* 209 210 * Cookie 210 211 */ 211 for (i = 0; i < sizeof(ckstr); i++)212 aimutil_put8(ckstr, (fu8_t) rand());212 for (i = 0; i < 8; i++) 213 ckstr[i] = (fu8_t)rand(); 213 214 214 215 /* XXX should be uncached by an unwritten 'invite accept' handler */ … … 225 226 free(priv); 226 227 227 for (i = 0; i < sizeof(ckstr); i++) 228 aimbs_put8(&fr->data, ckstr[i]); 229 230 231 /* 232 * Channel (2) 233 */ 234 aimbs_put16(&fr->data, 0x0002); 235 236 /* 237 * Dest sn 238 */ 239 aimbs_put8(&fr->data, strlen(sn)); 240 aimbs_putraw(&fr->data, sn, strlen(sn)); 228 /* ICBM Header */ 229 aimbs_putraw(&fr->data, ckstr, 8); /* Cookie */ 230 aimbs_put16(&fr->data, 0x0002); /* Channel */ 231 aimbs_put8(&fr->data, strlen(sn)); /* Screename length */ 232 aimbs_putraw(&fr->data, sn, strlen(sn)); /* Screenname */ 241 233 242 234 /* … … 346 338 347 339 while (curoccupant < usercount) 348 aim_ extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);340 aim_info_extract(sess, &occbs, &userinfo[curoccupant++]); 349 341 } 350 342 … … 424 416 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { 425 417 ret = userfunc(sess, 426 rx, 418 rx, 427 419 &roominfo, 428 420 roomname, 429 421 usercount, 430 userinfo, 422 userinfo, 431 423 roomdesc, 432 424 flags, … … 439 431 440 432 free(roominfo.name); 433 434 while (usercount > 0) 435 aim_info_free(&userinfo[--usercount]); 436 441 437 free(userinfo); 442 438 free(roomname); … … 457 453 curcount++; 458 454 userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t)); 459 aim_ extractuserinfo(sess, bs, &userinfo[curcount-1]);455 aim_info_extract(sess, bs, &userinfo[curcount-1]); 460 456 } 461 457 … … 463 459 ret = userfunc(sess, rx, curcount, userinfo); 464 460 461 aim_info_free(userinfo); 465 462 free(userinfo); 466 463 … … 498 495 aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid); 499 496 500 501 /* 502 * Generate a random message cookie. 497 /* 498 * Cookie 503 499 * 504 500 * XXX mkcookie should generate the cookie and cache it in one 505 501 * operation to preserve uniqueness. 506 * 507 */ 508 for (i = 0; i < sizeof(ckstr); i++) 509 aimutil_put8(ckstr+i, (fu8_t) rand()); 502 */ 503 for (i = 0; i < 8; i++) 504 ckstr[i] = (fu8_t)rand(); 510 505 511 506 cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL); … … 514 509 aim_cachecookie(sess, cookie); 515 510 516 for (i = 0; i < sizeof(ckstr); i++) 517 aimbs_put8(&fr->data, ckstr[i]); 518 519 520 /* 521 * Channel ID. 522 */ 523 aimbs_put16(&fr->data, 0x0003); 524 511 /* ICBM Header */ 512 aimbs_putraw(&fr->data, ckstr, 8); /* Cookie */ 513 aimbs_put16(&fr->data, 0x0003); /* Channel */ 525 514 526 515 /* … … 544 533 * SubTLV: Type 1: Message 545 534 */ 546 aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg);535 aim_addtlvtochain_raw(&itl, 0x0001, msglen, msg); 547 536 548 537 /* … … 644 633 645 634 aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length); 646 aim_ extractuserinfo(sess, &tbs, &userinfo);635 aim_info_extract(sess, &tbs, &userinfo); 647 636 } 648 637 … … 678 667 ret = userfunc(sess, rx, &userinfo, msg); 679 668 669 aim_info_free(&userinfo); 680 670 free(cookie); 681 671 free(msg); … … 703 693 mod->family = 0x000e; 704 694 mod->version = 0x0001; 705 mod->toolid = 0x00 04; /* XXX this doesn't look right */706 mod->toolversion = 0x0 001; /* nor does this */695 mod->toolid = 0x0010; 696 mod->toolversion = 0x0629; 707 697 mod->flags = 0; 708 698 strncpy(mod->name, "chat", sizeof(mod->name)); -
libfaim/chatnav.c
r862371b re374dee 424 424 425 425 mod->family = 0x000d; 426 mod->version = 0x000 3;426 mod->version = 0x0001; 427 427 mod->toolid = 0x0010; 428 mod->toolversion = 0x0 47c;428 mod->toolversion = 0x0629; 429 429 mod->flags = 0; 430 430 strncpy(mod->name, "chatnav", sizeof(mod->name)); -
libfaim/configure
r5e53c4a re374dee 747 747 748 748 if test "$GCC" = yes; then 749 CFLAGS="$CFLAGS -Wall ";749 CFLAGS="$CFLAGS -Wall -g"; 750 750 fi 751 751 # Extract the first word of "ranlib", so it can be a program name with args. -
libfaim/configure.in
r5e53c4a re374dee 6 6 dnl we're using GCC, enable all warnings 7 7 if test "$GCC" = yes; then 8 CFLAGS="$CFLAGS -Wall ";8 CFLAGS="$CFLAGS -Wall -g"; 9 9 fi 10 10 AC_PROG_RANLIB -
libfaim/conn.c
r862371b re374dee 173 173 * This will free ->internal if it necessary... 174 174 */ 175 if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS) 176 aim_conn_kill_rend(sess, *deadconn); 177 else if ((*deadconn)->type == AIM_CONN_TYPE_CHAT) 175 if ((*deadconn)->type == AIM_CONN_TYPE_CHAT) 178 176 aim_conn_kill_chat(sess, *deadconn); 179 177 … … 319 317 faim_export void aim_conn_close(aim_conn_t *deadconn) 320 318 { 319 aim_rxcallback_t userfunc; 321 320 322 321 if (deadconn->fd >= 3) 323 322 close(deadconn->fd); 323 324 324 deadconn->fd = -1; 325 326 if ((userfunc = aim_callhandler(deadconn->sessv, deadconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNDEAD))) 327 userfunc(deadconn->sessv, NULL, deadconn); 328 325 329 if (deadconn->handlerlist) 326 330 aim_clearhandlers(deadconn); 327 if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS)328 aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn);329 331 330 332 return; … … 871 873 aim_initsnachash(sess); 872 874 sess->msgcookies = NULL; 875 sess->icq_info = NULL; 876 sess->oft_info = NULL; 873 877 sess->snacid_next = 0x00000001; 874 878 … … 880 884 881 885 sess->ssi.received_data = 0; 886 sess->ssi.numitems = 0; 887 sess->ssi.official = NULL; 888 sess->ssi.local = NULL; 889 sess->ssi.pending = NULL; 890 sess->ssi.timestamp = (time_t)0; 882 891 sess->ssi.waiting_for_ack = 0; 883 sess->ssi.holding_queue = NULL; 884 sess->ssi.revision = 0; 885 sess->ssi.items = NULL; 886 sess->ssi.timestamp = (time_t)0; 887 892 893 sess->authinfo = NULL; 888 894 sess->emailinfo = NULL; 889 895 … … 920 926 aim__registermodule(sess, chatnav_modfirst); 921 927 aim__registermodule(sess, chat_modfirst); 922 aim__registermodule(sess, newsearch_modfirst); 923 /* missing 0x10 - 0x12 */ 928 /* aim__registermodule(sess, odir_modfirst); */ /* kretch */ 929 /* aim__registermodule(sess, bart_modfirst); */ /* kretch */ 930 /* missing 0x11 - 0x12 */ 924 931 aim__registermodule(sess, ssi_modfirst); 925 932 /* missing 0x14 */ … … 992 999 faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn) 993 1000 { 994 fd_set fds, wfds;995 struct timeval tv;996 int res;997 int error = ETIMEDOUT;998 999 1001 aim_rxcallback_t userfunc; 1000 1002 … … 1005 1007 return -1; 1006 1008 1007 FD_ZERO(&fds); 1008 FD_SET(conn->fd, &fds); 1009 FD_ZERO(&wfds); 1010 FD_SET(conn->fd, &wfds); 1011 tv.tv_sec = 0; 1012 tv.tv_usec = 0; 1013 1014 if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { 1015 error = errno; 1016 aim_conn_close(conn); 1017 errno = error; 1018 return -1; 1019 } else if (res == 0) { 1020 faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); 1021 return 0; /* hasn't really completed yet... */ 1022 } 1023 1024 if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { 1025 int len = sizeof(error); 1026 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) 1027 error = errno; 1028 } 1029 1030 if (error) { 1031 aim_conn_close(conn); 1032 errno = error; 1033 return -1; 1034 } 1035 fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ 1009 fcntl(conn->fd, F_SETFL, 0); 1036 1010 1037 1011 conn->status &= ~AIM_CONN_STATUS_INPROGRESS; -
libfaim/email.c
r862371b re374dee 63 63 /** 64 64 * Subtype 0x0007 - Receive information about your email account 65 * 65 66 * So I don't even know if you can have multiple 16 byte keys, 66 67 * but this is coded so it will handle that, and handle it well. … … 74 75 static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 75 76 { 77 int ret = 0; 76 78 aim_rxcallback_t userfunc; 77 79 struct aim_emailinfo *new; … … 125 127 126 128 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 127 return userfunc(sess, rx, new, havenewmail); 128 129 return 0; 129 ret = userfunc(sess, rx, new, havenewmail); 130 131 aim_freetlvchain(&tlvlist); 132 133 return ret; 130 134 } 131 135 -
libfaim/ft.c
r862371b re374dee 1 1 /* 2 * File transfer (OFT) and DirectIM (ODC). 3 * (OSCAR File Transfer, Oscar Direct Connect(ion?) 2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC). 3 * (ODC is also referred to as DirectIM and IM Image.) 4 * 5 * There are a few static helper functions at the top, then 6 * ODC stuff, then ft stuff. 7 * 8 * I feel like this is a good place to explain OFT, so I'm going to 9 * do just that. Each OFT packet has a header type. I guess this 10 * is pretty similar to the subtype of a SNAC packet. The type 11 * basically tells the other client the meaning of the OFT packet. 12 * There are two distinct types of file transfer, which I usually 13 * call "sendfile" and "getfile." Sendfile is when you send a file 14 * to another AIM user. Getfile is when you share a group of files, 15 * and other users request that you send them the files. 16 * 17 * A typical sendfile file transfer goes like this: 18 * 1) Sender sends a channel 2 ICBM telling the other user that 19 * we want to send them a file. At the same time, we open a 20 * listener socket (this should be done before sending the 21 * ICBM) on some port, and wait for them to connect to us. 22 * The ICBM we sent should contain our IP address and the port 23 * number that we're listening on. 24 * 2) The receiver connects to the sender on the given IP address 25 * and port. After the connection is established, the receiver 26 * sends an ICBM signifying that we are ready and waiting. 27 * 3) The sender sends an OFT PROMPT message over the OFT 28 * connection. 29 * 4) The receiver of the file sends back an exact copy of this 30 * OFT packet, except the cookie is filled in with the cookie 31 * from the ICBM. I think this might be an attempt to verify 32 * that the user that is connected is actually the guy that 33 * we sent the ICBM to. Oh, I've been calling this the ACK. 34 * 5) The sender starts sending raw data across the connection 35 * until the entire file has been sent. 36 * 6) The receiver knows the file is finished because the sender 37 * sent the file size in an earlier OFT packet. So then the 38 * receiver sends the DONE thingy (after filling in the 39 * "received" checksum and size) and closes the connection. 4 40 */ 5 41 6 42 #define FAIM_INTERNAL 7 8 43 #ifdef HAVE_CONFIG_H 9 #include <config.h>44 #include <config.h> 10 45 #endif 46 11 47 #include <aim.h> 12 48 13 49 #ifndef _WIN32 50 #include <stdio.h> 14 51 #include <netdb.h> 15 52 #include <sys/socket.h> 16 53 #include <netinet/in.h> 17 #include <sys/utsname.h> /* for aim_ directim_initiate */54 #include <sys/utsname.h> /* for aim_odc_initiate */ 18 55 #include <arpa/inet.h> /* for inet_ntoa */ 19 56 #define G_DIR_SEPARATOR '/' … … 24 61 #endif 25 62 26 #define AIM_OFT_PROTO_OFFER 0x0101 27 #define AIM_OFT_PROTO_ACCEPT 0x0202 28 #define AIM_OFT_PROTO_RESUME 0x0205 29 #define AIM_OFT_PROTO_RESUMEACCEPT 0x0207 30 #define AIM_OFT_PROTO_ACK 0x0204 31 32 struct aim_filetransfer_priv { 33 char sn[MAXSNLEN+1]; 34 char cookie[8]; 35 char ip[30]; 36 int state; 37 struct aim_fileheader_t fh; 38 }; 39 40 struct aim_directim_intdata { 63 struct aim_odc_intdata { 41 64 fu8_t cookie[8]; 42 65 char sn[MAXSNLEN+1]; … … 44 67 }; 45 68 46 static int listenestablish(fu16_t portnum); 47 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs); 48 static void oft_dirconvert(char *name); 49 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh); 50 51 /** 52 * aim_handlerendconnect - call this to accept OFT connections and set up the required structures 53 * @sess: the session 54 * @cur: the conn the incoming connection is on 55 * 56 * call this when you get an outstanding read on a conn with subtype 57 * AIM_CONN_SUBTYPE_RENDEZVOUS_OUT, it will clone the current 58 * &aim_conn_t and tweak things as appropriate. the new conn and the 59 * listener conn are both returned to the client in the 60 * %AIM_CB_FAM_OFT, %AIM_CB_OFT_<CLASS>INITIATE callback. 61 */ 62 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) 63 { 64 int acceptfd = 0; 65 struct sockaddr cliaddr; 66 int clilen = sizeof(cliaddr); 67 int ret = 0; 68 aim_conn_t *newconn; 69 70 if ((acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1) 71 return 0; /* not an error */ 72 73 if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ 74 close(acceptfd); 75 aim_conn_close(cur); 76 return -1; 77 } 78 79 if (!(newconn = aim_cloneconn(sess, cur))) { 80 close(acceptfd); 81 aim_conn_close(cur); 82 return -1; 83 } 84 85 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; 86 newconn->fd = acceptfd; 87 88 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 89 struct aim_directim_intdata *priv; 90 aim_rxcallback_t userfunc; 91 92 priv = (struct aim_directim_intdata *)(newconn->internal = cur->internal); 93 cur->internal = NULL; 94 95 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", 96 inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), 97 ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); 98 99 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE))) 100 ret = userfunc(sess, NULL, newconn, cur); 101 102 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 103 #if 0 104 struct aim_filetransfer_priv *priv; 105 aim_rxcallback_t userfunc; 106 107 newconn->priv = cur->priv; 108 cur->priv = NULL; 109 priv = (struct aim_filetransfer_priv *)newconn->priv; 110 111 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); 112 113 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE))) 114 ret = userfunc(sess, NULL, newconn, cur); 115 #endif 116 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { 117 struct aim_filetransfer_priv *ft; 118 aim_rxcallback_t userfunc; 119 120 /* The new conn automatically inherits the internal value 121 * of cur. */ 122 cur->internal = NULL; 123 ft = (struct aim_filetransfer_priv *)newconn->internal; 124 125 snprintf(ft->ip, sizeof(ft->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); 126 127 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEINITIATE))) 128 ret = userfunc(sess, NULL, newconn, cur); 129 } else { 130 faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n"); 131 aim_conn_close(newconn); 132 ret = -1; 133 } 134 135 return ret; 136 } 137 138 /** 139 * aim_send_typing - send client-to-client typing notification over established connection 140 * @sess: session to conn 141 * @conn: directim connection 142 * @typing: If true, notify user has started typing; if false, notify user has stopped. 143 * 144 * The connection must have been previously established. 145 */ 146 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) 147 { 148 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 149 aim_frame_t *fr; 150 aim_bstream_t *hdrbs; 151 fu8_t *hdr; 152 int hdrlen = 0x44; 153 154 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 155 return -EINVAL; 156 157 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) 158 return -ENOMEM; 159 memcpy(fr->hdr.rend.magic, "ODC2", 4); 160 fr->hdr.rend.hdrlen = hdrlen; 161 162 if (!(hdr = calloc(1, hdrlen))) { 163 aim_frame_destroy(fr); 164 return -ENOMEM; 165 } 166 167 hdrbs = &(fr->data); 168 aim_bstream_init(hdrbs, hdr, hdrlen); 169 170 aimbs_put16(hdrbs, 0x0006); 171 aimbs_put16(hdrbs, 0x0000); 172 aimbs_putraw(hdrbs, intdata->cookie, 8); 173 aimbs_put16(hdrbs, 0x0000); 174 aimbs_put16(hdrbs, 0x0000); 175 aimbs_put16(hdrbs, 0x0000); 176 aimbs_put16(hdrbs, 0x0000); 177 aimbs_put32(hdrbs, 0x00000000); 178 aimbs_put16(hdrbs, 0x0000); 179 aimbs_put16(hdrbs, 0x0000); 180 aimbs_put16(hdrbs, 0x0000); 181 182 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */ 183 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002)); 184 185 aimbs_put16(hdrbs, 0x0000); 186 aimbs_put16(hdrbs, 0x0000); 187 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 188 189 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 190 191 aimbs_put8(hdrbs, 0x00); 192 aimbs_put16(hdrbs, 0x0000); 193 aimbs_put16(hdrbs, 0x0000); 194 aimbs_put16(hdrbs, 0x0000); 195 aimbs_put16(hdrbs, 0x0000); 196 aimbs_put16(hdrbs, 0x0000); 197 aimbs_put16(hdrbs, 0x0000); 198 aimbs_put16(hdrbs, 0x0000); 199 aimbs_put8(hdrbs, 0x00); 200 201 /* end of hdr */ 202 203 aim_tx_enqueue(sess, fr); 204 205 return 0; 206 } 207 208 /** 209 * aim_send_im_direct - send IM client-to-client over established connection 210 * @sess: session to conn 211 * @conn: directim connection 212 * @msg: null-terminated string to send. 213 * @len: The length of the message to send, including binary data. 214 * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1 215 * 216 * Call this just like you would aim_send_im, to send a directim. You 217 * _must_ have previously established the directim connection. 218 */ 219 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding) 220 { 221 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 222 aim_frame_t *fr; 223 aim_bstream_t *hdrbs; 224 int hdrlen = 0x44; 225 fu8_t *hdr; 226 227 if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 228 return -EINVAL; 229 230 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len))) 231 return -ENOMEM; 232 233 memcpy(fr->hdr.rend.magic, "ODC2", 4); 234 fr->hdr.rend.hdrlen = hdrlen; 235 236 if (!(hdr = calloc(1, hdrlen + len))) { 237 aim_frame_destroy(fr); 238 return -ENOMEM; 239 } 240 241 hdrbs = &(fr->data); 242 aim_bstream_init(hdrbs, hdr, hdrlen + len); 243 244 aimbs_put16(hdrbs, 0x0006); 245 aimbs_put16(hdrbs, 0x0000); 246 aimbs_putraw(hdrbs, intdata->cookie, 8); 247 aimbs_put16(hdrbs, 0x0000); 248 aimbs_put16(hdrbs, 0x0000); 249 aimbs_put16(hdrbs, 0x0000); 250 aimbs_put16(hdrbs, 0x0000); 251 aimbs_put32(hdrbs, len); 252 aimbs_put16(hdrbs, encoding); 253 aimbs_put16(hdrbs, 0x0000); 254 aimbs_put16(hdrbs, 0x0000); 255 256 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */ 257 aimbs_put16(hdrbs, 0x0000); 258 259 aimbs_put16(hdrbs, 0x0000); 260 aimbs_put16(hdrbs, 0x0000); 261 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 262 263 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 264 265 aimbs_put8(hdrbs, 0x00); 266 aimbs_put16(hdrbs, 0x0000); 267 aimbs_put16(hdrbs, 0x0000); 268 aimbs_put16(hdrbs, 0x0000); 269 aimbs_put16(hdrbs, 0x0000); 270 aimbs_put16(hdrbs, 0x0000); 271 aimbs_put16(hdrbs, 0x0000); 272 aimbs_put16(hdrbs, 0x0000); 273 aimbs_put8(hdrbs, 0x00); 274 275 /* end of hdr2 */ 276 277 #if 0 /* XXX this is how you send buddy icon info... */ 278 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); 279 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c); 280 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); 281 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466); 282 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); 283 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); 284 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); 285 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8); 286 #endif 287 aimbs_putraw(hdrbs, msg, len); 288 289 aim_tx_enqueue(sess, fr); 290 291 return 0; 292 } 293 294 static int getlocalip(fu8_t *ip) 295 { 296 struct hostent *hptr; 297 char localhost[129]; 298 299 /* XXX if available, use getaddrinfo() */ 300 /* XXX allow client to specify which IP to use for multihomed boxes */ 301 302 if (gethostname(localhost, 128) < 0) 303 return -1; 304 305 if (!(hptr = gethostbyname(localhost))) 306 return -1; 307 308 memcpy(ip, hptr->h_addr_list[0], 4); 309 310 return 0; 311 } 312 313 /** 314 * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves. 315 * @sess: your session, 316 * @conn: the BOS conn, 317 * @priv: a dummy priv value (we'll let it get filled in later) (if you pass a %NULL, we alloc one) 318 * @destsn: the SN to connect to. 319 * 320 */ 321 faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, const char *destsn) 322 { 323 aim_conn_t *newconn; 324 aim_msgcookie_t *cookie; 325 struct aim_directim_intdata *priv; 326 int listenfd; 327 fu16_t port = 4443; 328 fu8_t localip[4]; 329 fu8_t ck[8]; 330 331 if (getlocalip(localip) == -1) 332 return NULL; 333 334 if ((listenfd = listenestablish(port)) == -1) 335 return NULL; 336 337 aim_request_directim(sess, destsn, localip, port, ck); 338 339 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); 340 memcpy(cookie->cookie, ck, 8); 341 cookie->type = AIM_COOKIETYPE_OFTIM; 342 343 /* this one is for the cookie */ 344 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); 345 346 memcpy(priv->cookie, ck, 8); 347 strncpy(priv->sn, destsn, sizeof(priv->sn)); 348 cookie->data = priv; 349 aim_cachecookie(sess, cookie); 350 351 /* XXX switch to aim_cloneconn()? */ 352 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { 353 close(listenfd); 354 return NULL; 355 } 356 357 /* this one is for the conn */ 358 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); 359 360 memcpy(priv->cookie, ck, 8); 361 strncpy(priv->sn, destsn, sizeof(priv->sn)); 362 363 newconn->fd = listenfd; 364 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; 365 newconn->internal = priv; 366 newconn->lastactivity = time(NULL); 367 368 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); 369 370 return newconn; 371 } 372 373 /** 374 * aim_sendfile_intitiate - For those times when we want to send the file ourselves. 375 * @sess: your session, 376 * @conn: the BOS conn, 377 * @destsn: the SN to connect to. 378 * @filename: the name of the files you want to send 379 * 380 */ 381 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret) 382 { 383 aim_conn_t *newconn; 384 aim_msgcookie_t *cookie; 385 struct aim_filetransfer_priv *ft; 386 int listenfd; 387 388 /* XXX allow different ports */ 389 fu16_t port = 4443; 390 fu8_t localip[4]; 391 fu8_t ck[8]; 392 393 if (getlocalip(localip) == -1) 394 return NULL; 395 396 if ((listenfd = listenestablish(port)) == -1) 397 return NULL; 398 399 aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck); 400 401 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); 402 memcpy(cookie->cookie, ck, 8); 403 cookie->type = AIM_COOKIETYPE_OFTSEND; 404 memcpy(cookret, ck, 8); 405 406 /* this one is for the cookie */ 407 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 408 409 memcpy(ft->cookie, ck, 8); 410 strncpy(ft->sn, destsn, sizeof(ft->sn)); 411 cookie->data = ft; 412 aim_cachecookie(sess, cookie); 413 414 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { 415 close(listenfd); 416 return NULL; 417 } 418 419 /* this one is for the conn */ 420 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 421 422 memcpy(ft->cookie, ck, 8); 423 strncpy(ft->sn, destsn, sizeof(ft->sn)); 424 425 newconn->fd = listenfd; 426 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 427 newconn->internal = ft; 428 newconn->lastactivity = time(NULL); 429 430 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); 431 432 return newconn; 433 } 434 435 #if 0 436 /** 437 * unsigned int aim_oft_listener_clean - close up old listeners 438 * @sess: session to clean up in 439 * @age: maximum age in seconds 440 * 441 * returns number closed, -1 on error. 442 */ 443 faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age) 444 { 445 aim_conn_t *cur; 446 time_t now; 447 unsigned int hit = 0; 448 449 if (!sess) 450 return -1; 451 now = time(NULL); 452 453 for(cur = sess->connlist;cur; cur = cur->next) 454 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 455 if (cur->lastactivity < (now - age) ) { 456 aim_conn_close(cur); 457 hit++; 458 } 459 } 460 return hit; 461 } 462 #endif 463 464 faim_export const char *aim_directim_getsn(aim_conn_t *conn) 465 { 466 struct aim_directim_intdata *intdata; 467 468 if (!conn) 469 return NULL; 470 471 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 472 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) 473 return NULL; 474 475 if (!conn->internal) 476 return NULL; 477 478 intdata = (struct aim_directim_intdata *)conn->internal; 479 480 return intdata->sn; 481 } 482 483 /** 484 * aim_directim_connect - connect to buddy for directim 485 * @sess: the session to append the conn to, 486 * @sn: the SN we're connecting to 487 * @addr: address to connect to 488 * 489 * This is a wrapper for aim_newconn. 490 * 491 * If addr is NULL, the socket is not created, but the connection is 492 * allocated and setup to connect. 493 * 494 */ 495 faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) 496 { 497 aim_conn_t *newconn; 498 struct aim_directim_intdata *intdata; 499 500 if (!sess || !sn) 501 return NULL; 502 503 if (!(intdata = malloc(sizeof(struct aim_directim_intdata)))) 504 return NULL; 505 memset(intdata, 0, sizeof(struct aim_directim_intdata)); 506 507 memcpy(intdata->cookie, cookie, 8); 508 strncpy(intdata->sn, sn, sizeof(intdata->sn)); 509 if (addr) 510 strncpy(intdata->ip, addr, sizeof(intdata->ip)); 511 512 /* XXX verify that non-blocking connects actually work */ 513 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { 514 free(intdata); 515 return NULL; 516 } 517 518 if (!newconn) { 519 free(intdata); 520 return newconn; 521 } 522 523 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; 524 newconn->internal = intdata; 525 526 return newconn; 527 } 528 529 /** 530 * aim_directim_getconn - find a directim conn for buddy name 531 * @sess: your session, 532 * @name: the name to get, 533 * 534 * returns conn for directim with name, %NULL if none found. 535 * 536 */ 537 faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name) 538 { 539 aim_conn_t *cur; 540 541 if (!sess || !name || !strlen(name)) 542 return NULL; 543 544 for (cur = sess->connlist; cur; cur = cur->next) { 545 struct aim_directim_intdata *intdata; 546 547 if ((cur->type != AIM_CONN_TYPE_RENDEZVOUS) || (cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) 548 continue; 549 550 intdata = cur->internal; 551 552 if (aim_sncmp(intdata->sn, name) == 0) 553 break; 554 } 555 556 return cur; 557 } 558 559 /** 560 * aim_accepttransfer - accept a file transfer request 561 * @sess: the session, 562 * @conn: the BOS conn for the CAP reply 563 * @sn: the screenname to send it to, 564 * @cookie: the cookie used 565 * @ip: the ip to connect to 566 * @port: the port to use 567 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) 568 * 569 * @listingfiles: number of files to share 570 * @listingtotsize: total size of shared files 571 * @listingsize: length of the listing file(buffer) 572 * @listingchecksum: checksum of the listing 573 * 574 * Returns new connection or %NULL on error. 575 * 576 * XXX this should take a struct. 577 */ 578 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, 579 const fu8_t *cookie, const fu8_t *ip, 580 fu16_t port, fu16_t rendid, ...) 581 { 582 aim_frame_t *newpacket; 583 aim_conn_t *newconn; 584 struct aim_filetransfer_priv *priv; 69 /** 70 * Convert the directory separator from / (0x2f) to ^A (0x01) 71 * 72 * @param name The filename to convert. 73 */ 74 static void aim_oft_dirconvert_tostupid(char *name) 75 { 76 while (name[0]) { 77 if (name[0] == 0x01) 78 name[0] = G_DIR_SEPARATOR; 79 name++; 80 } 81 } 82 83 /** 84 * Convert the directory separator from ^A (0x01) to / (0x2f) 85 * 86 * @param name The filename to convert. 87 */ 88 static void aim_oft_dirconvert_fromstupid(char *name) 89 { 90 while (name[0]) { 91 if (name[0] == G_DIR_SEPARATOR) 92 name[0] = 0x01; 93 name++; 94 } 95 } 96 97 /** 98 * Calculate oft checksum of buffer 99 * 100 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The 101 * checksum is kind of a rolling checksum thing, so each time you get bytes 102 * of a file you just call this puppy and it updates the checksum. You can 103 * calculate the checksum of an entire file by calling this in a while or a 104 * for loop, or something. 105 * 106 * Thanks to Graham Booker for providing this improved checksum routine, 107 * which is simpler and should be more accurate than Josh Myer's original 108 * code. -- wtm 109 * 110 * This algorithim works every time I have tried it. The other fails 111 * sometimes. So, AOL who thought this up? It has got to be the weirdest 112 * checksum I have ever seen. 113 * 114 * @param buffer Buffer of data to checksum. Man I'd like to buff her... 115 * @param bufsize Size of buffer. 116 * @param prevcheck Previous checksum. 117 */ 118 faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck) 119 { 120 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck; 585 121 int i; 586 char addr[21]; 587 588 if (!sess || !conn || !sn || !cookie || !ip) { 589 return NULL; 590 } 591 592 /* OSCAR CAP accept packet */ 593 594 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 595 return NULL; 596 } 597 598 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 599 600 for (i = 0; i < 8; i++) 601 aimbs_put8(&newpacket->data, cookie[i]); 602 603 aimbs_put16(&newpacket->data, 0x0002); 604 aimbs_put8(&newpacket->data, strlen(sn)); 605 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 606 aimbs_put16(&newpacket->data, 0x0005); 607 aimbs_put16(&newpacket->data, 0x001a); 608 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT); 609 610 for (i = 0; i < 8; i++) /* yes, again... */ 611 aimbs_put8(&newpacket->data, cookie[i]); 612 613 aim_putcap(&newpacket->data, rendid); 614 aim_tx_enqueue(sess, newpacket); 615 616 snprintf(addr, sizeof(addr), "%s:%d", ip, port); 617 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr); 618 619 if (newconn->status & AIM_CONN_STATUS_CONNERR) { 620 return NULL; 621 } 622 623 if (!newconn || (newconn->fd == -1)) { 624 perror("aim_newconn"); 625 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0); 626 return newconn; 627 } 628 629 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 630 631 memcpy(priv->cookie, cookie, 8); 632 priv->state = 0; 633 strncpy(priv->sn, sn, MAXSNLEN); 634 strncpy(priv->ip, ip, sizeof(priv->ip)); 635 newconn->internal = (void *)priv; 636 637 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd); 638 639 if (rendid == AIM_CAPS_GETFILE) { 640 return NULL; /* This should never happen for now. -- wtm */ 641 642 #if 0 643 struct aim_fileheader_t *fh; 644 aim_frame_t *newoft; 645 aim_msgcookie_t *cachedcook; 646 /* XXX take the following parameters fu16_t listingfiles, 647 fu16_t listingtotsize, 648 fu16_t listingsize, 649 fu32_t listingchecksum, */ 650 651 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 652 653 faimdprintf(sess, 2, "faim: getfile request accept\n"); 654 655 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 656 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 657 /* XXX: conn leak here */ 658 return NULL; 659 } 660 661 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 662 newoft->hdr.oft.hdr2len = 0x100 - 8; 663 664 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) { 665 /* XXX: conn leak here */ 666 perror("calloc"); 667 return NULL; 668 } 669 670 fh->encrypt = 0x0000; 671 fh->compress = 0x0000; 672 fh->totfiles = listingfiles; 673 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/ 674 fh->totparts = 0x0001; 675 fh->partsleft = 0x0001; 676 fh->totsize = listingtotsize; 677 fh->size = listingsize; /* ls -l listing.txt */ 678 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 679 fh->checksum = listingchecksum; 680 fh->rfcsum = 0x00000000; 681 fh->rfsize = 0x00000000; 682 fh->cretime = 0x00000000; 683 fh->rfcsum = 0x00000000; 684 fh->nrecvd = 0x00000000; 685 fh->recvcsum = 0x00000000; 686 memset(fh->idstring, 0, sizeof(fh->idstring)); 687 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 688 fh->flags = 0x02; 689 fh->lnameoffset = 0x1a; 690 fh->lsizeoffset = 0x10; 691 memset(fh->dummy, 0, sizeof(fh->dummy)); 692 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 693 694 /* we need to figure out these encodings for filenames */ 695 fh->nencode = 0x0000; 696 fh->nlanguage = 0x0000; 697 memset(fh->name, 0, sizeof(fh->name)); 698 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 699 700 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 701 aim_frame_destroy(newoft); 702 /* XXX: conn leak */ 703 perror("calloc (1)"); 704 return NULL; 705 } 706 707 memcpy(fh->bcookie, cookie, 8); 708 709 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh))) 710 faimdprintf(sess, 1, "eek, bh fail!\n"); 711 712 aim_tx_enqueue(sess, newoft); 713 714 if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { 715 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n"); 716 /* XXX: more cleanup, conn leak */ 717 perror("calloc (2)"); 718 return NULL; 719 } 720 721 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t)); 722 memcpy(cachedcook->cookie, cookie, 8); 723 724 cachedcook->type = AIM_COOKIETYPE_OFTGET; 725 /* XXX doesn't priv need to be copied so we don't 726 * double free? -- wtm 727 */ 728 cachedcook->data = (void *)priv; 729 730 if (aim_cachecookie(sess, cachedcook) == -1) 731 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n"); 732 733 free(fh); 734 #endif 735 736 } else if (rendid == AIM_CAPS_SENDFILE) { 737 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 738 priv->fh.recvcsum = 0xffff0000; 739 } else { 740 return NULL; 741 } 742 743 return newconn; 744 } 745 746 /* conn is a BOS connection over which to send the cancel msg */ 747 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn, 748 const char *cookie, const char *sn, int rendid) 749 { 750 aim_frame_t *newpacket; 751 int i; 752 753 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 754 return 1; 755 } 756 757 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 758 759 for (i = 0; i < 8; i++) 760 aimbs_put8(&newpacket->data, cookie[i]); 761 762 aimbs_put16(&newpacket->data, 0x0002); 763 aimbs_put8(&newpacket->data, strlen(sn)); 764 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 765 aimbs_put16(&newpacket->data, 0x0005); 766 aimbs_put16(&newpacket->data, 0x001a); 767 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL); 768 769 for (i = 0; i < 8; i++) 770 aimbs_put8(&newpacket->data, cookie[i]); 771 772 aim_putcap(&newpacket->data, rendid); 773 aim_tx_enqueue(sess, newpacket); 774 775 return 0; 776 } 777 778 /** 779 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE* 780 * @file is an opened listing file 781 * 782 * returns a pointer to the filled-in fileheader_t 783 * 784 * Currently omits checksum. we'll fix this when AOL breaks us, i 785 * guess. 786 * 787 */ 788 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file) 789 { 790 return NULL; 791 #if 0 792 struct aim_fileheader_t *fh; 793 u_long totsize = 0, size = 0, checksum = 0xffff0000; 794 short totfiles = 0; 795 char *linebuf, sizebuf[9]; 796 int linelength = 1024; 797 798 /* XXX: if we have a line longer than 1024chars, God help us. */ 799 if ((linebuf = (char *)calloc(1, linelength)) == NULL ) { 800 faimdprintf(sess, 2, "linebuf calloc failed\n"); 801 return NULL; 802 } 803 804 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */ 805 perror("getlisting END1 fseek:"); 806 faimdprintf(sess, 2, "getlising fseek END1 error\n"); 807 } 808 809 if ((size = ftell(file)) == -1) { 810 perror("getlisting END1 getpos:"); 811 faimdprintf(sess, 2, "getlising getpos END1 error\n"); 812 } 813 814 if (fseek(file, 0, SEEK_SET) != 0) { 815 perror("getlesting fseek(SET):"); 816 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n"); 817 } 818 819 memset(linebuf, 0, linelength); 820 821 size = 0; 822 823 while(fgets(linebuf, linelength, file)) { 824 totfiles++; 825 memset(sizebuf, 0, 9); 826 827 size += strlen(linebuf); 828 829 if (strlen(linebuf) < 23) { 830 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf); 831 continue; 832 } 833 834 if (linebuf[strlen(linebuf)-1] != '\n') { 835 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n"); 836 } 837 838 memcpy(sizebuf, linebuf+17, 8); 839 840 totsize += strtol(sizebuf, NULL, 10); 841 memset(linebuf, 0, linelength); 842 } 843 844 if (fseek(file, 0, SEEK_SET) == -1) { 845 perror("getlisting END2 fseek:"); 846 faimdprintf(sess, 2, "getlising fseek END2 error\n"); 847 } 848 849 free(linebuf); 850 851 /* we're going to ignore checksumming the data for now -- that 852 * requires walking the whole listing.txt. it should probably be 853 * done at register time and cached, but, eh. */ 854 855 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 856 return NULL; 857 858 fh->encrypt = 0x0000; 859 fh->compress = 0x0000; 860 fh->totfiles = totfiles; 861 fh->filesleft = totfiles; /* is this right? */ 862 fh->totparts = 0x0001; 863 fh->partsleft = 0x0001; 864 fh->totsize = totsize; 865 fh->size = size; /* ls -l listing.txt */ 866 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 867 fh->checksum = checksum; /* XXX: checksum ! */ 868 fh->rfcsum = 0x00000000; 869 fh->rfsize = 0x00000000; 870 fh->cretime = 0x00000000; 871 fh->rfcsum = 0x00000000; 872 fh->nrecvd = 0x00000000; 873 fh->recvcsum = 0x00000000; 874 875 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */ 876 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 877 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring)); 878 879 fh->flags = 0x02; 880 fh->lnameoffset = 0x1a; 881 fh->lsizeoffset = 0x10; 882 883 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */ 884 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 885 886 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */ 887 fh->nlanguage = 0x0000; 888 889 /* memset(fh->name, 0, sizeof(fh->name)); */ 890 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 891 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name)); 892 893 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name)))); 894 return fh; 895 #endif 896 } 897 898 /** 899 * aim_listenestablish - create a listening socket on a port. 900 * @portnum: the port number to bind to. 901 * 902 * you need to call accept() when it's connected. returns your fd 903 * 904 * XXX: give the client author the responsibility of setting up a 905 * listener, then we no longer have a libfaim problem with broken 906 * solaris *innocent smile* -jbm 122 unsigned short val; 123 124 for (i=0; i<bufferlen; i++) { 125 oldcheck = check; 126 if (i&1) 127 val = buffer[i]; 128 else 129 val = buffer[i] << 8; 130 check -= val; 131 /* 132 * The following appears to be necessary.... It happens 133 * every once in a while and the checksum doesn't fail. 134 */ 135 if (check > oldcheck) 136 check--; 137 } 138 check = ((check & 0x0000ffff) + (check >> 16)); 139 check = ((check & 0x0000ffff) + (check >> 16)); 140 return check << 16; 141 } 142 143 faim_export fu32_t aim_oft_checksum_file(char *filename) { 144 FILE *fd; 145 fu32_t checksum = 0xffff0000; 146 147 if ((fd = fopen(filename, "rb"))) { 148 int bytes; 149 fu8_t buffer[1024]; 150 151 while ((bytes = fread(buffer, 1, 1024, fd))) 152 checksum = aim_oft_checksum_chunk(buffer, bytes, checksum); 153 fclose(fd); 154 } 155 156 return checksum; 157 } 158 159 /** 160 * Create a listening socket on a given port. 161 * 162 * XXX - Give the client author the responsibility of setting up a 163 * listener, then we no longer have a libfaim problem with broken 164 * solaris *innocent smile* -- jbm 165 * 166 * @param portnum The port number to bind to. 167 * @return The file descriptor of the listening socket. 907 168 */ 908 169 static int listenestablish(fu16_t portnum) … … 919 180 hints.ai_family = AF_UNSPEC; 920 181 hints.ai_socktype = SOCK_STREAM; 921 if (getaddrinfo(NULL /* any IP*/, serv, &hints, &res) != 0) {182 if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) { 922 183 perror("getaddrinfo"); 923 184 return -1; … … 930 191 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 931 192 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) 932 break; 933 /* success */ 193 break; /* success */ 934 194 close(listenfd); 935 195 } while ( (res = res->ai_next) ); … … 938 198 return -1; 939 199 940 if (listen(listenfd, 1024)!=0) {941 perror("listen");942 return -1;943 }944 945 fcntl(listenfd, F_SETFL, O_NONBLOCK);946 947 200 freeaddrinfo(ressave); 948 return listenfd;949 201 #else 950 202 int listenfd; … … 953 205 954 206 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 955 perror("socket (listenfd)");207 perror("socket"); 956 208 return -1; 957 209 } 958 210 959 211 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { 960 perror("setsockopt (listenfd)");212 perror("setsockopt"); 961 213 close(listenfd); 962 214 return -1; 963 } 215 } 964 216 965 217 memset(&sockin, 0, sizeof(struct sockaddr_in)); … … 968 220 969 221 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { 970 perror("bind (listenfd)");222 perror("bind"); 971 223 close(listenfd); 972 224 return -1; 973 225 } 226 #endif 227 974 228 if (listen(listenfd, 4) != 0) { 975 perror("listen (listenfd)");229 perror("listen"); 976 230 close(listenfd); 977 231 return -1; 978 232 } 979 233 fcntl(listenfd, F_SETFL, O_NONBLOCK); 234 980 235 return listenfd; 236 } 237 238 /** 239 * After establishing a listening socket, this is called to accept a connection. It 240 * clones the conn used by the listener, and passes both of these to a signal handler. 241 * The signal handler should close the listener conn and keep track of the new conn, 242 * since this is what is used for file transfers and what not. 243 * 244 * @param sess The session. 245 * @param cur The conn the incoming connection is on. 246 * @return Return 0 if no errors, otherwise return the error number. 247 */ 248 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) 249 { 250 int acceptfd = 0; 251 struct sockaddr addr; 252 socklen_t addrlen = sizeof(addr); 253 int ret = 0; 254 aim_conn_t *newconn; 255 char ip[20]; 256 int port; 257 258 if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1) 259 return 0; /* not an error */ 260 261 if (addr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ 262 close(acceptfd); 263 aim_conn_close(cur); 264 return -1; 265 } 266 267 strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip)); 268 port = ntohs(((struct sockaddr_in *)&addr)->sin_port); 269 270 if (!(newconn = aim_cloneconn(sess, cur))) { 271 close(acceptfd); 272 aim_conn_close(cur); 273 return -ENOMEM; 274 } 275 276 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; 277 newconn->fd = acceptfd; 278 279 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 280 aim_rxcallback_t userfunc; 281 struct aim_odc_intdata *priv; 282 283 priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal); 284 cur->internal = NULL; 285 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port); 286 287 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED))) 288 ret = userfunc(sess, NULL, newconn, cur); 289 290 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 291 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { 292 aim_rxcallback_t userfunc; 293 294 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED))) 295 ret = userfunc(sess, NULL, newconn, cur); 296 297 } else { 298 faimdprintf(sess, 1,"Got a connection on a listener that's not rendezvous. Closing connection.\n"); 299 aim_conn_close(newconn); 300 ret = -1; 301 } 302 303 return ret; 304 } 305 306 /** 307 * Send client-to-client typing notification over an established direct connection. 308 * 309 * @param sess The session. 310 * @param conn The already-connected ODC connection. 311 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and 312 * 0x0000 sends "stopped." 313 * @return Return 0 if no errors, otherwise return the error number. 314 */ 315 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) 316 { 317 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; 318 aim_frame_t *fr; 319 aim_bstream_t *hdrbs; 320 fu8_t *hdr; 321 int hdrlen = 0x44; 322 323 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 324 return -EINVAL; 325 326 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, 0))) 327 return -ENOMEM; 328 memcpy(fr->hdr.rend.magic, "ODC2", 4); 329 fr->hdr.rend.hdrlen = hdrlen; 330 331 if (!(hdr = calloc(1, hdrlen))) { 332 aim_frame_destroy(fr); 333 return -ENOMEM; 334 } 335 336 hdrbs = &(fr->data); 337 aim_bstream_init(hdrbs, hdr, hdrlen); 338 339 aimbs_put16(hdrbs, 0x0006); 340 aimbs_put16(hdrbs, 0x0000); 341 aimbs_putraw(hdrbs, intdata->cookie, 8); 342 aimbs_put16(hdrbs, 0x0000); 343 aimbs_put16(hdrbs, 0x0000); 344 aimbs_put16(hdrbs, 0x0000); 345 aimbs_put16(hdrbs, 0x0000); 346 aimbs_put32(hdrbs, 0x00000000); 347 aimbs_put16(hdrbs, 0x0000); 348 aimbs_put16(hdrbs, 0x0000); 349 aimbs_put16(hdrbs, 0x0000); 350 351 if (typing == 0x0002) 352 aimbs_put16(hdrbs, 0x0002 | 0x0008); 353 else if (typing == 0x0001) 354 aimbs_put16(hdrbs, 0x0002 | 0x0004); 355 else 356 aimbs_put16(hdrbs, 0x0002); 357 358 aimbs_put16(hdrbs, 0x0000); 359 aimbs_put16(hdrbs, 0x0000); 360 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 361 362 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 363 364 aimbs_put8(hdrbs, 0x00); 365 aimbs_put16(hdrbs, 0x0000); 366 aimbs_put16(hdrbs, 0x0000); 367 aimbs_put16(hdrbs, 0x0000); 368 aimbs_put16(hdrbs, 0x0000); 369 aimbs_put16(hdrbs, 0x0000); 370 aimbs_put16(hdrbs, 0x0000); 371 aimbs_put16(hdrbs, 0x0000); 372 aimbs_put8(hdrbs, 0x00); 373 374 /* end of hdr */ 375 376 aim_tx_enqueue(sess, fr); 377 378 return 0; 379 } 380 381 /** 382 * Send client-to-client IM over an established direct connection. 383 * Call this just like you would aim_send_im, to send a directim. 384 * 385 * @param sess The session. 386 * @param conn The already-connected ODC connection. 387 * @param msg Null-terminated string to send. 388 * @param len The length of the message to send, including binary data. 389 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1. 390 * @param isawaymsg 0 if this is not an auto-response, 1 if it is. 391 * @return Return 0 if no errors, otherwise return the error number. 392 */ 393 faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg) 394 { 395 aim_frame_t *fr; 396 aim_bstream_t *hdrbs; 397 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; 398 int hdrlen = 0x44; 399 fu8_t *hdr; 400 401 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg) 402 return -EINVAL; 403 404 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) 405 return -ENOMEM; 406 407 memcpy(fr->hdr.rend.magic, "ODC2", 4); 408 fr->hdr.rend.hdrlen = hdrlen; 409 410 if (!(hdr = calloc(1, hdrlen + len))) { 411 aim_frame_destroy(fr); 412 return -ENOMEM; 413 } 414 415 hdrbs = &(fr->data); 416 aim_bstream_init(hdrbs, hdr, hdrlen + len); 417 418 aimbs_put16(hdrbs, 0x0006); 419 aimbs_put16(hdrbs, 0x0000); 420 aimbs_putraw(hdrbs, intdata->cookie, 8); 421 aimbs_put16(hdrbs, 0x0000); 422 aimbs_put16(hdrbs, 0x0000); 423 aimbs_put16(hdrbs, 0x0000); 424 aimbs_put16(hdrbs, 0x0000); 425 aimbs_put32(hdrbs, len); 426 aimbs_put16(hdrbs, encoding); 427 aimbs_put16(hdrbs, 0x0000); 428 aimbs_put16(hdrbs, 0x0000); 429 430 /* flags - used for typing notification and to mark if this is an away message */ 431 aimbs_put16(hdrbs, 0x0000 | isawaymsg); 432 433 aimbs_put16(hdrbs, 0x0000); 434 aimbs_put16(hdrbs, 0x0000); 435 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); 436 437 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ 438 439 aimbs_put8(hdrbs, 0x00); 440 aimbs_put16(hdrbs, 0x0000); 441 aimbs_put16(hdrbs, 0x0000); 442 aimbs_put16(hdrbs, 0x0000); 443 aimbs_put16(hdrbs, 0x0000); 444 aimbs_put16(hdrbs, 0x0000); 445 aimbs_put16(hdrbs, 0x0000); 446 aimbs_put16(hdrbs, 0x0000); 447 aimbs_put8(hdrbs, 0x00); 448 449 /* end of hdr2 */ 450 451 #if 0 /* XXX - this is how you send buddy icon info... */ 452 aimbs_put16(hdrbs, 0x0008); 453 aimbs_put16(hdrbs, 0x000c); 454 aimbs_put16(hdrbs, 0x0000); 455 aimbs_put16(hdrbs, 0x1466); 456 aimbs_put16(hdrbs, 0x0001); 457 aimbs_put16(hdrbs, 0x2e0f); 458 aimbs_put16(hdrbs, 0x393e); 459 aimbs_put16(hdrbs, 0xcac8); 981 460 #endif 982 } 983 984 static int getcommand_getfile(aim_session_t *sess, aim_conn_t *conn) 985 { 986 #if 0 987 struct aim_filetransfer_priv *ft; 988 aim_rxcallback_t userfunc; 989 990 ft = conn->priv; 991 if (ft->state == 2) { 992 /* waiting on listing data */ 993 int ret = 0; 994 char *listing; 995 aim_frame_t *newoft; 996 997 if (!(listing = malloc(ft->fh.size))) 998 return -1; 999 1000 ft->state = 0; 1001 if (aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size) 1002 faimdprintf(sess, 2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size); 1003 1004 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { 1005 faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); 1006 free(listing); 1007 aim_conn_close(conn); 1008 return -1; 461 aimbs_putraw(hdrbs, msg, len); 462 463 aim_tx_enqueue(sess, fr); 464 465 return 0; 466 } 467 468 /** 469 * Get the screen name of the peer of a direct connection. 470 * 471 * @param conn The ODC connection. 472 * @return The screen name of the dude, or NULL if there was an anomaly. 473 */ 474 faim_export const char *aim_odc_getsn(aim_conn_t *conn) 475 { 476 struct aim_odc_intdata *intdata; 477 478 if (!conn || !conn->internal) 479 return NULL; 480 481 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 482 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) 483 return NULL; 484 485 intdata = (struct aim_odc_intdata *)conn->internal; 486 487 return intdata->sn; 488 } 489 490 /** 491 * Find the conn of a direct connection with the given buddy. 492 * 493 * @param sess The session. 494 * @param sn The screen name of the buddy whose direct connection you want to find. 495 * @return The conn for the direct connection with the given buddy, or NULL if no 496 * connection was found. 497 */ 498 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) 499 { 500 aim_conn_t *cur; 501 struct aim_odc_intdata *intdata; 502 503 if (!sess || !sn || !strlen(sn)) 504 return NULL; 505 506 for (cur = sess->connlist; cur; cur = cur->next) { 507 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { 508 intdata = cur->internal; 509 if (!aim_sncmp(intdata->sn, sn)) 510 return cur; 1009 511 } 1010 1011 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1012 newoft->hdr.oft.hdr2len = 0x100 - 8; 1013 1014 /* Protocol BS - set nrecvd to size of listing, recvcsum to listing checksum, flags to 0 */ 1015 1016 ft->fh.nrecvd = ft->fh.size; 1017 ft->fh.recvcsum = ft->fh.checksum; 1018 ft->fh.flags = 0; 1019 1020 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 1021 aim_frame_destroy(newoft); 1022 free(listing); 1023 return -1; 1024 } 1025 1026 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) 1027 faimdprintf(sess, 2, "eek! bh fail listing\n"); 1028 1029 /* send the 120b */ 1030 aim_tx_enqueue(sess, newoft); 1031 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) ) 1032 ret = userfunc(sess, NULL, conn, ft, listing); 1033 1034 free(listing); 1035 return ret; 1036 } 1037 1038 if (ft->state == 3) { 1039 /* waiting on file data */ 1040 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) ) 1041 return userfunc(sess, NULL, conn, ft->fh.name, 1042 ft->fh.size); 1043 return 0; 1044 } 1045 1046 if (ft->state == 4) { 1047 if( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4)) ) 1048 return userfunc(sess, NULL, conn); 1049 aim_conn_close(conn); 1050 return 0; 1051 } 1052 1053 return 0; 1054 #else 1055 return -1; 1056 #endif 1057 } 1058 1059 static void connclose_sendfile(aim_session_t *sess, aim_conn_t *conn) 1060 { 1061 aim_msgcookie_t *cook; 1062 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->internal; 1063 1064 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); 1065 aim_cookie_free(sess, cook); 1066 1067 return; 1068 } 1069 1070 static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn) 1071 { 1072 free(conn->internal); 1073 1074 return; 1075 } 1076 1077 static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn) 1078 { 1079 #if 0 1080 aim_msgcookie_t *cook; 1081 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv; 1082 1083 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET); 1084 aim_cookie_free(sess, cook); 1085 #endif 1086 return; 1087 } 1088 1089 static void connkill_getfile(aim_session_t *sess, aim_conn_t *conn) 1090 { 1091 1092 free(conn->internal); 1093 1094 return; 1095 } 1096 1097 static void connclose_directim(aim_session_t *sess, aim_conn_t *conn) 1098 { 1099 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 1100 aim_msgcookie_t *cook; 1101 1102 cook = aim_uncachecookie(sess, intdata->cookie, AIM_COOKIETYPE_OFTIM); 1103 aim_cookie_free(sess, cook); 1104 1105 return; 1106 } 1107 1108 static void connkill_directim(aim_session_t *sess, aim_conn_t *conn) 1109 { 1110 1111 free(conn->internal); 1112 1113 return; 1114 } 1115 1116 faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn) 1117 { 1118 1119 if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) 1120 return; 1121 1122 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) 1123 connclose_sendfile(sess, conn); 1124 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) 1125 connclose_getfile(sess, conn); 1126 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) 1127 connclose_directim(sess, conn); 1128 1129 return; 1130 } 1131 1132 faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn) 1133 { 1134 1135 if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) 1136 return; 1137 1138 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) 1139 connkill_sendfile(sess, conn); 1140 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) 1141 connkill_getfile(sess, conn); 1142 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) 1143 connkill_directim(sess, conn); 1144 1145 return; 1146 } 1147 1148 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 512 } 513 514 return NULL; 515 } 516 517 /** 518 * For those times when we want to open up the direct connection channel ourselves. 519 * 520 * You'll want to set up some kind of watcher on this socket. 521 * When the state changes, call aim_handlerendconnection with 522 * the connection returned by this. aim_handlerendconnection 523 * will accept the pending connection and stop listening. 524 * 525 * @param sess The session 526 * @param sn The screen name to connect to. 527 * @return The new connection. 528 */ 529 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn) 530 { 531 aim_conn_t *newconn; 532 aim_msgcookie_t *cookie; 533 struct aim_odc_intdata *priv; 534 int listenfd; 535 fu16_t port = 4443; 536 fu8_t localip[4]; 537 fu8_t ck[8]; 538 539 if (aim_util_getlocalip(localip) == -1) 540 return NULL; 541 542 if ((listenfd = listenestablish(port)) == -1) 543 return NULL; 544 545 aim_im_sendch2_odcrequest(sess, ck, sn, localip, port); 546 547 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); 548 memcpy(cookie->cookie, ck, 8); 549 cookie->type = AIM_COOKIETYPE_OFTIM; 550 551 /* this one is for the cookie */ 552 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); 553 554 memcpy(priv->cookie, ck, 8); 555 strncpy(priv->sn, sn, sizeof(priv->sn)); 556 cookie->data = priv; 557 aim_cachecookie(sess, cookie); 558 559 /* XXX - switch to aim_cloneconn()? */ 560 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { 561 close(listenfd); 562 return NULL; 563 } 564 565 /* this one is for the conn */ 566 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); 567 568 memcpy(priv->cookie, ck, 8); 569 strncpy(priv->sn, sn, sizeof(priv->sn)); 570 571 newconn->fd = listenfd; 572 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; 573 newconn->internal = priv; 574 newconn->lastactivity = time(NULL); 575 576 return newconn; 577 } 578 579 /** 580 * Connect directly to the given buddy for directim. 581 * 582 * This is a wrapper for aim_newconn. 583 * 584 * If addr is NULL, the socket is not created, but the connection is 585 * allocated and setup to connect. 586 * 587 * @param sess The Godly session. 588 * @param sn The screen name we're connecting to. I hope it's a girl... 589 * @param addr Address to connect to. 590 * @return The new connection. 591 */ 592 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) 593 { 594 aim_conn_t *newconn; 595 struct aim_odc_intdata *intdata; 596 597 if (!sess || !sn) 598 return NULL; 599 600 if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata)))) 601 return NULL; 602 memcpy(intdata->cookie, cookie, 8); 603 strncpy(intdata->sn, sn, sizeof(intdata->sn)); 604 if (addr) 605 strncpy(intdata->ip, addr, sizeof(intdata->ip)); 606 607 /* XXX - verify that non-blocking connects actually work */ 608 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { 609 free(intdata); 610 return NULL; 611 } 612 613 newconn->internal = intdata; 614 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; 615 616 return newconn; 617 } 618 619 /** 620 * Sometimes you just don't know with these kinds of people. 621 * 622 * @param sess The session. 623 * @param conn The ODC connection of the incoming data. 624 * @param frr The frame allocated for the incoming data. 625 * @param bs It stands for "bologna sandwich." 626 * @return Return 0 if no errors, otherwise return the error number. 627 */ 628 static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs) 1149 629 { 1150 630 aim_frame_t fr; 631 int ret = 0; 1151 632 aim_rxcallback_t userfunc; 1152 633 fu32_t payloadlength; … … 1156 637 fr.conn = conn; 1157 638 1158 /* XXXugly */639 /* AAA - ugly */ 1159 640 aim_bstream_setpos(bs, 20); 1160 641 payloadlength = aimbs_get32(bs); … … 1167 648 1168 649 aim_bstream_setpos(bs, 36); 1169 /* XXX -create an aimbs_getnullstr function? */ 1170 snptr = aimbs_getstr(bs, MAXSNLEN); 1171 1172 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr); 1173 1174 if (flags & 0x0002) { 1175 int ret = 0; 1176 1177 if (flags == 0x000c) { 1178 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1179 ret = userfunc(sess, &fr, snptr, 1); 1180 return ret; 1181 } 1182 650 /* XXX - create an aimbs_getnullstr function? */ 651 snptr = aimbs_getstr(bs, 32); /* Next 32 bytes contain the sn, padded with null chars */ 652 653 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr); 654 655 if (flags & 0x0008) { 656 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 657 ret = userfunc(sess, &fr, snptr, 2); 658 } else if (flags & 0x0004) { 659 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 660 ret = userfunc(sess, &fr, snptr, 1); 661 } else { 1183 662 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1184 663 ret = userfunc(sess, &fr, snptr, 0); 1185 1186 return ret; 1187 1188 } else if (((flags & 0x000f) == 0x0000) && payloadlength) { 1189 char *msg, *msg2; 1190 int ret = 0; 664 } 665 666 if (payloadlength) { 667 char *msg; 1191 668 int recvd = 0; 1192 int i; 1193 1194 if (!(msg = calloc(1, payloadlength+1))) 1195 return -1; 1196 msg2 = msg; 1197 669 int i, isawaymsg; 670 671 isawaymsg = flags & 0x0001; 672 673 if (!(msg = calloc(1, payloadlength+1))) { 674 free(snptr); 675 return -ENOMEM; 676 } 677 1198 678 while (payloadlength - recvd) { 1199 679 if (payloadlength - recvd >= 1024) 1200 i = aim_recv(conn->fd, msg2, 1024);680 i = aim_recv(conn->fd, &msg[recvd], 1024); 1201 681 else 1202 i = aim_recv(conn->fd, msg2, payloadlength - recvd);682 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); 1203 683 if (i <= 0) { 1204 684 free(msg); 685 free(snptr); 1205 686 return -1; 1206 687 } 1207 688 recvd = recvd + i; 1208 msg2 = msg2 + i; 1209 if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) 1210 userfunc(sess, &fr, snptr, (double)recvd / payloadlength); 689 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) 690 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); 1211 691 } 1212 692 1213 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)))1214 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding );693 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) 694 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); 1215 695 1216 696 free(msg); 1217 1218 return ret; 1219 } 697 } 698 699 free(snptr); 700 701 return ret; 702 } 703 704 faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename) 705 { 706 struct aim_oft_info *new; 707 708 if (!sess) 709 return NULL; 710 711 if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info)))) 712 return NULL; 713 714 new->sess = sess; 715 if (cookie) 716 memcpy(new->cookie, cookie, 8); 717 if (ip) 718 new->clientip = strdup(ip); 719 if (sn) 720 new->sn = strdup(sn); 721 new->port = port; 722 new->fh.totfiles = 1; 723 new->fh.filesleft = 1; 724 new->fh.totparts = 1; 725 new->fh.partsleft = 1; 726 new->fh.totsize = size; 727 new->fh.size = size; 728 new->fh.modtime = modtime; 729 new->fh.checksum = 0xffff0000; 730 new->fh.rfrcsum = 0xffff0000; 731 new->fh.rfcsum = 0xffff0000; 732 new->fh.recvcsum = 0xffff0000; 733 strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31); 734 if (filename) 735 strncpy(new->fh.name, filename, 63); 736 737 new->next = sess->oft_info; 738 sess->oft_info = new; 739 740 return new; 741 } 742 743 /** 744 * Remove the given oft_info struct from the oft_info linked list, and 745 * then free its memory. 746 * 747 * @param sess The session. 748 * @param oft_info The aim_oft_info struct that we're destroying. 749 * @return Return 0 if no errors, otherwise return the error number. 750 */ 751 faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info) 752 { 753 aim_session_t *sess; 754 755 if (!oft_info || !(sess = oft_info->sess)) 756 return -EINVAL; 757 758 if (sess->oft_info && (sess->oft_info == oft_info)) { 759 sess->oft_info = sess->oft_info->next; 760 } else { 761 struct aim_oft_info *cur; 762 for (cur=sess->oft_info; (cur->next && (cur->next!=oft_info)); cur=cur->next); 763 if (cur->next) 764 cur->next = cur->next->next; 765 } 766 767 free(oft_info->sn); 768 free(oft_info->proxyip); 769 free(oft_info->clientip); 770 free(oft_info->verifiedip); 771 free(oft_info); 1220 772 1221 773 return 0; 1222 774 } 1223 775 1224 static int handlehdr_getfile_listing(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1225 { 1226 #if 0 1227 struct aim_filetransfer_priv *ft; 1228 struct aim_fileheader_t *fh; 1229 struct aim_msgcookie_t *cook; 1230 aim_frame_t *newoft; 1231 aim_rxcallback_t userfunc; 1232 1233 faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n"); 1234 fh = aim_oft_getfh(hdr); 1235 1236 faim_mutex_unlock(&conn->active); 1237 1238 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { 1239 free(fh); 1240 return -1; 1241 } 1242 1243 ft = cook->data; 1244 1245 /* we're waaaaiiiting.. for listing.txt */ 1246 ft->state = 2; 1247 1248 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 1249 free(fh); 1250 1251 if(aim_cachecookie(sess, cook) == -1) { 1252 faimdprintf(sess, 1, "error caching cookie\n"); 1253 return -1; 1254 } 1255 1256 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) { 1257 aim_conn_close(conn); 1258 return -1; 1259 } 1260 1261 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1262 newoft->hdr.oft.hdr2len = 0x100 - 8; 1263 1264 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 1265 newoft->lock = 0; 1266 aim_frame_destroy(newoft); 1267 return -1; 1268 } 1269 1270 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 1271 newoft->lock = 0; 1272 aim_frame_destroy(newoft); 1273 return -1; 1274 } 1275 1276 newoft->lock = 0; 1277 aim_tx_enqueue(sess, newoft); 1278 #endif 1279 return -1; 1280 } 1281 1282 static int handlehdr_getfile_listing2(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1283 { 1284 #if 0 1285 struct aim_filetransfer_priv *ft; 1286 struct aim_fileheader_t *fh; 1287 struct aim_msgcookie_t *cook; 1288 int ret = 0; 1289 aim_rxcallback_t userfunc; 1290 1291 fh = aim_oft_getfh(hdr); 1292 1293 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) 1294 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie); 1295 1296 ft = cook->data; 1297 1298 if (ft->fh.size != fh->size) 1299 faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size); 1300 1301 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ))) 1302 ret = userfunc(sess, NULL, conn, fh); 1303 1304 faimdprintf(sess, 2, "faim: get_command_rendezvous: hit end of 1209\n"); 1305 1306 free(fh); 1307 1308 return ret; 1309 #else 1310 return -1; 1311 #endif 1312 } 1313 1314 static int handlehdr_getfile_listing3(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1315 { 1316 #if 0 1317 struct aim_filetransfer_priv *ft; 1318 struct aim_msgcookie_t *cook; 1319 struct aim_fileheader_t *fh; 1320 aim_rxcallback_t userfunc; 1321 1322 fh = aim_oft_getfh(hdr); 1323 1324 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { 1325 free(fh); 1326 return -1; 1327 } 1328 1329 free(fh); 1330 1331 ft = cook->data; 1332 1333 if (aim_cachecookie(sess, cook) == -1) 1334 return -1; 1335 1336 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGRXCONFIRM))) 1337 return userfunc(sess, NULL, conn); 1338 #endif 1339 return -1; 1340 } 1341 1342 static int handlehdr_getfile_request(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1343 { 1344 #if 0 1345 struct aim_filetransfer_priv *ft; 1346 aim_msgcookie_t *cook; 1347 struct aim_fileheader_t *fh; 1348 aim_frame_t *newoft; 1349 int i = 0; 1350 aim_rxcallback_t userfunc; 1351 1352 fh = aim_oft_getfh(hdr); 1353 1354 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { 1355 free(fh); 1356 return -1; 1357 } 1358 1359 ft = cook->data; 1360 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 1361 free(fh); 1362 1363 aim_cachecookie(sess, cook); 1364 1365 faimdprintf(sess, 2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name); 1366 1367 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) ) 1368 i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie); 1369 1370 if (i < 0) 1371 return i; 1372 1373 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0101, 0))) { 1374 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); 1375 return -1; 1376 } 1377 1378 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1379 newoft->hdr.oft.hdr2len = 0x100 - 8; 1380 1381 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { 1382 aim_frame_destroy(newoft); 1383 return -1; 1384 } 1385 1386 /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */ 1387 ft->fh.nrecvd = 0; 1388 ft->fh.recvcsum = 0; 1389 ft->fh.flags = 0x20; 1390 1391 aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); 1392 1393 aim_tx_enqueue(sess, newoft); 1394 1395 faimdprintf(sess, 2, "faim: OFT: OFT file header enqueued.\n"); 1396 1397 return i; 1398 #else 1399 return -1; 1400 #endif 1401 } 1402 1403 static int handlehdr_getfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1404 { 1405 #if 0 1406 struct aim_fileheader_t *fh; 1407 struct aim_filetransfer_priv *ft; 1408 struct aim_msgcookie_t *cook; 1409 struct command_tx_struct *newoft; 1410 aim_rxcallback_t userfunc; 1411 1412 fh = aim_oft_getfh(hdr); 1413 1414 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { 1415 free(fh); 1416 return -1; 1417 } 1418 1419 free(fh); 1420 1421 ft = cook->data; 1422 1423 ft->state = 3; 1424 1425 if (aim_cachecookie(sess, cook) == -1) 1426 return -1; 1427 1428 faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name); 1429 1430 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { 1431 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); 1432 return -1; 1433 } 1434 1435 newoft->lock = 1; 1436 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1437 1438 newoft->hdr.oft.hdr2len = 0x100 - 8; 1439 1440 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { 1441 aim_frame_destroy(newoft); 1442 return -1; 1443 } 1444 1445 aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); 1446 1447 newoft->lock = 0; 1448 aim_tx_enqueue(sess, newoft); 1449 1450 faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n"); 1451 1452 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL) 776 /** 777 * Creates a listener socket so the other dude can connect to us. 778 * 779 * You'll want to set up some kind of watcher on this socket. 780 * When the state changes, call aim_handlerendconnection with 781 * the connection returned by this. aim_handlerendconnection 782 * will accept the pending connection and stop listening. 783 * 784 * @param sess The session. 785 * @param oft_info File transfer information associated with this 786 * connection. 787 * @return Return 0 if no errors, otherwise return the error number. 788 */ 789 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info) 790 { 791 int listenfd; 792 793 if (!oft_info) 794 return -EINVAL; 795 796 if ((listenfd = listenestablish(oft_info->port)) == -1) 1453 797 return 1; 1454 #else 1455 return -1; 1456 #endif 1457 } 1458 1459 /* We are receiving a file, and the buddy sent us this header describing 1460 * it. We send back a similar header to confirm, then we're ready to 1461 * start reading the raw data. 1462 */ 1463 static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 1464 { 1465 struct aim_filetransfer_priv *ft; 1466 struct aim_fileheader_t *fh; 1467 aim_frame_t *newoft; 1468 aim_rxcallback_t userfunc; 1469 1470 fh = aim_oft_getfh(bs); 1471 1472 /* We receive a null cookie for the first file; we must fill 1473 * it in to authenticate ourselves. -- wtm 1474 */ 1475 ft = conn->internal; 1476 memcpy(&(fh->bcookie), ft->cookie, 8); 1477 1478 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 1479 free(fh); 1480 1481 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) { 1482 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); 1483 return -1; 1484 } 1485 1486 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 1487 return -1; 1488 } 1489 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 1490 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 1491 1492 aim_tx_enqueue(sess, newoft); 1493 1494 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL) 1495 return 1; 1496 1497 { 1498 char *cur; 1499 /* Convert the directory separator: it is sent 1500 * as ^A (0x01). 1501 */ 1502 while ((cur = strchr(ft->fh.name, 0x01))) { 1503 *cur = G_DIR_SEPARATOR; 1504 } 1505 } 1506 return userfunc(sess, NULL, conn, &(ft->fh)); 1507 } 1508 1509 1510 /* 1511 * These were originally described by Josh Myer: 1512 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/ 1513 * XXX this doesn't actually work yet 1514 * -- wtm 1515 */ 1516 static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) { 1517 aim_frame_t *newoft; 1518 aim_msgcookie_t *cook; 1519 struct aim_fileheader_t *fh; 1520 struct aim_filetransfer_priv *ft; 1521 1522 fh = aim_oft_getfh(bs); 1523 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1524 free(fh); 1525 return -1; 1526 } 1527 ft = (struct aim_filetransfer_priv *)cook->data; 1528 1529 ft->fh.nrecvd = fh->nrecvd; 1530 ft->fh.recvcsum = fh->recvcsum; 1531 strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name)); 1532 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) { 1533 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 1534 free(fh); 1535 return -1; 1536 } 1537 1538 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 1539 aim_frame_destroy(newoft); 1540 free(fh); 1541 return -1; 1542 } 1543 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 1544 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 1545 1546 aim_tx_enqueue(sess, newoft); 1547 free(fh); 798 799 if (!(oft_info->conn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { 800 close(listenfd); 801 return -ENOMEM; 802 } 803 804 oft_info->conn->fd = listenfd; 805 oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 806 oft_info->conn->lastactivity = time(NULL); 1548 807 1549 808 return 0; 1550 809 } 1551 810 1552 /* We are sending a file, and the buddy sent us this header indicating 1553 * that he or she is ready for the raw data. 1554 */ 1555 static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) { 1556 struct aim_fileheader_t *fh; 1557 aim_msgcookie_t *cook; 1558 int ret = 1; 1559 struct aim_filetransfer_priv *ft; 1560 aim_rxcallback_t userfunc; 1561 1562 fh = aim_oft_getfh(bs); 1563 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1564 free(fh); 1565 return -1; 1566 } 1567 ft = (struct aim_filetransfer_priv *)cook->data; 1568 1569 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILESEND)) ) 1570 ret = userfunc(sess, NULL, conn, &(ft->fh)); 1571 1572 free(fh); 1573 1574 return ret; 1575 } 1576 1577 static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1578 { 1579 #if 0 1580 struct aim_fileheader_t *fh; 1581 struct aim_msgcookie_t *cook; 1582 int ret = 1; 1583 aim_rxcallback_t userfunc; 1584 struct aim_filetransfer_priv *ft; 1585 1586 fh = aim_oft_getfh(hdr); 1587 1588 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { 1589 free(fh); 1590 return -1; 1591 } 1592 1593 ft = cook->data; 1594 1595 faimdprintf(sess, 2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n"); 1596 1597 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) ) 1598 ret = userfunc(sess, NULL, conn, fh); 1599 1600 free(fh); 1601 1602 return ret; 1603 #else 1604 return -1; 1605 #endif 1606 } 1607 1608 /* We just sent the raw data of a file, and the buddy sent us back this 1609 * header indicating that the transfer is complete. 1610 */ 1611 static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 1612 { 1613 struct aim_fileheader_t *fh; 1614 aim_msgcookie_t *cook; 1615 aim_rxcallback_t userfunc; 1616 1617 fh = aim_oft_getfh(bs); 1618 1619 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1620 free(fh); 1621 return -1; 1622 } 1623 1624 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILECOMPLETE)) ) 1625 userfunc(sess, NULL, conn, fh->bcookie); 1626 1627 free(fh); 1628 return 0; 1629 } 1630 1631 static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1632 { 1633 #if 0 1634 struct aim_fileheader_t *fh; 1635 aim_rxcallback_t userfunc; 1636 1637 fh = aim_oft_getfh(hdr); 1638 1639 faimdprintf(sess, 2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n"); 1640 1641 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) ) 1642 userfunc(sess, NULL, conn, fh); 1643 1644 free(fh); 1645 #endif 1646 1647 return -1; 1648 } 1649 1650 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) 1651 { 1652 aim_conn_t *conn = fr->conn; 1653 aim_bstream_t *bs = &fr->data; 1654 int ret = -1; 1655 1656 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 1657 /* This should never happen. -- wtm */ 1658 return getcommand_getfile(sess, conn); 1659 1660 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { 1661 switch(fr->hdr.rend.type) { 1662 case AIM_OFT_PROTO_OFFER: 1663 ret = handlehdr_sendfile_sending(sess, conn, bs); 1664 break; 1665 case AIM_OFT_PROTO_RESUME: 1666 ret = handlehdr_sendfile_resume(sess, conn, bs); 1667 break; 1668 case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */; 1669 case AIM_OFT_PROTO_ACCEPT: 1670 ret = handlehdr_sendfile_recv(sess, conn, bs); 1671 break; 1672 case AIM_OFT_PROTO_ACK: 1673 ret = handlehdr_sendfile_finish(sess, conn, bs); 1674 break; 1675 default: 1676 faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type); 1677 ret = -1; 1678 break; 1679 } 1680 1681 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 1682 if (fr->hdr.rend.type == 0x0001) 1683 ret = handlehdr_directim(sess, conn, bs); 1684 else 1685 faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type); 1686 1687 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 1688 /* This _really_ shouldn't happen. :) -- wtm */ 1689 char *hdr = NULL; 1690 int hdrtype = fr->hdr.rend.type; 1691 if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */ 1692 ret = handlehdr_getfile_listing(sess, conn, hdr); 1693 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */ 1694 ret = handlehdr_getfile_listing2(sess, conn, hdr); 1695 else if (hdrtype == 0x120b) /* get file listing rx confirm */ 1696 ret = handlehdr_getfile_listing3(sess, conn, hdr); 1697 else if (hdrtype == 0x120c) /* getfile request */ 1698 ret = handlehdr_getfile_request(sess, conn, hdr); 1699 else if (hdrtype == 0x0101) /* getfile sending data */ 1700 ret = handlehdr_getfile_sending(sess, conn, hdr); 1701 else if (hdrtype == 0x0202) /* getfile recv data */ 1702 ret = handlehdr_getfile_recv(sess, conn, hdr); 1703 else if (hdrtype == 0x0204) /* getfile finished */ 1704 ret = handlehdr_getfile_finish(sess, conn, hdr); 1705 else { 1706 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); 1707 ret = -1; 1708 } 1709 } 1710 1711 if (ret == -1) 1712 aim_conn_close(conn); 1713 1714 return ret; 1715 } 1716 1717 /** 1718 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. 1719 * @bs: bstream to extract header from 1720 * 1721 * returns pointer to new struct on success; %NULL on error. 1722 * 1723 */ 1724 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs) 811 /** 812 * Extract an &aim_fileheader_t from the given buffer. 813 * 814 * @param bs The should be from an incoming rendezvous packet. 815 * @return A pointer to new struct on success, or NULL on error. 816 */ 817 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs) 1725 818 { 1726 819 struct aim_fileheader_t *fh; … … 1755 848 fh->nencode = aimbs_get16(bs); 1756 849 fh->nlanguage = aimbs_get16(bs); 1757 aimbs_getrawbuf(bs, fh->name, 64); /* XXX */850 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ 1758 851 1759 852 return fh; … … 1761 854 1762 855 /** 1763 * aim_oft_checksum - calculate oft checksum of buffer 1764 * @buffer: buffer of data to checksum 1765 * @bufsize: size of buffer 1766 * @prevcheck: previous checksum 1767 * 1768 * Prevcheck should be 0xFFFF0000 for each new file; you can have this 1769 * checksum chunks of files in series if you just call it repeatedly in a 1770 * for(; ; ) loop and don't reset the checksum between each call. And you 1771 * thought we didn't care about you and your pathetic client's meomry 1772 * footprint ;^) 1773 * 1774 * Thanks to Graham Booker for providing this improved checksum 1775 * routine, which is simpler and should be more accurate than Josh 1776 * Myer's original code. -- wtm 1777 * 1778 * This algorithim works every time I have tried it. The other fails 1779 * sometimes. So, AOL who thought this up? It has got to be the weirdest 1780 * checksum I have ever seen. 1781 */ 1782 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) { 1783 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck; 1784 int i; 1785 unsigned short val; 1786 1787 for (i=0; i<bufferlen; i++) { 1788 oldcheck = check; 1789 if (i&1) { 1790 val = buffer[i]; 1791 } else { 1792 val = buffer[i] << 8; 1793 } 1794 check -= val; 1795 /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */ 1796 if (check > oldcheck) { 1797 check--; 1798 } 1799 } 1800 check = ((check & 0x0000ffff) + (check >> 16)); 1801 check = ((check & 0x0000ffff) + (check >> 16)); 1802 return check << 16; 1803 } 1804 1805 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn, 1806 const unsigned char *buffer, int len) { 1807 struct aim_filetransfer_priv *ft = conn->internal; 1808 1809 ft->fh.nrecvd += len; 1810 ft->fh.recvcsum = aim_oft_checksum(buffer, len, ft->fh.recvcsum); 1811 1812 return 0; 1813 } 1814 1815 /** 1816 * aim_oft_buildheader - fills a buffer with network-order fh data 1817 * @bs: bstream to fill -- automatically initialized 1818 * @fh: fh to get data from 1819 * 1820 * returns -1 on error. 1821 * 856 * Fills a buffer with network-order fh data 857 * 858 * @param bs A bstream to fill -- automatically initialized 859 * @param fh A struct aim_fileheader_t to get data from. 860 * @return Return non-zero on error. 1822 861 */ 1823 862 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) … … 1826 865 1827 866 if (!bs || !fh) 1828 return -1; 1829 1830 1831 1832 1833 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) { 1834 return -1; 1835 } 867 return -EINVAL; 868 869 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) 870 return -ENOMEM; 871 1836 872 aim_bstream_init(bs, hdr, 0x100 - 8); 1837 1838 873 aimbs_putraw(bs, fh->bcookie, 8); 1839 874 aimbs_put16(bs, fh->encrypt); … … 1861 896 aimbs_put16(bs, fh->nencode); 1862 897 aimbs_put16(bs, fh->nlanguage); 1863 aimbs_putraw(bs, fh->name, 64); 1864 1865 /* XXX: Filenames longer than 64B */ 898 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */ 899 1866 900 return 0; 1867 901 } 1868 902 1869 903 /** 1870 * aim_getfile_intitiate - Request an OFT getfile session 1871 * @sess: your session, 1872 * @conn: the BOS conn, 1873 * @destsn is the SN to connect to. 1874 * 1875 * returns a new &aim_conn_t on success, %NULL on error 1876 */ 1877 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) 1878 { 1879 return NULL; 904 * Create an OFT packet based on the given information, and send it on its merry way. 905 * 906 * @param sess The session. 907 * @param type The subtype of the OFT packet we're sending. 908 * @param oft_info The aim_oft_info struct with the connection and OFT 909 * info we're sending. 910 * @return Return 0 if no errors, otherwise return the error number. 911 */ 912 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info) 913 { 914 aim_frame_t *fr; 915 916 if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 917 return -EINVAL; 918 1880 919 #if 0 1881 struct command_tx_struct *newpacket; 1882 struct aim_conn_t *newconn; 1883 struct aim_filetransfer_priv *priv; 1884 struct aim_msgcookie_t *cookie; 1885 int curbyte, i, listenfd; 1886 short port = 4443; 1887 struct hostent *hptr; 1888 struct utsname myname; 1889 char cap[16]; 1890 char d[4]; 1891 1892 /* Open our socket */ 1893 1894 if ( (listenfd = aim_listenestablish(port)) == -1) 1895 return NULL; 1896 1897 /* get our local IP */ 1898 1899 if (uname(&myname) < 0) 1900 return NULL; 1901 if ( (hptr = gethostbyname(myname.nodename)) == NULL) 1902 return NULL; 1903 memcpy(&d, hptr->h_addr_list[0], 4); 1904 1905 aim_putcap(cap, 16, AIM_CAPS_GETFILE); 1906 1907 /* create the OSCAR packet */ 1908 1909 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42))) 1910 return NULL; 1911 newpacket->lock = 1; 1912 1913 /* lock struct */ 1914 curbyte = 0; 1915 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid); 1916 1917 /* XXX: check the cookie before commiting to using it */ 1918 1919 /* Generate a random message cookie 1920 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */ 1921 for (i=0; i<7; i++) 1922 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10)); 1923 1924 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1925 1926 /* grab all the data for cookie caching. */ 1927 1928 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) 1929 return NULL; 1930 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8); 1931 cookie->type = AIM_COOKIETYPE_OFTGET; 1932 1933 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) 1934 return NULL; 1935 memcpy(priv->cookie, cookie, 8); 1936 memcpy(priv->sn, destsn, sizeof(priv->sn)); 1937 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt")); 1938 priv->state = 1; 1939 1940 cookie->data = priv; 1941 1942 aim_cachecookie(sess, cookie); 1943 1944 /* Channel ID */ 1945 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002); 1946 1947 /* Destination SN (prepended with byte length) */ 1948 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); 1949 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); 1950 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1951 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1952 1953 /* enTLV start */ 1954 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1955 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042); 1956 1957 /* Flag data / ICBM Parameters? */ 1958 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1959 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1960 1961 /* Cookie */ 1962 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8); 1963 1964 /* Capability String */ 1965 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10); 1966 1967 /* 000a/0002 : 0001 */ 1968 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); 1969 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1970 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); 1971 1972 /* 0003/0004: IP address */ 1973 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 1974 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); 1975 for (i = 0; i < 4; i++) 1976 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); 1977 1978 /* already in network byte order */ 1979 1980 /* 0005/0002: Port */ 1981 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 1982 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 1983 curbyte += aimutil_put16(newpacket->data+curbyte, port); 1984 1985 /* 000f/0000: ?? */ 1986 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); 1987 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 1988 1989 /* 2711/000c: ?? */ 1990 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); 1991 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c); 1992 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001); 1993 1994 for (i = 0; i < 0x000c - 4; i++) 1995 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1996 1997 newpacket->commandlen = curbyte; 1998 newpacket->lock = 0; 1999 aim_tx_enqueue(sess, newpacket); 2000 2001 /* allocate and set up our connection */ 2002 2003 i = fcntl(listenfd, F_GETFL, 0); 2004 fcntl(listenfd, F_SETFL, i | O_NONBLOCK); 2005 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL); 2006 2007 if (!newconn){ 2008 perror("aim_newconn"); 2009 return NULL; 2010 } 2011 2012 newconn->fd = listenfd; 2013 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 2014 newconn->internal = priv; 2015 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); 2016 2017 return newconn; 2018 #endif 2019 } 2020 2021 /** 2022 * aim_oft_getfile_request - request a particular file over an established getfile connection 2023 * @sess: your session 2024 * @conn: the established OFT getfile connection 2025 * @name: filename to request 2026 * @size: size of the file 2027 * 2028 * 2029 * returns -1 on error, 0 on successful enqueuing 2030 */ 2031 #if 0 2032 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size) 2033 { 2034 aim_frame_t *newoft; 2035 struct aim_filetransfer_priv *ft; 2036 if (!sess || !conn || !conn->priv || !name) 2037 return -1; 2038 2039 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) { 2040 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2041 return -1; 2042 } 2043 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2044 newoft->hdr.oft.hdr2len = 0x100 - 8; 2045 2046 ft = (struct aim_filetransfer_priv *)conn->priv; 2047 ft->fh.filesleft = 1; 2048 ft->fh.totfiles = 1; 2049 ft->fh.totparts = 1; 2050 ft->fh.partsleft = 1; 2051 ft->fh.totsize = size; 2052 ft->fh.size = size; 2053 ft->fh.checksum = 0; 2054 memcpy(ft->fh.name, name, strlen(name)); 2055 memset(ft->fh.name+strlen(name), 0, 1); 2056 2057 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2058 aim_frame_destroy(newoft); 2059 return -1; 2060 } 2061 2062 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { 2063 aim_frame_destroy(newoft); 2064 return -1; 2065 } 2066 2067 aim_tx_enqueue(sess, newoft); 2068 return 0; 2069 } 2070 #endif 2071 2072 /* Identify a file that we are about to send by transmitting the 2073 * appropriate header. 2074 */ 2075 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize) 2076 { 2077 aim_frame_t *newoft; 2078 aim_msgcookie_t *cook; 2079 struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal; 2080 struct aim_fileheader_t *fh; 2081 2082 if (!sess || !conn || !filename) 2083 return -1; 2084 2085 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 2086 return -1; 2087 2088 #ifdef DUMB_OFT_CHECKSUM 2089 /* Yes, we are supposed to checksum the whole file before sending, and 2090 * yes, it's dumb. This is the only way to get some clients (such as 2091 * Mac AIM v4.5.163) to successfully complete the transfer. With 2092 * the WinAIM clients, we seem to be able to get away with just 2093 * setting the checksum to zero. 2094 * -- wtm 920 /* 921 * If you are receiving a file, the cookie should be null, if you are sending a 922 * file, the cookie should be the same as the one used in the ICBM negotiation 923 * SNACs. 2095 924 */ 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 #else2109 fh->checksum = 0x00000000;2110 #endif2111 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 925 fh->lnameoffset = 0x1a; 2131 926 fh->lsizeoffset = 0x10; 2132 memset(fh->dummy, 0, sizeof(fh->dummy));2133 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));2134 927 2135 928 /* apparently 0 is ASCII, 2 is UCS-2 */ 2136 929 /* it is likely that 3 is ISO 8859-1 */ 930 /* I think "nlanguage" might be the same thing as "subenc" in im.c */ 2137 931 fh->nencode = 0x0000; 2138 932 fh->nlanguage = 0x0000; 2139 2140 /* Convert the directory separator to ^A for portability. */ 2141 strncpy(fh->name, filename, sizeof(fh->name)); 2142 oft_dirconvert(fh->name); 2143 2144 /* XXX we should normally send a null cookie here, and make 2145 * the receiver fill it in for authentication -- wtm 2146 */ 2147 memcpy(fh->bcookie, ft->cookie, 8); 2148 2149 if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) { 2150 return -1; 2151 } 2152 2153 /* Update both headers to be safe. */ 2154 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 2155 memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t)); 2156 2157 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) { 2158 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2159 free(fh); 2160 return -1; 2161 } 2162 2163 if (aim_oft_buildheader(&newoft->data, fh) == -1) { 2164 aim_frame_destroy(newoft); 2165 free(fh); 2166 return -1; 2167 } 2168 2169 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 2170 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 2171 2172 aim_tx_enqueue(sess, newoft); 2173 free(fh); 933 #endif 934 935 aim_oft_dirconvert_tostupid(oft_info->fh.name); 936 937 if (!(fr = aim_tx_new(sess, oft_info->conn, AIM_FRAMETYPE_OFT, type, 0))) 938 return -ENOMEM; 939 940 if (aim_oft_buildheader(&fr->data, &oft_info->fh) == -1) { 941 aim_frame_destroy(fr); 942 return -ENOMEM; 943 } 944 945 memcpy(fr->hdr.rend.magic, "OFT2", 4); 946 fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data); 947 948 aim_tx_enqueue(sess, fr); 949 2174 950 return 0; 2175 951 } 2176 2177 /** 2178 * aim_oft_getfile_ack - acknowledge a getfile download as complete 2179 * @sess: your session 2180 * @conn: the getfile conn to send the ack over 2181 * 2182 * Call this function after you have read all the data in a particular 2183 * filetransfer. Returns -1 on error, 0 on apparent success 2184 * 2185 */ 2186 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) 2187 { 2188 return -EINVAL; 2189 #if 0 2190 struct command_tx_struct *newoft; 2191 struct aim_filetransfer_priv *ft; 2192 2193 if (!sess || !conn || !conn->priv) 2194 return -1; 2195 2196 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { 2197 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2198 return -1; 2199 } 2200 2201 newoft->lock = 1; 2202 2203 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2204 newoft->hdr.oft.hdr2len = 0x100-8; 2205 2206 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2207 newoft->lock = 0; 2208 aim_frame_destroy(newoft); 2209 return -1; 2210 } 2211 2212 ft = (struct aim_filetransfer_priv *)conn->priv; 2213 2214 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 2215 newoft->lock = 0; 2216 aim_frame_destroy(newoft); 2217 return -1; 2218 } 2219 2220 newoft->lock = 0; 2221 aim_tx_enqueue(sess, newoft); 2222 return 0; 2223 #endif 2224 } 2225 2226 /** 2227 * aim_oft_end - end a getfile/sendfile. 2228 * @sess: your session 2229 * @conn: the getfile connection 2230 * 2231 * call this before you close the getfile connection if you're on the 2232 * receiving/requesting end. 2233 */ 2234 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn) 2235 { 2236 aim_frame_t *newoft; 2237 struct aim_filetransfer_priv *ft; 2238 2239 if (!sess || !conn || !conn->internal) 2240 return -1; 2241 2242 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) { 2243 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2244 return -1; 2245 } 2246 2247 ft = (struct aim_filetransfer_priv *)conn->internal; 2248 ft->state = 4; /* no longer wanting data */ 2249 ft->fh.flags = 0x21; 2250 2251 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 2252 aim_frame_destroy(newoft); 2253 return -1; 2254 } 2255 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 2256 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 2257 2258 aim_tx_enqueue(sess, newoft); 2259 2260 return 0; 2261 } 2262 2263 /* 2264 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability. 2265 */ 2266 static void oft_dirconvert(char *name) { 2267 char *c = name; 2268 while ((c = strchr(c, G_DIR_SEPARATOR))) 2269 *c = 0x01; 2270 } 952 953 /** 954 * Handle incoming data on a rendezvous connection. This is analogous to the 955 * consumesnac function in rxhandlers.c, and I really think this should probably 956 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. 957 * 958 * @param sess The session. 959 * @param fr The frame allocated for the incoming data. 960 * @return Return 0 if the packet was handled correctly, otherwise return the 961 * error number. 962 */ 963 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) 964 { 965 aim_conn_t *conn = fr->conn; 966 int ret = 1; 967 968 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 969 if (fr->hdr.rend.type == 0x0001) 970 ret = handlehdr_odc(sess, conn, fr, &fr->data); 971 else 972 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type); 973 974 } else { 975 aim_rxcallback_t userfunc; 976 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data); 977 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */ 978 979 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type))) 980 ret = userfunc(sess, fr, conn, header->bcookie, header); 981 982 free(header); 983 } 984 985 if (ret == -1) 986 aim_conn_close(conn); 987 988 return ret; 989 } -
libfaim/icq.c
r862371b re374dee 71 71 } 72 72 73 faim_export int aim_icq_hideip(aim_session_t *sess) 74 { 75 aim_conn_t *conn; 76 aim_frame_t *fr; 77 aim_snacid_t snacid; 78 int bslen; 79 80 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 81 return -EINVAL; 82 83 bslen = 2+4+2+2+2+4; 84 85 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 86 return -ENOMEM; 87 88 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 89 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 90 91 /* For simplicity, don't bother using a tlvlist */ 92 aimbs_put16(&fr->data, 0x0001); 93 aimbs_put16(&fr->data, bslen); 94 95 aimbs_putle16(&fr->data, bslen - 2); 96 aimbs_putle32(&fr->data, atoi(sess->sn)); 97 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 98 aimbs_putle16(&fr->data, snacid); /* eh. */ 99 aimbs_putle16(&fr->data, 0x0424); /* shrug. */ 100 aimbs_putle16(&fr->data, 0x0001); 101 aimbs_putle16(&fr->data, 0x0001); 102 103 aim_tx_enqueue(sess, fr); 104 105 return 0; 106 } 107 108 /** 109 * Change your ICQ password. 110 * 111 * @param sess The oscar session 112 * @param passwd The new password. If this is longer than 8 characters it 113 * will be truncated. 114 * @return Return 0 if no errors, otherwise return the error number. 115 */ 116 faim_export int aim_icq_changepasswd(aim_session_t *sess, const char *passwd) 117 { 118 aim_conn_t *conn; 119 aim_frame_t *fr; 120 aim_snacid_t snacid; 121 int bslen, passwdlen; 122 123 if (!passwd) 124 return -EINVAL; 125 126 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 127 return -EINVAL; 128 129 passwdlen = strlen(passwd); 130 if (passwdlen > MAXICQPASSLEN) 131 passwdlen = MAXICQPASSLEN; 132 bslen = 2+4+2+2+2+2+passwdlen+1; 133 134 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 135 return -ENOMEM; 136 137 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 138 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 139 140 /* For simplicity, don't bother using a tlvlist */ 141 aimbs_put16(&fr->data, 0x0001); 142 aimbs_put16(&fr->data, bslen); 143 144 aimbs_putle16(&fr->data, bslen - 2); 145 aimbs_putle32(&fr->data, atoi(sess->sn)); 146 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 147 aimbs_putle16(&fr->data, snacid); /* eh. */ 148 aimbs_putle16(&fr->data, 0x042e); /* shrug. */ 149 aimbs_putle16(&fr->data, passwdlen+1); 150 aimbs_putraw(&fr->data, passwd, passwdlen); 151 aimbs_putle8(&fr->data, '\0'); 152 153 aim_tx_enqueue(sess, fr); 154 155 return 0; 156 } 157 158 faim_export int aim_icq_getallinfo(aim_session_t *sess, const char *uin) 159 { 160 aim_conn_t *conn; 161 aim_frame_t *fr; 162 aim_snacid_t snacid; 163 int bslen; 164 struct aim_icq_info *info; 165 166 if (!uin || uin[0] < '0' || uin[0] > '9') 167 return -EINVAL; 168 169 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 170 return -EINVAL; 171 172 bslen = 2 + 4 + 2 + 2 + 2 + 4; 173 174 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 175 return -ENOMEM; 176 177 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 178 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 179 180 /* For simplicity, don't bother using a tlvlist */ 181 aimbs_put16(&fr->data, 0x0001); 182 aimbs_put16(&fr->data, bslen); 183 184 aimbs_putle16(&fr->data, bslen - 2); 185 aimbs_putle32(&fr->data, atoi(sess->sn)); 186 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 187 aimbs_putle16(&fr->data, snacid); /* eh. */ 188 aimbs_putle16(&fr->data, 0x04b2); /* shrug. */ 189 aimbs_putle32(&fr->data, atoi(uin)); 190 191 aim_tx_enqueue(sess, fr); 192 193 /* Keep track of this request and the ICQ number and request ID */ 194 info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info)); 195 info->reqid = snacid; 196 info->uin = atoi(uin); 197 info->next = sess->icq_info; 198 sess->icq_info = info; 199 200 return 0; 201 } 202 203 faim_export int aim_icq_getalias(aim_session_t *sess, const char *uin) 204 { 205 aim_conn_t *conn; 206 aim_frame_t *fr; 207 aim_snacid_t snacid; 208 int bslen; 209 struct aim_icq_info *info; 210 211 if (!uin || uin[0] < '0' || uin[0] > '9') 212 return -EINVAL; 213 214 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 215 return -EINVAL; 216 217 bslen = 2 + 4 + 2 + 2 + 2 + 4; 218 219 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 220 return -ENOMEM; 221 222 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 223 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 224 225 /* For simplicity, don't bother using a tlvlist */ 226 aimbs_put16(&fr->data, 0x0001); 227 aimbs_put16(&fr->data, bslen); 228 229 aimbs_putle16(&fr->data, bslen - 2); 230 aimbs_putle32(&fr->data, atoi(sess->sn)); 231 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 232 aimbs_putle16(&fr->data, snacid); /* eh. */ 233 aimbs_putle16(&fr->data, 0x04ba); /* shrug. */ 234 aimbs_putle32(&fr->data, atoi(uin)); 235 236 aim_tx_enqueue(sess, fr); 237 238 /* Keep track of this request and the ICQ number and request ID */ 239 info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info)); 240 info->reqid = snacid; 241 info->uin = atoi(uin); 242 info->next = sess->icq_info; 243 sess->icq_info = info; 244 245 return 0; 246 } 247 248 faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin) 249 { 250 aim_conn_t *conn; 251 aim_frame_t *fr; 252 aim_snacid_t snacid; 253 int bslen; 254 255 if (!uin || uin[0] < '0' || uin[0] > '9') 256 return -EINVAL; 257 258 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 259 return -EINVAL; 260 261 bslen = 2 + 4 + 2 + 2 + 2 + 4; 262 263 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 264 return -ENOMEM; 265 266 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 267 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 268 269 /* For simplicity, don't bother using a tlvlist */ 270 aimbs_put16(&fr->data, 0x0001); 271 aimbs_put16(&fr->data, bslen); 272 273 aimbs_putle16(&fr->data, bslen - 2); 274 aimbs_putle32(&fr->data, atoi(sess->sn)); 275 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 276 aimbs_putle16(&fr->data, snacid); /* eh. */ 277 aimbs_putle16(&fr->data, 0x051f); /* shrug. */ 278 aimbs_putle32(&fr->data, atoi(uin)); 279 280 aim_tx_enqueue(sess, fr); 281 282 return 0; 283 } 284 73 285 faim_export int aim_icq_sendxmlreq(aim_session_t *sess, const char *xml) 74 286 { … … 109 321 } 110 322 111 faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin) 112 { 113 aim_conn_t *conn; 114 aim_frame_t *fr; 115 aim_snacid_t snacid; 116 int bslen; 117 118 if (!uin || uin[0] < '0' || uin[0] > '9') 119 return -EINVAL; 120 121 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) 122 return -EINVAL; 123 124 bslen = 2 + 4 + 2 + 2 + 2 + 4; 125 126 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) 127 return -ENOMEM; 128 129 snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); 130 aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); 131 132 /* For simplicity, don't bother using a tlvlist */ 133 aimbs_put16(&fr->data, 0x0001); 134 aimbs_put16(&fr->data, bslen); 135 136 aimbs_putle16(&fr->data, bslen - 2); 137 aimbs_putle32(&fr->data, atoi(sess->sn)); 138 aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ 139 aimbs_putle16(&fr->data, snacid); /* eh. */ 140 aimbs_putle16(&fr->data, 0x051f); /* shrug. */ 141 aimbs_putle32(&fr->data, atoi(uin)); 142 143 aim_tx_enqueue(sess, fr); 144 145 return 0; 146 } 147 148 /* 149 * Response to 15/2, contains an ICQ packet. 323 static void aim_icq_freeinfo(struct aim_icq_info *info) { 324 int i; 325 326 if (!info) 327 return; 328 free(info->nick); 329 free(info->first); 330 free(info->last); 331 free(info->email); 332 free(info->homecity); 333 free(info->homestate); 334 free(info->homephone); 335 free(info->homefax); 336 free(info->homeaddr); 337 free(info->mobile); 338 free(info->homezip); 339 free(info->personalwebpage); 340 if (info->email2) 341 for (i = 0; i < info->numaddresses; i++) 342 free(info->email2[i]); 343 free(info->email2); 344 free(info->workcity); 345 free(info->workstate); 346 free(info->workphone); 347 free(info->workfax); 348 free(info->workaddr); 349 free(info->workzip); 350 free(info->workcompany); 351 free(info->workdivision); 352 free(info->workposition); 353 free(info->workwebpage); 354 free(info->info); 355 free(info); 356 } 357 358 /** 359 * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet. 150 360 */ 151 361 static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) … … 173 383 faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); 174 384 175 if (cmd == 0x0041) { 176 fu16_t msglen; 385 if (cmd == 0x0041) { /* offline message */ 177 386 struct aim_icq_offlinemsg msg; 178 387 aim_rxcallback_t userfunc; … … 186 395 msg.hour = aimbs_getle8(&qbs); 187 396 msg.minute = aimbs_getle8(&qbs); 188 msg.type = aimbs_getle16(&qbs); 189 msglen = aimbs_getle16(&qbs); 190 msg.msg = aimbs_getstr(&qbs, msglen); 397 msg.type = aimbs_getle8(&qbs); 398 msg.flags = aimbs_getle8(&qbs); 399 msg.msglen = aimbs_getle16(&qbs); 400 msg.msg = aimbs_getstr(&qbs, msg.msglen); 191 401 192 402 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) … … 200 410 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) 201 411 ret = userfunc(sess, rx); 202 } else if (cmd == 0x07da) { 412 413 } else if (cmd == 0x07da) { /* information */ 203 414 fu16_t subtype; 415 struct aim_icq_info *info; 416 aim_rxcallback_t userfunc; 204 417 205 418 subtype = aimbs_getle16(&qbs); 206 207 if (subtype == 0x019a) { 208 fu16_t tlen; 209 struct aim_icq_simpleinfo info; 210 aim_rxcallback_t userfunc; 211 212 memset(&info, 0, sizeof(info)); 213 214 aimbs_getle8(&qbs); /* no clue */ 215 aimbs_getle16(&qbs); /* no clue */ 216 info.uin = aimbs_getle32(&qbs); 217 tlen = aimbs_getle16(&qbs); 218 info.nick = aimbs_getstr(&qbs, tlen); 219 tlen = aimbs_getle16(&qbs); 220 info.first = aimbs_getstr(&qbs, tlen); 221 tlen = aimbs_getle16(&qbs); 222 info.last = aimbs_getstr(&qbs, tlen); 223 tlen = aimbs_getle16(&qbs); 224 info.email = aimbs_getstr(&qbs, tlen); 225 /* no clue what the rest of it is */ 226 227 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO))) 228 ret = userfunc(sess, rx, &info); 229 230 free(info.nick); 231 free(info.first); 232 free(info.last); 233 free(info.email); 419 aim_bstream_advance(&qbs, 1); /* 0x0a */ 420 421 /* find other data from the same request */ 422 for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next); 423 if (!info) { 424 info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info)); 425 info->reqid = reqid; 426 info->next = sess->icq_info; 427 sess->icq_info = info; 234 428 } 235 429 430 switch (subtype) { 431 case 0x00a0: { /* hide ip status */ 432 /* nothing */ 433 } break; 434 435 case 0x00aa: { /* password change status */ 436 /* nothing */ 437 } break; 438 439 case 0x00c8: { /* general and "home" information */ 440 info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 441 info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 442 info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 443 info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 444 info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 445 info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 446 info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 447 info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 448 info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 449 info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 450 info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 451 info->homecountry = aimbs_getle16(&qbs); 452 /* 0x0a 00 02 00 */ 453 /* 1 byte timezone? */ 454 /* 1 byte hide email flag? */ 455 } break; 456 457 case 0x00dc: { /* personal information */ 458 info->age = aimbs_getle8(&qbs); 459 info->unknown = aimbs_getle8(&qbs); 460 info->gender = aimbs_getle8(&qbs); 461 info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 462 info->birthyear = aimbs_getle16(&qbs); 463 info->birthmonth = aimbs_getle8(&qbs); 464 info->birthday = aimbs_getle8(&qbs); 465 info->language1 = aimbs_getle8(&qbs); 466 info->language2 = aimbs_getle8(&qbs); 467 info->language3 = aimbs_getle8(&qbs); 468 /* 0x00 00 01 00 00 01 00 00 00 00 00 */ 469 } break; 470 471 case 0x00d2: { /* work information */ 472 info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 473 info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 474 info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 475 info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 476 info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 477 info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 478 info->workcountry = aimbs_getle16(&qbs); 479 info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 480 info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 481 info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 482 aim_bstream_advance(&qbs, 2); /* 0x01 00 */ 483 info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 484 } break; 485 486 case 0x00e6: { /* additional personal information */ 487 info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)-1); 488 } break; 489 490 case 0x00eb: { /* email address(es) */ 491 int i; 492 info->numaddresses = aimbs_getle16(&qbs); 493 info->email2 = (char **)calloc(info->numaddresses, sizeof(char *)); 494 for (i = 0; i < info->numaddresses; i++) { 495 info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 496 if (i+1 != info->numaddresses) 497 aim_bstream_advance(&qbs, 1); /* 0x00 */ 498 } 499 } break; 500 501 case 0x00f0: { /* personal interests */ 502 } break; 503 504 case 0x00fa: { /* past background and current organizations */ 505 } break; 506 507 case 0x0104: { /* alias info */ 508 info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 509 info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 510 info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 511 aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); /* email address? */ 512 /* Then 0x00 02 00 */ 513 } break; 514 515 case 0x010e: { /* unknown */ 516 /* 0x00 00 */ 517 } break; 518 519 case 0x019a: { /* simple info */ 520 aim_bstream_advance(&qbs, 2); 521 info->uin = aimbs_getle32(&qbs); 522 info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 523 info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 524 info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 525 info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); 526 /* Then 0x00 02 00 00 00 00 00 */ 527 } break; 528 } /* End switch statement */ 529 530 if (!(snac->flags & 0x0001)) { 531 if (subtype != 0x0104) 532 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO))) 533 ret = userfunc(sess, rx, info); 534 535 if (info->uin && info->nick) 536 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALIAS))) 537 ret = userfunc(sess, rx, info); 538 539 if (sess->icq_info == info) { 540 sess->icq_info = info->next; 541 } else { 542 struct aim_icq_info *cur; 543 for (cur=sess->icq_info; (cur->next && (cur->next!=info)); cur=cur->next); 544 if (cur->next) 545 cur->next = cur->next->next; 546 } 547 aim_icq_freeinfo(info); 548 } 236 549 } 237 550 … … 248 561 249 562 return 0; 563 } 564 565 static void icq_shutdown(aim_session_t *sess, aim_module_t *mod) 566 { 567 struct aim_icq_info *del; 568 569 while (sess->icq_info) { 570 del = sess->icq_info; 571 sess->icq_info = sess->icq_info->next; 572 aim_icq_freeinfo(del); 573 } 574 575 return; 250 576 } 251 577 … … 256 582 mod->version = 0x0001; 257 583 mod->toolid = 0x0110; 258 mod->toolversion = 0x047 b;584 mod->toolversion = 0x047c; 259 585 mod->flags = 0; 260 586 strncpy(mod->name, "icq", sizeof(mod->name)); 261 587 mod->snachandler = snachandler; 262 263 return 0; 264 } 588 mod->shutdown = icq_shutdown; 589 590 return 0; 591 } -
libfaim/im.c
r862371b re374dee 1 1 /* 2 * Family 0x0004 - Routines for sending/receiving Instant Messages. 3 * 4 * Note the term ICBM (Inter-Client Basic Message) which blankets 5 * all types of genericly routed through-server messages. Within 6 * the ICBM types (family 4), a channel is defined. Each channel 7 * represents a different type of message. Channel 1 is used for 8 * what would commonly be called an "instant message". Channel 2 9 * is used for negotiating "rendezvous". These transactions end in 10 * something more complex happening, such as a chat invitation, or 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. 15 * 16 * In addition to the channel, every ICBM contains a cookie. For 17 * standard IMs, these are only used for error messages. However, 18 * the more complex rendezvous messages make suitably more complex 19 * use of this field. 20 * 2 * Family 0x0004 - Routines for sending/receiving Instant Messages. 3 * 4 * Note the term ICBM (Inter-Client Basic Message) which blankets 5 * all types of genericly routed through-server messages. Within 6 * the ICBM types (family 4), a channel is defined. Each channel 7 * represents a different type of message. Channel 1 is used for 8 * what would commonly be called an "instant message". Channel 2 9 * is used for negotiating "rendezvous". These transactions end in 10 * something more complex happening, such as a chat invitation, or 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. 15 * 16 * In addition to the channel, every ICBM contains a cookie. For 17 * standard IMs, these are only used for error messages. However, 18 * the more complex rendezvous messages make suitably more complex 19 * use of this field. 20 * 21 * TODO: Split this up into an im.c file an an icbm.c file. It 22 * will be beautiful, you'll see. 23 * 24 * Need to rename all the mpmsg messages to aim_im_bleh. 25 * 26 * Make sure aim_conn_findbygroup is used by all functions. 21 27 */ 22 28 … … 27 33 #include "win32dep.h" 28 34 #endif 35 36 /** 37 * Add a standard ICBM header to the given bstream with the given 38 * information. 39 * 40 * @param bs The bstream to write the ICBM header to. 41 * @param c c is for cookie, and cookie is for me. 42 * @param ch The ICBM channel (1 through 4). 43 * @param sn Null-terminated scrizeen nizame. 44 * @return The number of bytes written. It's really not useful. 45 */ 46 static int aim_im_puticbm(aim_bstream_t *bs, const fu8_t *c, fu16_t ch, const char *sn) 47 { 48 aimbs_putraw(bs, c, 8); 49 aimbs_put16(bs, ch); 50 aimbs_put8(bs, strlen(sn)); 51 aimbs_putraw(bs, sn, strlen(sn)); 52 return 8+2+1+strlen(sn); 53 } 29 54 30 55 /* … … 38 63 * 39 64 * Heres the current collection: 40 * 0501 0003 0101 0101 01 41 * 0501 0003 0101 0201 01 42 * 43 * 0501 0004 0101 0102 0101 44 * 0501 0003 0101 02 45 * 0501 0001 01 iChat x.x46 * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any47 * TOC client65 * 0501 0003 0101 0101 01 AOL Mobile Communicator, WinAIM 1.0.414 66 * 0501 0003 0101 0201 01 WinAIM 2.0.847, 2.1.1187, 3.0.1464, 67 * 4.3.2229, 4.4.2286 68 * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here) 69 * 0501 0003 0101 02 WinAIM 5 70 * 0501 0001 01 iChat x.x, mobile buddies 71 * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any TOC client 72 * 0501 0002 0106 WinICQ 5.45.1.3777.85 48 73 * 49 74 * Note that in this function, only the feature bytes are tested, since … … 51 76 * 52 77 */ 53 faim_export fu16_t aim_ fingerprintclient(fu8_t *msghdr, int len)78 faim_export fu16_t aim_im_fingerprint(const fu8_t *msghdr, int len) 54 79 { 55 80 static const struct { … … 91 116 } 92 117 93 /* 94 * Subtype 0x0002 118 /** 119 * Subtype 0x0002 - Set ICBM parameters. 95 120 * 96 121 * 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.122 * with the rather unreasonable defaults. 98 123 * 99 124 */ 100 faim_export int aim_ seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)125 faim_export int aim_im_setparams(aim_session_t *sess, struct aim_icbmparameters *params) 101 126 { 102 127 aim_conn_t *conn; … … 131 156 } 132 157 133 /* Subtype 0x0004 - Request ICBM parameter information. */ 134 faim_export int aim_reqicbmparams(aim_session_t *sess) 158 /** 159 * Subtype 0x0004 - Request ICBM parameter information. 160 * 161 */ 162 faim_export int aim_im_reqparams(aim_session_t *sess) 135 163 { 136 164 aim_conn_t *conn; … … 142 170 } 143 171 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 { 172 /** 173 * Subtype 0x0005 - Receive parameter information. 174 * 175 */ 176 static int aim_im_paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 177 { 178 aim_rxcallback_t userfunc; 147 179 struct aim_icbmparameters params; 148 aim_rxcallback_t userfunc;149 180 150 181 params.maxchan = aimbs_get16(bs); … … 161 192 } 162 193 163 /* This should be endian-safe now... but who knows... */ 164 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen) 165 { 166 fu32_t sum; 167 int i; 168 169 for (i = 0, sum = 0; i + 1 < buflen; i += 2) 170 sum += (buf[i+1] << 8) + buf[i]; 171 if (i < buflen) 172 sum += buf[i]; 173 174 sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff); 175 176 return (fu16_t)sum; 177 } 178 179 /* 194 /** 180 195 * Subtype 0x0006 - Send an ICBM (instant message). 181 196 * … … 220 235 * instead of writing out the bytes manually. 221 236 * 222 * XXX more precise verification that we never send SNACs larger than 8192 223 * XXX check SNAC size for multipart 224 * 225 */ 226 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args) 227 { 228 static const fu8_t deffeatures[] = { 229 0x01, 0x01, 0x01, 0x02 230 }; 237 * XXX - more precise verification that we never send SNACs larger than 8192 238 * XXX - check SNAC size for multipart 239 * 240 */ 241 faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args) 242 { 231 243 aim_conn_t *conn; 232 int i, msgtlvlen;233 244 aim_frame_t *fr; 234 245 aim_snacid_t snacid; 246 fu8_t ck[8]; 247 int i, msgtlvlen; 248 static const fu8_t deffeatures[] = { 0x01, 0x01, 0x01, 0x02 }; 235 249 236 250 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) … … 275 289 return -ENOMEM; 276 290 277 /* XXX should be optional */291 /* XXX - should be optional */ 278 292 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); 279 293 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 280 294 281 295 /* 282 * Generate a random message cookie 296 * Generate a random message cookie 283 297 * 284 298 * We could cache these like we do SNAC IDs. (In fact, it … … 289 303 */ 290 304 for (i = 0; i < 8; i++) 291 aimbs_put8(&fr->data, (fu8_t) rand()); 292 293 /* 294 * Channel ID 295 */ 296 aimbs_put16(&fr->data, 0x0001); 297 298 /* 299 * Destination SN (prepended with byte length) 300 */ 301 aimbs_put8(&fr->data, strlen(args->destsn)); 302 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); 303 304 /* 305 * Message TLV (type 2). 306 */ 305 ck[i] = (fu8_t)rand(); 306 307 /* ICBM header */ 308 aim_im_puticbm(&fr->data, ck, 0x0001, args->destsn); 309 310 /* Message TLV (type 0x0002) */ 307 311 aimbs_put16(&fr->data, 0x0002); 308 312 aimbs_put16(&fr->data, msgtlvlen); 309 313 310 /* 311 * Features 312 * 313 */ 314 aimbs_put8(&fr->data, 0x05); 315 aimbs_put8(&fr->data, 0x01); 316 314 /* Features TLV (type 0x0501) */ 315 aimbs_put16(&fr->data, 0x0501); 317 316 if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { 318 317 aimbs_put16(&fr->data, args->featureslen); … … 326 325 aim_mpmsg_section_t *sec; 327 326 327 /* Insert each message part in a TLV (type 0x0101) */ 328 328 for (sec = args->mpmsg->parts; sec; sec = sec->next) { 329 329 aimbs_put16(&fr->data, 0x0101); … … 336 336 } else { 337 337 338 /* Insert message text in a TLV (type 0x0101) */ 338 339 aimbs_put16(&fr->data, 0x0101); 339 340 340 /* 341 * Message block length. 342 */ 341 /* Message block length */ 343 342 aimbs_put16(&fr->data, args->msglen + 0x04); 344 343 345 /* 346 * Character set. 347 */ 348 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) { 349 350 aimbs_put16(&fr->data, args->charset); 351 aimbs_put16(&fr->data, args->charsubset); 352 353 } else { 354 if (args->flags & AIM_IMFLAGS_UNICODE) 355 aimbs_put16(&fr->data, 0x0002); 356 else if (args->flags & AIM_IMFLAGS_ISO_8859_1) 357 aimbs_put16(&fr->data, 0x0003); 358 else 359 aimbs_put16(&fr->data, 0x0000); 360 361 aimbs_put16(&fr->data, 0x0000); 362 } 363 364 /* 365 * Message. Not terminated. 366 */ 344 /* Character set */ 345 aimbs_put16(&fr->data, args->charset); 346 aimbs_put16(&fr->data, args->charsubset); 347 348 /* Message. Not terminated */ 367 349 aimbs_putraw(&fr->data, args->msg, args->msglen); 368 350 } 369 351 370 /* 371 * Set the Request Acknowledge flag. 372 */ 373 if (args->flags & AIM_IMFLAGS_ACK) { 374 aimbs_put16(&fr->data, 0x0003); 375 aimbs_put16(&fr->data, 0x0000); 376 } 377 378 /* 379 * Set the Autoresponse flag. 380 */ 352 /* Set the Autoresponse flag */ 381 353 if (args->flags & AIM_IMFLAGS_AWAY) { 382 354 aimbs_put16(&fr->data, 0x0004); 355 aimbs_put16(&fr->data, 0x0000); 356 } else if (args->flags & AIM_IMFLAGS_ACK) { 357 /* Set the Request Acknowledge flag */ 358 aimbs_put16(&fr->data, 0x0003); 383 359 aimbs_put16(&fr->data, 0x0000); 384 360 } … … 414 390 aim_tx_enqueue(sess, fr); 415 391 392 /* Move this to receive aim_flap_nop and send aim_flap_nop */ 416 393 if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) 417 394 aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */ … … 421 398 422 399 /* 423 * Simple wrapper for aim_ send_im_ext()400 * Simple wrapper for aim_im_sendch1_ext() 424 401 * 425 402 * You cannot use aim_send_im if you need the HASICON flag. You must 426 * use aim_ send_im_ext directly for that.403 * use aim_im_sendch1_ext directly for that. 427 404 * 428 405 * aim_send_im also cannot be used if you require UNICODE messages, because 429 * that requires an explicit message length. Use aim_ send_im_ext().430 * 431 */ 432 faim_export int aim_ send_im(aim_session_t *sess, const char *destsn, fu16_t flags, const char *msg)406 * that requires an explicit message length. Use aim_im_sendch1_ext(). 407 * 408 */ 409 faim_export int aim_im_sendch1(aim_session_t *sess, const char *sn, fu16_t flags, const char *msg) 433 410 { 434 411 struct aim_sendimext_args args; 435 412 436 args.destsn = destsn;413 args.destsn = sn; 437 414 args.flags = flags; 438 415 args.msg = msg; 439 416 args.msglen = strlen(msg); 440 441 /* Make these don't get set by accident -- they need aim_send_im_ext */ 417 args.charset = 0x0000; 418 args.charsubset = 0x0000; 419 420 /* Make these don't get set by accident -- they need aim_im_sendch1_ext */ 442 421 args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART); 443 422 444 return aim_ send_im_ext(sess, &args);445 } 446 447 /* 448 * Subtype 0x0006 423 return aim_im_sendch1_ext(sess, &args); 424 } 425 426 /** 427 * Subtype 0x0006 - Send your icon to a given user. 449 428 * 450 429 * This is also performance sensitive. (If you can believe it...) 451 430 * 452 431 */ 453 faim_export int aim_ send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum)432 faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum) 454 433 { 455 434 aim_conn_t *conn; 456 int i;457 fu8_t ck[8];458 435 aim_frame_t *fr; 459 436 aim_snacid_t snacid; 437 fu8_t ck[8]; 438 int i; 460 439 461 440 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) … … 466 445 467 446 for (i = 0; i < 8; i++) 468 aimutil_put8(ck+i, (fu8_t) rand());447 ck[i] = (fu8_t)rand(); 469 448 470 449 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) … … 474 453 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 475 454 476 /* 477 * Cookie 478 */ 479 aimbs_putraw(&fr->data, ck, 8); 480 481 /* 482 * Channel (2) 483 */ 484 aimbs_put16(&fr->data, 0x0002); 485 486 /* 487 * Dest sn 488 */ 489 aimbs_put8(&fr->data, strlen(sn)); 490 aimbs_putraw(&fr->data, sn, strlen(sn)); 455 /* ICBM header */ 456 aim_im_puticbm(&fr->data, ck, 0x0002, sn); 491 457 492 458 /* … … 531 497 532 498 /* 533 * Subtype 0x0006 499 * Subtype 0x0006 - Send a rich text message. 534 500 * 535 501 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only … … 545 511 * 546 512 */ 547 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args) 548 { 549 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */ 513 faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args) 514 { 550 515 aim_conn_t *conn; 551 int i;552 fu8_t ck[8];553 516 aim_frame_t *fr; 554 517 aim_snacid_t snacid; 555 int servdatalen; 518 fu8_t ck[8]; 519 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */ 520 int i, servdatalen; 556 521 557 522 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) … … 564 529 565 530 for (i = 0; i < 8; i++) 566 aimutil_put8(ck+i, (fu8_t) rand());531 ck[i] = (fu8_t)rand(); 567 532 568 533 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen))) … … 572 537 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 573 538 574 /* 575 * Cookie 576 */ 577 aimbs_putraw(&fr->data, ck, 8); 578 579 /* 580 * Channel (2) 581 */ 582 aimbs_put16(&fr->data, 0x0002); 583 584 /* 585 * Dest sn 586 */ 587 aimbs_put8(&fr->data, strlen(args->destsn)); 588 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); 589 590 /* 591 * TLV t(0005) 592 * 593 * Encompasses everything below. 594 */ 539 /* ICBM header */ 540 aim_im_puticbm(&fr->data, ck, 0x0002, args->destsn); 541 542 /* TLV t(0005) - Encompasses everything below. */ 595 543 aimbs_put16(&fr->data, 0x0005); 596 544 aimbs_put16(&fr->data, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen); … … 600 548 aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY); 601 549 602 /* 603 * t(000a) l(0002) v(0001) 604 */ 550 /* t(000a) l(0002) v(0001) */ 605 551 aimbs_put16(&fr->data, 0x000a); 606 552 aimbs_put16(&fr->data, 0x0002); 607 553 aimbs_put16(&fr->data, 0x0001); 608 554 609 /* 610 * t(000f) l(0000) v() 611 */ 555 /* t(000f) l(0000) v() */ 612 556 aimbs_put16(&fr->data, 0x000f); 613 557 aimbs_put16(&fr->data, 0x0000); 614 558 615 /* 616 * Service Data TLV 617 */ 559 /* Service Data TLV */ 618 560 aimbs_put16(&fr->data, 0x2711); 619 561 aimbs_put16(&fr->data, servdatalen); … … 648 590 } 649 591 650 /* Subtype 0x0006 */ 651 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret) 592 /** 593 * Subtype 0x0006 - Send an "I want to directly connect to you" message 594 * 595 */ 596 faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port) 652 597 { 653 598 aim_conn_t *conn; 654 fu8_t ck[8];655 599 aim_frame_t *fr; 656 600 aim_snacid_t snacid; 601 fu8_t ck[8]; 657 602 aim_tlvlist_t *tl = NULL, *itl = NULL; 658 603 int hdrlen, i; … … 663 608 return -EINVAL; 664 609 665 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen( destsn))))610 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(sn)))) 666 611 return -ENOMEM; 667 612 … … 675 620 * TOC-compatible. 676 621 * 677 * XXX have I mentioned these should be generated in msgcookie.c?622 * XXX - have I mentioned these should be generated in msgcookie.c? 678 623 * 679 624 */ … … 682 627 ck[7] = '\0'; 683 628 684 if (ckret) 685 memcpy(ckret, ck, 8); 686 687 /* Cookie */ 688 aimbs_putraw(&fr->data, ck, 8); 689 690 /* Channel */ 691 aimbs_put16(&fr->data, 0x0002); 692 693 /* Destination SN */ 694 aimbs_put8(&fr->data, strlen(destsn)); 695 aimbs_putraw(&fr->data, destsn, strlen(destsn)); 629 if (cookie) 630 memcpy(cookie, ck, 8); 631 632 /* ICBM header */ 633 aim_im_puticbm(&fr->data, ck, 0x0002, sn); 696 634 697 635 aim_addtlvtochain_noval(&tl, 0x0003); … … 703 641 aimbs_put16(&hdrbs, 0x0000); 704 642 aimbs_putraw(&hdrbs, ck, 8); 705 aim_putcap(&hdrbs, AIM_CAPS_ IMIMAGE);643 aim_putcap(&hdrbs, AIM_CAPS_DIRECTIM); 706 644 707 645 aim_addtlvtochain16(&itl, 0x000a, 0x0001); … … 725 663 } 726 664 727 /* Subtype 0x0006 */ 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) 665 /** 666 * Subtype 0x0006 - Send an "I want to send you this file" message 667 * 668 */ 669 faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info) 729 670 { 730 671 aim_conn_t *conn; 731 int i;732 fu8_t ck[8];733 672 aim_frame_t *fr; 734 673 aim_snacid_t snacid; 735 struct aim_snac_destructor snacdest; 736 737 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 674 aim_tlvlist_t *tl=NULL, *subtl=NULL; 675 int i; 676 677 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info) 738 678 return -EINVAL; 739 679 740 if (!sn || !filename) 680 /* XXX - Should be like "21CBF95" and null terminated */ 681 for (i = 0; i < 7; i++) 682 oft_info->cookie[i] = 0x30 + ((fu8_t)rand() % 10); 683 oft_info->cookie[7] = '\0'; 684 685 { /* Create the subTLV chain */ 686 fu8_t *buf; 687 int buflen; 688 aim_bstream_t bs; 689 690 aim_addtlvtochain16(&subtl, 0x000a, 0x0001); 691 aim_addtlvtochain_noval(&subtl, 0x000f); 692 /* aim_addtlvtochain_raw(&subtl, 0x000e, 2, "en"); 693 aim_addtlvtochain_raw(&subtl, 0x000d, 8, "us-ascii"); 694 aim_addtlvtochain_raw(&subtl, 0x000c, 24, "Please accept this file."); */ 695 if (oft_info->clientip) { 696 fu8_t ip[4]; 697 char *nexttoken; 698 int i = 0; 699 nexttoken = strtok(oft_info->clientip, "."); 700 while (nexttoken && i<4) { 701 ip[i] = atoi(nexttoken); 702 nexttoken = strtok(NULL, "."); 703 i++; 704 } 705 aim_addtlvtochain_raw(&subtl, 0x0003, 4, ip); 706 } 707 aim_addtlvtochain16(&subtl, 0x0005, oft_info->port); 708 709 /* TLV t(2711) */ 710 buflen = 2+2+4+strlen(oft_info->fh.name)+1; 711 buf = malloc(buflen); 712 aim_bstream_init(&bs, buf, buflen); 713 aimbs_put16(&bs, (oft_info->fh.totfiles > 1) ? 0x0002 : 0x0001); 714 aimbs_put16(&bs, oft_info->fh.totfiles); 715 aimbs_put32(&bs, oft_info->fh.totsize); 716 717 /* Filename - NULL terminated, for some odd reason */ 718 aimbs_putraw(&bs, oft_info->fh.name, strlen(oft_info->fh.name)); 719 aimbs_put8(&bs, 0x00); 720 721 aim_addtlvtochain_raw(&subtl, 0x2711, bs.len, bs.data); 722 free(buf); 723 } 724 725 { /* Create the main TLV chain */ 726 fu8_t *buf; 727 int buflen; 728 aim_bstream_t bs; 729 730 /* TLV t(0005) - Encompasses everything from above. Gee. */ 731 buflen = 2+8+16+aim_sizetlvchain(&subtl); 732 buf = malloc(buflen); 733 aim_bstream_init(&bs, buf, buflen); 734 aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE); 735 aimbs_putraw(&bs, oft_info->cookie, 8); 736 aim_putcap(&bs, AIM_CAPS_SENDFILE); 737 aim_writetlvchain(&bs, &subtl); 738 aim_freetlvchain(&subtl); 739 aim_addtlvtochain_raw(&tl, 0x0005, bs.len, bs.data); 740 free(buf); 741 742 /* TLV t(0003) - Request an ack */ 743 aim_addtlvtochain_noval(&tl, 0x0003); 744 } 745 746 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + aim_sizetlvchain(&tl)))) 747 return -ENOMEM; 748 749 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, oft_info->cookie, sizeof(oft_info->cookie)); 750 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 751 752 /* ICBM header */ 753 aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn); 754 755 /* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */ 756 aim_writetlvchain(&fr->data, &tl); 757 aim_freetlvchain(&tl); 758 759 aim_tx_enqueue(sess, fr); 760 761 return 0; 762 } 763 764 /** 765 * Subtype 0x0006 - Send an "I will accept this file" message? 766 * 767 * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE) 768 */ 769 faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *oft_info) 770 { 771 aim_conn_t *conn; 772 aim_frame_t *fr; 773 aim_snacid_t snacid; 774 775 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info) 741 776 return -EINVAL; 742 777 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)))778 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16))) 744 779 return -ENOMEM; 745 780 746 for (i = 0; i < 7; i++) 747 aimutil_put8(ck+i, 0x30 + ((fu8_t) rand() % 10)); 748 ck[7] = '\0'; 749 750 if (ckret) 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)); 781 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 761 782 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 762 783 763 /* 764 * Cookie 765 */ 766 aimbs_putraw(&fr->data, ck, 8); 767 768 /* 769 * Channel (2) 770 */ 771 aimbs_put16(&fr->data, 0x0002); 772 773 /* 774 * Dest sn 775 */ 776 aimbs_put8(&fr->data, strlen(sn)); 777 aimbs_putraw(&fr->data, sn, strlen(sn)); 778 779 /* 780 * TLV t(0005) 781 * 782 * Encompasses everything below. Gee. 783 */ 784 /* ICBM header */ 785 aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn); 786 784 787 aimbs_put16(&fr->data, 0x0005); 785 aimbs_put16(&fr->data, 2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4); 786 787 aimbs_put16(&fr->data, 0x0000); 788 aimbs_putraw(&fr->data, ck, 8); 788 aimbs_put16(&fr->data, 0x001a); 789 aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT); 790 aimbs_putraw(&fr->data, oft_info->cookie, 8); 789 791 aim_putcap(&fr->data, AIM_CAPS_SENDFILE); 790 792 791 /* TLV t(000a) */ 792 aimbs_put16(&fr->data, 0x000a); 793 aimbs_put16(&fr->data, 0x0002); 794 aimbs_put16(&fr->data, 0x0001); 795 796 /* TLV t(0003) (IP) */ 797 aimbs_put16(&fr->data, 0x0003); 798 aimbs_put16(&fr->data, 0x0004); 799 aimbs_putraw(&fr->data, ip, 4); 800 801 /* TLV t(0005) (port) */ 793 aim_tx_enqueue(sess, fr); 794 795 return 0; 796 } 797 798 /** 799 * Subtype 0x0006 - Send a "cancel this file transfer" message? 800 * 801 */ 802 faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info) 803 { 804 aim_conn_t *conn; 805 aim_frame_t *fr; 806 aim_snacid_t snacid; 807 808 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info) 809 return -EINVAL; 810 811 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16))) 812 return -ENOMEM; 813 814 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 815 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 816 817 /* ICBM header */ 818 aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn); 819 802 820 aimbs_put16(&fr->data, 0x0005); 803 aimbs_put16(&fr->data, 0x0002); 804 aimbs_put16(&fr->data, port); 805 806 /* TLV t(000f) */ 807 aimbs_put16(&fr->data, 0x000f); 808 aimbs_put16(&fr->data, 0x0000); 809 810 /* TLV t(2711) */ 811 aimbs_put16(&fr->data, 0x2711); 812 aimbs_put16(&fr->data, 2+2+4+strlen(filename)+4); 813 814 /* ? */ 815 aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001); 816 aimbs_put16(&fr->data, numfiles); 817 aimbs_put32(&fr->data, totsize); 818 aimbs_putraw(&fr->data, filename, strlen(filename)); 819 820 /* ? */ 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 821 aimbs_put16(&fr->data, 0x001a); 822 aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL); 823 aimbs_putraw(&fr->data, oft_info->cookie, 8); 824 aim_putcap(&fr->data, AIM_CAPS_SENDFILE); 827 825 828 826 aim_tx_enqueue(sess, fr); … … 840 838 * @return Return 0 if no errors, otherwise return the error number. 841 839 */ 842 faim_export int aim_ send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type)840 faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type) 843 841 { 844 842 aim_conn_t *conn; 843 aim_frame_t *fr; 844 aim_snacid_t snacid; 845 845 int i; 846 846 fu8_t ck[8]; 847 aim_frame_t *fr;848 aim_snacid_t snacid;849 847 850 848 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn) … … 852 850 853 851 for (i = 0; i < 8; i++) 854 aimutil_put8(ck+i, (fu8_t) rand());852 ck[i] = (fu8_t)rand(); 855 853 856 854 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4))) … … 860 858 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 861 859 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)); 860 /* ICBM header */ 861 aim_im_puticbm(&fr->data, ck, 0x0002, sn); 871 862 872 863 /* TLV t(0005) - Encompasses almost everything below. */ … … 897 888 aimbs_putle16(&fr->data, 0x001b); /* L */ 898 889 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 */ 890 aim_putcap(&fr->data, AIM_CAPS_EMPTY); 903 891 aimbs_putle16(&fr->data, 0x0000); /* Unknown */ 904 892 aimbs_putle16(&fr->data, 0x0003); /* Client features? */ … … 927 915 aimbs_putle16(&fr->data, 0x0000); /* Status? */ 928 916 aimbs_putle16(&fr->data, 0x0001); /* Priority of this message? */ 929 aimbs_putle16(&fr->data, 0x0001); /* L ?*/930 aimbs_putle8(&fr->data, 0x00); /* Null termination?*/917 aimbs_putle16(&fr->data, 0x0001); /* L */ 918 aimbs_putle8(&fr->data, 0x00); /* String of length L */ 931 919 } /* End TLV t(2711) */ 932 920 } /* End TLV t(0005) */ … … 942 930 943 931 /** 944 * Subtype 0x0006 932 * Subtype 0x0006 - Send an ICQ-esque ICBM. 945 933 * 946 934 * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way." … … 955 943 * @return Return 0 if no errors, otherwise return the error number. 956 944 */ 957 faim_export int aim_ send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)945 faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message) 958 946 { 959 947 aim_conn_t *conn; … … 961 949 aim_snacid_t snacid; 962 950 int i; 951 char ck[8]; 963 952 964 953 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002))) … … 974 963 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 975 964 976 /* 977 * Cookie 978 */ 965 /* Cookie */ 979 966 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)); 967 ck[i] = (fu8_t)rand(); 968 969 /* ICBM header */ 970 aim_im_puticbm(&fr->data, ck, 0x0004, sn); 992 971 993 972 /* … … 1022 1001 } 1023 1002 1003 /* 1004 * XXX - I don't see when this would ever get called... 1005 */ 1024 1006 static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1025 1007 { … … 1177 1159 } 1178 1160 1179 /* XXX should provide a way of saying ISO-8859-1 specifically */1161 /* XXX - should provide a way of saying ISO-8859-1 specifically */ 1180 1162 faim_export int aim_mpmsg_addascii(aim_session_t *sess, aim_mpmsg_t *mpm, const char *ascii) 1181 1163 { … … 1280 1262 * the specified data length, which will not include the pad. 1281 1263 * 1282 * XXX There's an API bug here. For sending, the UNICODE is1264 * XXX - There's an API bug here. For sending, the UNICODE is 1283 1265 * given in host byte order (aim_mpmsg_addunicode), but here 1284 1266 * the received messages are given in network byte order. … … 1313 1295 args->charset = sec->charset; 1314 1296 args->charsubset = sec->charsubset; 1315 args->icbmflags |= AIM_IMFLAGS_CUSTOMCHARSET;1316 1297 1317 1298 /* Set up the simple flags */ … … 1331 1312 else if (args->charsubset == 0xffff) 1332 1313 ; /* no subencoding */ 1333 #if 01334 /* XXX this isn't really necesary... */1335 if ( ((args.flag1 != 0x0000) &&1336 (args.flag1 != 0x0002) &&1337 (args.flag1 != 0x0003) &&1338 (args.flag1 != 0xffff)) ||1339 ((args.flag2 != 0x0000) &&1340 (args.flag2 != 0x000b) &&1341 (args.flag2 != 0xffff))) {1342 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2);1343 }1344 #endif1345 1314 1346 1315 args->msg = sec->data; … … 1419 1388 } else if (type == 0x0006) { /* Message was received offline. */ 1420 1389 1421 /* XXX not sure if this actually gets sent. */1390 /* XXX - not sure if this actually gets sent. */ 1422 1391 args.icbmflags |= AIM_IMFLAGS_OFFLINE; 1423 1392 … … 1555 1524 { 1556 1525 1557 /* XXX aim_chat_roominfo_free() */1526 /* XXX - aim_chat_roominfo_free() */ 1558 1527 free(args->info.chat.roominfo.name); 1559 1528 … … 1616 1585 aim_bstream_advance(servdata, hdrlen); 1617 1586 1618 /* XXX This is such a hack. */1587 /* XXX - This is such a hack. */ 1619 1588 args->reqclass = AIM_CAPS_ICQRTF; 1620 1589 … … 1634 1603 args->destructor = (void *)incomingim_ch2_sendfile_free; 1635 1604 1636 if (servdata) { 1605 /* Maybe there is a better way to tell what kind of sendfile 1606 * this is? Maybe TLV t(000a)? */ 1607 if (servdata) { /* Someone is sending us a file */ 1637 1608 int flen; 1638 1609 … … 1642 1613 args->info.sendfile.totsize = aimbs_get32(servdata); 1643 1614 1644 /* XXX - create an aimbs_getnullstr function */ 1615 /* 1616 * I hope to God I'm right when I guess that there is a 1617 * 32 char max filename length for single files. I think 1618 * OFT tends to do that. Gotta love inconsistency. I saw 1619 * a 26 byte filename? 1620 */ 1621 /* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */ 1645 1622 /* Use an inelegant way of getting the null-terminated filename, 1646 1623 * since there's no easy bstream routine. */ … … 1651 1628 /* There is sometimes more after the null-terminated filename, 1652 1629 * but I'm unsure of its format. */ 1630 /* I don't believe him. */ 1653 1631 } 1654 1632 … … 1668 1646 int ret = 0; 1669 1647 1670 char clientip1[30] = {""};1671 char clientip 2[30] = {""};1648 char proxyip[30] = {""}; 1649 char clientip[30] = {""}; 1672 1650 char verifiedip[30] = {""}; 1673 1651 … … 1711 1689 1712 1690 /* 1713 * IP address from the perspective of the client. 1691 * IP address to proxy the file transfer through. 1692 * 1693 * XXX - I don't like this. Maybe just read in an int? Or inet_ntoa... 1714 1694 */ 1715 1695 if (aim_gettlv(list2, 0x0002, 1)) { … … 1717 1697 1718 1698 iptlv = aim_gettlv(list2, 0x0002, 1); 1719 1720 snprintf(clientip1, sizeof(clientip1), "%d.%d.%d.%d", 1721 aimutil_get8(iptlv->value+0), 1722 aimutil_get8(iptlv->value+1), 1723 aimutil_get8(iptlv->value+2), 1724 aimutil_get8(iptlv->value+3)); 1725 } 1726 1727 /* 1728 * Secondary IP address from the perspective of the client. 1699 if (iptlv->length == 4) 1700 snprintf(proxyip, sizeof(proxyip), "%hhd.%hhd.%hhd.%hhd", 1701 iptlv->value[0], iptlv->value[1], 1702 iptlv->value[2], iptlv->value[3]); 1703 } 1704 1705 /* 1706 * IP address from the perspective of the client. 1729 1707 */ 1730 1708 if (aim_gettlv(list2, 0x0003, 1)) { … … 1732 1710 1733 1711 iptlv = aim_gettlv(list2, 0x0003, 1); 1734 1735 snprintf(clientip2, sizeof(clientip2), "%d.%d.%d.%d", 1736 aimutil_get8(iptlv->value+0), 1737 aimutil_get8(iptlv->value+1), 1738 aimutil_get8(iptlv->value+2), 1739 aimutil_get8(iptlv->value+3)); 1712 if (iptlv->length == 4) 1713 snprintf(clientip, sizeof(clientip), "%hhd.%hhd.%hhd.%hhd", 1714 iptlv->value[0], iptlv->value[1], 1715 iptlv->value[2], iptlv->value[3]); 1740 1716 } 1741 1717 … … 1749 1725 1750 1726 iptlv = aim_gettlv(list2, 0x0004, 1); 1751 1752 snprintf(verifiedip, sizeof(verifiedip), "%d.%d.%d.%d", 1753 aimutil_get8(iptlv->value+0), 1754 aimutil_get8(iptlv->value+1), 1755 aimutil_get8(iptlv->value+2), 1756 aimutil_get8(iptlv->value+3)); 1727 if (iptlv->length == 4) 1728 snprintf(verifiedip, sizeof(verifiedip), "%hhd.%hhd.%hhd.%hhd", 1729 iptlv->value[0], iptlv->value[1], 1730 iptlv->value[2], iptlv->value[3]); 1757 1731 } 1758 1732 … … 1762 1736 if (aim_gettlv(list2, 0x0005, 1)) 1763 1737 args.port = aim_gettlv16(list2, 0x0005, 1); 1738 1739 /* 1740 * Something to do with ft -- two bytes 1741 * 0x0001 - "I want to send you this file" 1742 * 0x0002 - "I will accept this file from you" 1743 */ 1744 if (aim_gettlv(list2, 0x000a, 1)) 1745 ; 1764 1746 1765 1747 /* … … 1787 1769 args.language = aim_gettlv_str(list2, 0x000e, 1); 1788 1770 1789 /* Unknown -- two bytes = 0x0001 */1790 if (aim_gettlv(list2, 0x000a, 1))1791 ;1792 1793 /* Unknown -- no value*/1771 /* 1772 * Unknown -- no value 1773 * 1774 * Maybe means we should connect directly to transfer the file? 1775 */ 1794 1776 if (aim_gettlv(list2, 0x000f, 1)) 1795 1777 ; 1796 1778 1797 if (strlen(clientip1)) 1798 args.clientip = (char *)clientip1; 1799 if (strlen(clientip2)) 1800 args.clientip2 = (char *)clientip2; 1779 /* 1780 * Unknown -- no value 1781 * 1782 * Maybe means we should proxy the file transfer through an AIM server? 1783 */ 1784 if (aim_gettlv(list2, 0x0010, 1)) 1785 ; 1786 1787 if (strlen(proxyip)) 1788 args.proxyip = (char *)proxyip; 1789 if (strlen(clientip)) 1790 args.clientip = (char *)clientip; 1801 1791 if (strlen(verifiedip)) 1802 1792 args.verifiedip = (char *)verifiedip; 1803 1793 1804 1794 /* 1805 * This ismust be present in PROPOSALs, but will probably not1795 * This must be present in PROPOSALs, but will probably not 1806 1796 * exist in CANCELs and ACCEPTs. 1807 1797 * … … 1863 1853 1864 1854 args.uin = aimbs_getle32(&meat); 1865 args.type = aimbs_getle16(&meat); 1866 args.msg = aimbs_getraw(&meat, aimbs_getle16(&meat)); 1855 args.type = aimbs_getle8(&meat); 1856 args.flags = aimbs_getle8(&meat); 1857 args.msglen = aimbs_getle16(&meat); 1858 args.msg = aimbs_getraw(&meat, args.msglen); 1867 1859 1868 1860 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) … … 1905 1897 * Channel ID. 1906 1898 * 1907 * Channel 0x0001 is the message channel. There are 1908 * other channels for things called "rendevous" 1909 * which represent chat and some of the other new 1910 * features of AIM2/3/3.5. 1899 * Channel 0x0001 is the message channel. It is 1900 * used to send basic ICBMs. 1911 1901 * 1912 1902 * Channel 0x0002 is the Rendevous channel, which 1913 1903 * is where Chat Invitiations and various client-client 1914 1904 * connection negotiations come from. 1905 * 1906 * Channel 0x0003 is used for chat messages. 1915 1907 * 1916 1908 * Channel 0x0004 is used for ICQ authorization, or … … 1927 1919 * userinfo block contains the number of TLVs that contain user 1928 1920 * information, the rest are not even though there is no seperation. 1929 * aim_extractuserinfo() returns the number of bytes used by the 1930 * userinfo tlvs, so you can start reading the rest of them right 1931 * afterward. 1921 * You can start reading the message TLVs after aim_info_extract() 1922 * parses out the standard userinfo block. 1932 1923 * 1933 1924 * That also means that TLV types can be duplicated between the … … 1936 1927 * 1937 1928 */ 1938 aim_ extractuserinfo(sess, bs, &userinfo);1929 aim_info_extract(sess, bs, &userinfo); 1939 1930 1940 1931 /* … … 1970 1961 1971 1962 } else { 1972 1973 faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); 1974 1975 return 0; 1976 } 1963 faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel. Ignoring. (chan = %04x)\n", channel); 1964 } 1965 1966 aim_info_free(&userinfo); 1977 1967 1978 1968 return ret; … … 1980 1970 1981 1971 /* 1982 * Subtype 0x0008 - Send a warning to destsn.1972 * Subtype 0x0008 - Send a warning to sn. 1983 1973 * 1984 1974 * Flags: … … 1988 1978 * 1989 1979 */ 1990 faim_export int aim_ send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags)1980 faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu32_t flags) 1991 1981 { 1992 1982 aim_frame_t *fr; 1993 1983 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))) 1984 1985 if (!sess || !conn || !sn) 1986 return -EINVAL; 1987 1988 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13))) 1997 1989 return -ENOMEM; 1998 1990 1999 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); 2000 1991 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1); 2001 1992 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); 2002 1993 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)); 1994 aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); 1995 aimbs_put8(&fr->data, strlen(sn)); 1996 aimbs_putraw(&fr->data, sn, strlen(sn)); 2009 1997 2010 1998 aim_tx_enqueue(sess, fr); … … 2024 2012 2025 2013 channel = aimbs_get16(bs); 2026 aim_ extractuserinfo(sess, bs, &userinfo);2014 aim_info_extract(sess, bs, &userinfo); 2027 2015 nummissed = aimbs_get16(bs); 2028 2016 reason = aimbs_get16(bs); … … 2030 2018 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2031 2019 ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason); 2020 2021 aim_info_free(&userinfo); 2032 2022 } 2033 2023 … … 2044 2034 * 2045 2035 */ 2046 faim_export int aim_ denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code)2036 faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code) 2047 2037 { 2048 2038 aim_conn_t *conn; … … 2096 2086 2097 2087 if (channel == 0x0002) { /* File transfer declined */ 2088 aimbs_get16(bs); /* Unknown */ 2089 aimbs_get16(bs); /* Unknown */ 2098 2090 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2099 2091 ret = userfunc(sess, rx, channel, sn, reason, ck); … … 2159 2151 } 2160 2152 2161 /* Subtype 0x000c */ 2153 /* 2154 * Subtype 0x000c - Receive an ack after sending an ICBM. 2155 * 2156 * You have to have send the message with the AIM_IMFLAGS_ACK flag set 2157 * (TLV t(0003)). The ack contains the ICBM header of the message you 2158 * sent. 2159 * 2160 */ 2162 2161 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2163 2162 { 2164 2163 aim_rxcallback_t userfunc; 2165 fu16_t type;2166 fu8_t snlen,*ck;2164 fu16_t ch; 2165 fu8_t *ck; 2167 2166 char *sn; 2168 2167 int ret = 0; 2169 2168 2170 2169 ck = aimbs_getraw(bs, 8); 2171 type = aimbs_get16(bs); 2172 snlen = aimbs_get8(bs); 2173 sn = aimbs_getstr(bs, snlen); 2170 ch = aimbs_get16(bs); 2171 sn = aimbs_getstr(bs, aimbs_get8(bs)); 2174 2172 2175 2173 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2176 ret = userfunc(sess, rx, type, sn);2174 ret = userfunc(sess, rx, ch, sn); 2177 2175 2178 2176 free(sn); … … 2189 2187 * 2190 2188 */ 2191 faim_export int aim_ mtn_send(aim_session_t *sess, fu16_t type1,char *sn, fu16_t type2)2189 faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2) 2192 2190 { 2193 2191 aim_conn_t *conn; … … 2270 2268 2271 2269 if (snac->subtype == 0x0005) 2272 return paraminfo(sess, mod, rx, snac, bs);2270 return aim_im_paraminfo(sess, mod, rx, snac, bs); 2273 2271 else if (snac->subtype == 0x0006) 2274 2272 return outgoingim(sess, mod, rx, snac, bs); … … 2287 2285 } 2288 2286 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;2300 }2301 2302 2287 faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod) 2303 2288 { … … 2306 2291 mod->version = 0x0001; 2307 2292 mod->toolid = 0x0110; 2308 mod->toolversion = 0x0 47b;2293 mod->toolversion = 0x0629; 2309 2294 mod->flags = 0; 2310 2295 strncpy(mod->name, "messaging", sizeof(mod->name)); 2311 2296 mod->snachandler = snachandler; 2312 mod->snacdestructor = snacdestructor;2313 2297 2314 2298 return 0; -
libfaim/info.c
r862371b re374dee 9 9 #define FAIM_INTERNAL 10 10 #include <aim.h> 11 #ifdef _WIN32 12 #include "win32dep.h" 13 #endif 11 14 12 15 struct aim_priv_inforeq { … … 30 33 * 31 34 * Gives BOS your profile. 35 * 36 * profile_encoding and awaymsg_encoding MUST be set if profile or 37 * away are set, respectively, and their value may or may not be 38 * restricted to a few choices. I am currently aware of: 32 39 * 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\""}; 40 * us-ascii Just that 41 * unicode-2-0 UCS2-BE 42 * 43 * profile_len and awaymsg_len MUST be set similarly, and they MUST 44 * be the length of their respective strings in bytes. 45 * 46 * To get the previous behavior of awaymsg == "" un-setting the away 47 * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the 48 * obvious equivalent). 49 * 50 */ 51 faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, 52 const char *profile_encoding, const char *profile, const int profile_len, 53 const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len, 54 fu32_t caps) 55 { 56 static const char defencoding[] = {"text/aolrtf; charset=\"%s\""}; 37 57 aim_frame_t *fr; 38 58 aim_tlvlist_t *tl = NULL; 39 59 aim_snacid_t snacid; 60 char *encoding; 61 62 if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) { 63 return -EINVAL; 64 } 40 65 41 66 /* Build to packet first to get real length */ 42 67 if (profile) { 43 aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding); 44 aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile); 68 /* no + 1 here because of %s */ 69 encoding = malloc(strlen(defencoding) + strlen(profile_encoding)); 70 if (encoding == NULL) { 71 return -ENOMEM; 72 } 73 snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding); 74 aim_addtlvtochain_raw(&tl, 0x0001, strlen(encoding), encoding); 75 aim_addtlvtochain_raw(&tl, 0x0002, profile_len, profile); 76 free(encoding); 45 77 } 46 78 … … 54 86 */ 55 87 if (awaymsg) { 56 if (strlen(awaymsg)) { 57 aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding); 58 aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg); 88 if (awaymsg_len) { 89 encoding = malloc(strlen(defencoding) + strlen(awaymsg_encoding)); 90 if (encoding == NULL) { 91 return -ENOMEM; 92 } 93 snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding); 94 aim_addtlvtochain_raw(&tl, 0x0003, strlen(encoding), encoding); 95 aim_addtlvtochain_raw(&tl, 0x0004, awaymsg_len, awaymsg); 96 free(encoding); 59 97 } else 60 98 aim_addtlvtochain_noval(&tl, 0x0004); … … 205 243 206 244 /* 207 * Chat is oddball. 208 */ 209 {AIM_CAPS_CHAT, 210 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 211 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 212 213 /* 214 * These are mostly in order. 215 */ 245 * These are in ascending numerical order. 246 */ 247 {AIM_CAPS_ICHAT, 248 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1, 249 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 250 251 {AIM_CAPS_SECUREIM, 252 {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1, 253 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 254 255 {AIM_CAPS_HIPTOP, 256 {0x09, 0x46, 0x13, 0x23, 0x4c, 0x7f, 0x11, 0xd1, 257 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 258 216 259 {AIM_CAPS_VOICE, 217 260 {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, … … 229 272 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 230 273 231 {AIM_CAPS_ IMIMAGE,274 {AIM_CAPS_DIRECTIM, 232 275 {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, 233 276 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, … … 237 280 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 238 281 282 /* 283 * Windows AIM calls this "Add-ins," which is probably more accurate 284 */ 239 285 {AIM_CAPS_SAVESTOCKS, 240 286 {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1, … … 266 312 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 267 313 268 /* from ICQ2002a 269 {AIM_CAPS_ICQUNKNOWN2, 314 /* 315 * Setting this lets AIM users receive messages from ICQ users, and ICQ 316 * users receive messages from AIM users. It also lets ICQ users show 317 * up in buddy lists for AIM users, and AIM users show up in buddy lists 318 * for ICQ users. And ICQ privacy/invisibility acts like AIM privacy, 319 * in that if you add a user to your deny list, you will not be able to 320 * see them as online (previous you could still see them, but they 321 * couldn't see you. 322 */ 323 {AIM_CAPS_INTEROPERATE, 324 {0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1, 325 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 326 327 {AIM_CAPS_ICQUTF8, 270 328 {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1, 271 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, */ 329 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 330 331 {AIM_CAPS_ICQUTF8OLD, 332 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, 333 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}}, 334 335 /* 336 * Chat is oddball. 337 */ 338 {AIM_CAPS_CHAT, 339 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 340 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 341 342 /* 343 {AIM_CAPS_ICQ2GO, 344 {0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, 345 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3}}, 346 */ 272 347 273 348 {AIM_CAPS_ICQRTF, 274 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 349 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 275 350 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}}, 276 351 … … 280 355 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}}, */ 281 356 282 {AIM_CAPS_ICQUNKNOWN, 283 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, 284 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}}, 357 {AIM_CAPS_APINFO, 358 {0xaa, 0x4a, 0x32, 0xb5, 0xf8, 0x84, 0x48, 0xc6, 359 0xa3, 0xd7, 0x8c, 0x50, 0x97, 0x19, 0xfd, 0x5b}}, 360 361 {AIM_CAPS_TRILLIANCRYPT, 362 {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb, 363 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}}, 285 364 286 365 {AIM_CAPS_EMPTY, 287 366 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 288 367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 289 290 {AIM_CAPS_TRILLIANCRYPT,291 {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,292 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},293 294 {AIM_CAPS_APINFO,295 {0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6,296 0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}},297 368 298 369 {AIM_CAPS_LAST} … … 385 456 } 386 457 458 faim_internal void aim_info_free(aim_userinfo_t *info) 459 { 460 free(info->iconcsum); 461 free(info->availmsg_encoding); 462 free(info->availmsg); 463 } 464 387 465 /* 388 466 * AIM is fairly regular about providing user info. This is a generic 389 467 * routine to extract it in its standard form. 390 468 */ 391 faim_internal int aim_ extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)469 faim_internal int aim_info_extract(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo) 392 470 { 393 471 int curtlv, tlvcnt; … … 478 556 * Type = 0x0004: Idle time. 479 557 * 480 * Number of seconds since the user actively used the558 * Number of minutes since the user actively used the 481 559 * service. 482 560 * … … 530 608 * apparently a port number, and some Other Stuff. 531 609 * 610 * Format is: 611 * 4 bytes - Our IP address, 0xc0 a8 01 2b for 192.168.1.43 612 * 613 * 532 614 */ 533 615 aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25); … … 570 652 outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN; 571 653 654 } else if (type == 0x0019) { 655 /* faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV type 0x0019: from %s\n", outinfo->sn); */ 656 657 } else if (type == 0x001b) { 658 /* faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV type 0x001b: from %s\n", outinfo->sn); */ 659 572 660 } else if (type == 0x001d) { 573 661 /* 574 * Type 29: Unknown. 575 * 576 * Currently very rare. Always 18 bytes of mostly zero. 577 */ 662 * Type = 0x001d 663 * 664 * Buddy icon information and available messages. 665 * 666 * This almost seems like the AIM protocol guys gave 667 * the iChat guys a Type, and the iChat guys tried to 668 * cram as much cool shit into it as possible. Then 669 * the Windows AIM guys were like, "hey, that's 670 * pretty neat, let's copy those prawns." 671 * 672 * In that spirit, this can contain a custom message, 673 * kind of like an away message, but you're not away 674 * (it's called an "available" message). Or it can 675 * contain information about the buddy icon the user 676 * has stored on the server. 677 */ 678 int type2, number, length2; 679 680 while (aim_bstream_curpos(bs) < endpos) { 681 type2 = aimbs_get16(bs); 682 number = aimbs_get8(bs); 683 length2 = aimbs_get8(bs); 684 685 switch (type2) { 686 case 0x0000: { /* This is an official buddy icon? */ 687 /* This is always 5 bytes of "0x02 01 d2 04 72"? */ 688 aim_bstream_advance(bs, length2); 689 } break; 690 691 case 0x0001: { /* A buddy icon checksum */ 692 if ((length2 > 0) && (number == 0x01)) { 693 free(outinfo->iconcsum); 694 outinfo->iconcsum = aimbs_getraw(bs, length2); 695 outinfo->iconcsumlen = length2; 696 } else 697 aim_bstream_advance(bs, length2); 698 } break; 699 700 case 0x0002: { /* An available message */ 701 if (length2 > 4) { 702 free(outinfo->availmsg); 703 outinfo->availmsg_len = aimbs_get16(bs); 704 outinfo->availmsg = aimbs_getstr(bs, outinfo->availmsg_len); 705 if (aimbs_get16(bs) == 0x0001) { /* We have an encoding */ 706 aimbs_get16(bs); 707 outinfo->availmsg_encoding = aimbs_getstr(bs, aimbs_get16(bs)); 708 } else { 709 /* No explicit encoding, client should use UTF-8 */ 710 outinfo->availmsg_encoding = NULL; 711 } 712 } else 713 aim_bstream_advance(bs, length2); 714 } break; 715 716 default: { 717 aim_bstream_advance(bs, length2); 718 } break; 719 } 720 } 578 721 579 722 } else if (type == 0x001e) { … … 607 750 608 751 /* 609 * Inverse of aim_ extractuserinfo()752 * Inverse of aim_info_extract() 610 753 */ 611 754 faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info) … … 713 856 aim_userinfo_t userinfo; 714 857 char *text_encoding = NULL, *text = NULL; 858 int textlen = 0; 715 859 aim_rxcallback_t userfunc; 716 860 aim_tlvlist_t *tlvlist; 861 aim_tlv_t *text_tlv = NULL; 717 862 aim_snac_t *origsnac = NULL; 718 863 struct aim_priv_inforeq *inforeq; … … 735 880 } 736 881 737 aim_ extractuserinfo(sess, bs, &userinfo);882 aim_info_extract(sess, bs, &userinfo); 738 883 739 884 tlvlist = aim_readtlvchain(bs); … … 748 893 if (inforeq->infotype == AIM_GETINFO_GENERALINFO) { 749 894 text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); 750 text = aim_gettlv_str(tlvlist, 0x0002, 1);895 text_tlv = aim_gettlv(tlvlist, 0x0002, 1); 751 896 } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) { 752 897 text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); 753 text = aim_gettlv_str(tlvlist, 0x0004, 1);898 text_tlv = aim_gettlv(tlvlist, 0x0004, 1); 754 899 } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) { 755 900 aim_tlv_t *ct; … … 765 910 } 766 911 912 if (text_tlv) { 913 text = text_tlv->value; 914 textlen = text_tlv->length; 915 } 916 767 917 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 768 ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text); 769 918 ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, textlen); 919 920 aim_info_free(&userinfo); 770 921 free(text_encoding); 771 free(text);772 773 922 aim_freetlvchain(&tlvlist); 774 775 923 if (origsnac) 776 924 free(origsnac->data); … … 887 1035 mod->family = 0x0002; 888 1036 mod->version = 0x0001; 889 mod->toolid = 0x01 01;890 mod->toolversion = 0x0 47b;1037 mod->toolid = 0x0110; 1038 mod->toolversion = 0x0629; 891 1039 mod->flags = 0; 892 1040 strncpy(mod->name, "locate", sizeof(mod->name)); -
libfaim/invite.c
r862371b re374dee 26 26 mod->version = 0x0001; 27 27 mod->toolid = 0x0110; 28 mod->toolversion = 0x0 47b;28 mod->toolversion = 0x0629; 29 29 mod->flags = 0; 30 30 strncpy(mod->name, "invite", sizeof(mod->name)); -
libfaim/meta.c
r862371b re374dee 35 35 } 36 36 37 #if 0 37 38 faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...) 38 39 { … … 55 56 } 56 57 58 #endif -
libfaim/msgcookie.c
r862371b re374dee 132 132 133 133 #if 0 /* debugging feature */ 134 faim_internal int aim_dumpcookie(aim_ msgcookie_t *cookie)134 faim_internal int aim_dumpcookie(aim_session_t *sess, aim_msgcookie_t *cookie) 135 135 { 136 136 … … 138 138 return -EINVAL; 139 139 140 printf("\tCookie at %p: %d/%s with %p, next %p\n", 141 cookie, cookie->type, cookie->cookie, 142 cookie->data, cookie->next); 140 faimdprintf(sess, 0, "\tCookie at %p: %d/%s with %p, next %p\n", cookie, 141 cookie->type, cookie->cookie, cookie->data, cookie->next); 143 142 144 143 return 0; … … 186 185 case AIM_CAPS_BUDDYICON: return AIM_COOKIETYPE_OFTICON; 187 186 case AIM_CAPS_VOICE: return AIM_COOKIETYPE_OFTVOICE; 188 case AIM_CAPS_ IMIMAGE: return AIM_COOKIETYPE_OFTIMAGE;187 case AIM_CAPS_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE; 189 188 case AIM_CAPS_CHAT: return AIM_COOKIETYPE_CHAT; 190 189 case AIM_CAPS_GETFILE: return AIM_COOKIETYPE_OFTGET; -
libfaim/newsearch.c
r862371b re374dee 160 160 static int parseresults(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 161 161 { 162 #if 0 162 163 aim_rxcallback_t userfunc; 163 164 fu16_t tmp, numresults; … … 217 218 free(del); 218 219 } 219 220 #endif 220 221 return 0; 221 222 } -
libfaim/rxhandlers.c
r862371b re374dee 15 15 fu16_t type; 16 16 aim_rxcallback_t handler; 17 u_short flags;17 fu16_t flags; 18 18 struct aim_rxcblist_s *next; 19 19 }; … … 108 108 snac.flags = aimbs_get16(&rx->data); 109 109 snac.id = aimbs_get32(&rx->data); 110 111 /* SNAC flags are apparently uniform across all SNACs, so we handle them here */ 112 if (snac.flags & 0x0001) { 113 /* 114 * This means the SNAC will be followed by another SNAC with 115 * related information. We don't need to do anything about 116 * this here. 117 */ 118 } 119 if (snac.flags & 0x8000) { 120 /* 121 * This packet contains the version of the family that this SNAC is 122 * in. You get this when your SSI module is version 2 or higher. 123 * For now we have no need for this, but you could always save 124 * it as a part of aim_modnsac_t, or something. The format is... 125 * 2 byte length of total mini-header (which is 6 bytes), then TLV 126 * of type 0x0001, length 0x0002, value is the 2 byte version 127 * number 128 */ 129 aim_bstream_advance(&rx->data, aimbs_get16(&rx->data)); 130 } 110 131 111 132 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { … … 371 392 } 372 393 373 /*374 * Some SNACs we do not allow to be hooked, for good reason.375 */376 static int checkdisallowed(fu16_t group, fu16_t type)377 {378 static const struct {379 fu16_t group;380 fu16_t type;381 } dontuse[] = {382 {0x0001, 0x0002},383 {0x0001, 0x0003},384 {0x0001, 0x0006},385 {0x0001, 0x0007},386 {0x0001, 0x0008},387 {0x0001, 0x0017},388 {0x0001, 0x0018},389 {0x0000, 0x0000}390 };391 int i;392 393 for (i = 0; dontuse[i].group != 0x0000; i++) {394 if ((dontuse[i].group == group) && (dontuse[i].type == type))395 return 1;396 }397 398 return 0;399 }400 401 394 faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags) 402 395 { … … 407 400 408 401 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); 409 410 if (checkdisallowed(family, type)) {411 faimdprintf(sess, 0, "aim_conn_addhandler: client tried to hook %x/%x -- BUG!!!\n", family, type);412 return -1;413 }414 402 415 403 if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s)))) … … 529 517 continue; 530 518 531 /* 532 * This is a debugging/sanity check only and probably 533 * could/should be removed for stable code. 534 */ 535 if (((cur->hdrtype == AIM_FRAMETYPE_OFT) && 536 (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 537 ((cur->hdrtype == AIM_FRAMETYPE_FLAP) && 538 (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { 539 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type); 540 cur->handled = 1; 541 continue; 542 } 543 544 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { 545 if (cur->hdrtype != AIM_FRAMETYPE_OFT) { 546 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n"); 547 cur->handled = 1; /* get rid of it */ 548 } else { 519 if (cur->hdrtype == AIM_FRAMETYPE_FLAP) { 520 if (cur->hdr.flap.type == 0x01) { 521 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */ 522 continue; 523 524 } else if (cur->hdr.flap.type == 0x02) { 525 if ((cur->handled = consumesnac(sess, cur))) 526 continue; 527 528 } else if (cur->hdr.flap.type == 0x04) { 529 cur->handled = negchan_middle(sess, cur); 530 continue; 531 532 } else if (cur->hdr.flap.type == 0x05) { 533 534 } 535 536 } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) { 537 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { 549 538 aim_rxdispatch_rendezvous(sess, cur); 550 539 cur->handled = 1; 540 continue; 541 542 } else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) { 543 /* not possible */ 544 faimdprintf(sess, 0, "rxdispatch called on LISTENER connection!\n"); 545 cur->handled = 1; 546 continue; 551 547 } 552 continue;553 548 } 554 549 555 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {556 /* not possible */557 faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");558 cur->handled = 1;559 continue;560 }561 562 if (cur->hdr.flap.type == 0x01) {563 564 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */565 566 continue;567 568 } else if (cur->hdr.flap.type == 0x02) {569 570 if ((cur->handled = consumesnac(sess, cur)))571 continue;572 573 } else if (cur->hdr.flap.type == 0x04) {574 575 cur->handled = negchan_middle(sess, cur);576 continue;577 578 } else if (cur->hdr.flap.type == 0x05)579 ;580 581 550 if (!cur->handled) { 582 551 consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */ -
libfaim/rxqueue.c
r862371b re374dee 83 83 * Read a FLAP header from conn into fr, and return the number of bytes in the payload. 84 84 */ 85 static faim_shortfuncint aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)85 static int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) 86 86 { 87 87 fu8_t flaphdr_raw[6]; … … 165 165 166 166 if (!sess || !conn) 167 return - 1;167 return -EINVAL; 168 168 169 169 if (conn->fd == -1) … … 177 177 178 178 if (!(newrx = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1))) 179 return - 1;179 return -ENOMEM; 180 180 181 181 /* … … 183 183 * function will break on them. 184 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); 185 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { 186 int ret = aim_get_command_rendezvous(sess, conn, newrx); 187 188 if (ret < 0) { 189 free(newrx); 190 return -1; 191 } 192 193 payloadlen = ret; 194 } else if (conn->type == AIM_CONN_TYPE_LISTENER) { 195 faimdprintf(sess, 0, "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd); 189 196 free(newrx); 190 197 return -1; -
libfaim/search.c
r862371b re374dee 41 41 * 42 42 */ 43 faim_export int aim_ usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address)43 faim_export int aim_search_address(aim_session_t *sess, aim_conn_t *conn, const char *address) 44 44 { 45 45 aim_frame_t *fr; … … 123 123 mod->version = 0x0001; 124 124 mod->toolid = 0x0110; 125 mod->toolversion = 0x0 47b;125 mod->toolversion = 0x0629; 126 126 mod->flags = 0; 127 127 strncpy(mod->name, "search", sizeof(mod->name)); -
libfaim/service.c
r862371b re374dee 120 120 redir.group = aim_gettlv16(tlvlist, 0x000d, 1); 121 121 redir.ip = aim_gettlv_str(tlvlist, 0x0005, 1); 122 redir.cookielen = aim_gettlv(tlvlist, 0x0006, 1)->length; 122 123 redir.cookie = aim_gettlv_str(tlvlist, 0x0006, 1); 123 124 … … 392 393 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 393 394 { 395 int ret = 0; 394 396 aim_rxcallback_t userfunc; 395 397 fu16_t code, rateclass; … … 408 410 409 411 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 410 ret urnuserfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);411 412 return 0;412 ret = userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); 413 414 return ret; 413 415 } 414 416 … … 429 431 static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 430 432 { 433 int ret = 0; 431 434 aim_rxcallback_t userfunc; 432 435 433 436 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 434 ret urnuserfunc(sess, rx);435 436 return 0;437 ret = userfunc(sess, rx); 438 439 return ret; 437 440 } 438 441 … … 477 480 static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 478 481 { 482 int ret = 0; 479 483 aim_rxcallback_t userfunc; 480 484 481 485 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 482 ret urnuserfunc(sess, rx);483 484 return 0;486 ret = userfunc(sess, rx); 487 488 return ret; 485 489 } 486 490 … … 494 498 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 495 499 { 500 int ret = 0; 496 501 aim_rxcallback_t userfunc; 497 502 aim_userinfo_t userinfo; 498 503 499 aim_ extractuserinfo(sess, bs, &userinfo);504 aim_info_extract(sess, bs, &userinfo); 500 505 501 506 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 502 return userfunc(sess, rx, &userinfo); 503 504 return 0; 507 ret = userfunc(sess, rx, &userinfo); 508 509 aim_info_free(&userinfo); 510 511 return ret; 505 512 } 506 513 … … 508 515 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 509 516 { 517 int ret = 0; 510 518 aim_rxcallback_t userfunc; 511 519 fu16_t newevil; … … 517 525 518 526 if (aim_bstream_empty(bs)) 519 aim_ extractuserinfo(sess, bs, &userinfo);527 aim_info_extract(sess, bs, &userinfo); 520 528 521 529 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 522 return userfunc(sess, rx, newevil, &userinfo); 523 524 return 0; 530 ret = userfunc(sess, rx, newevil, &userinfo); 531 532 aim_info_free(&userinfo); 533 534 return ret; 525 535 } 526 536 … … 725 735 726 736 /* 727 * Subtype 0x001e - Set Extended Status 728 * 729 * Currently only works if using ICQ. 730 * 731 */ 732 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status) 733 { 737 * Subtype 0x001e - Extended Status 738 * 739 * Sets your ICQ status (available, away, do not disturb, etc.) 740 * 741 * These are the same TLVs seen in user info. You can 742 * also set 0x0008 and 0x000c. 743 */ 744 faim_export int aim_setextstatus(aim_session_t *sess, fu32_t status) 745 { 746 aim_conn_t *conn; 734 747 aim_frame_t *fr; 735 748 aim_snacid_t snacid; … … 737 750 fu32_t data; 738 751 739 data = 0x00030000 | status; /* yay for error checking ;^) */ 752 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 753 return -EINVAL; 754 755 data = AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_WEBAWARE | status; /* yay for error checking ;^) */ 740 756 741 757 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8))) … … 749 765 aim_freetlvchain(&tl); 750 766 767 aim_tx_enqueue(sess, fr); 768 769 return 0; 770 } 771 772 /* 773 * Subtype 0x001e - Extended Status. 774 * 775 * Sets your "available" message. This is currently only supported by iChat 776 * and Gaim. 777 * 778 * These are the same TLVs seen in user info. You can 779 * also set 0x0008 and 0x000c. 780 */ 781 faim_export int aim_srv_setavailmsg(aim_session_t *sess, char *msg) 782 { 783 aim_conn_t *conn; 784 aim_frame_t *fr; 785 aim_snacid_t snacid; 786 787 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0001))) 788 return -EINVAL; 789 790 if (msg) { 791 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + strlen(msg) + 8))) 792 return -ENOMEM; 793 794 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); 795 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); 796 797 aimbs_put16(&fr->data, 0x001d); 798 aimbs_put16(&fr->data, strlen(msg)+8); 799 aimbs_put16(&fr->data, 0x0002); 800 aimbs_put8(&fr->data, 0x04); 801 aimbs_put8(&fr->data, strlen(msg)+4); 802 aimbs_put16(&fr->data, strlen(msg)); 803 aimbs_putraw(&fr->data, msg, strlen(msg)); 804 aimbs_put16(&fr->data, 0x0000); 805 } else { 806 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + 8))) 807 return -ENOMEM; 808 809 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); 810 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); 811 812 aimbs_put16(&fr->data, 0x001d); 813 aimbs_put16(&fr->data, 0x0008); 814 aimbs_put16(&fr->data, 0x0002); 815 aimbs_put16(&fr->data, 0x0404); 816 aimbs_put16(&fr->data, 0x0000); 817 aimbs_put16(&fr->data, 0x0000); 818 } 819 751 820 aim_tx_enqueue(sess, fr); 752 821 … … 794 863 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 795 864 { 865 int ret = 0; 796 866 aim_rxcallback_t userfunc; 797 867 fu32_t offset, len; … … 808 878 809 879 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 810 ret urnuserfunc(sess, rx, offset, len, modname);880 ret = userfunc(sess, rx, offset, len, modname); 811 881 812 882 free(modname); 813 883 aim_freetlvchain(&list); 814 884 815 return 0;885 return ret; 816 886 } 817 887 … … 924 994 925 995 return 0; 996 } 997 998 /* 999 * Subtype 0x0021 - Receive our extended status 1000 * 1001 * This is used for iChat's "available" messages, and maybe ICQ extended 1002 * status messages? It's also used to tell the client whether or not it 1003 * needs to upload an SSI buddy icon... who engineers this stuff, anyway? 1004 */ 1005 static int aim_parse_extstatus(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1006 { 1007 int ret = 0; 1008 aim_rxcallback_t userfunc; 1009 fu16_t type; 1010 fu8_t flags, length; 1011 1012 type = aimbs_get16(bs); 1013 flags = aimbs_get8(bs); 1014 length = aimbs_get8(bs); 1015 1016 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { 1017 switch (type) { 1018 case 0x0000: 1019 case 0x0001: { /* buddy icon checksum */ 1020 /* not sure what the difference between 1 and 0 is */ 1021 fu8_t *md5 = aimbs_getraw(bs, length); 1022 ret = userfunc(sess, rx, type, flags, length, md5); 1023 free(md5); 1024 } break; 1025 case 0x0002: { /* available message */ 1026 /* there is a second length that is just for the message */ 1027 char *msg = aimbs_getstr(bs, aimbs_get16(bs)); 1028 ret = userfunc(sess, rx, msg); 1029 free(msg); 1030 } break; 1031 } 1032 } 1033 1034 return ret; 926 1035 } 927 1036 … … 953 1062 else if (snac->subtype == 0x001f) 954 1063 return memrequest(sess, mod, rx, snac, bs); 1064 else if (snac->subtype == 0x0021) 1065 return aim_parse_extstatus(sess, mod, rx, snac, bs); 955 1066 956 1067 return 0; … … 963 1074 mod->version = 0x0003; 964 1075 mod->toolid = 0x0110; 965 mod->toolversion = 0x0 47b;1076 mod->toolversion = 0x0629; 966 1077 mod->flags = 0; 967 1078 strncpy(mod->name, "general", sizeof(mod->name)); -
libfaim/snac.c
r862371b re374dee 91 91 *prev = cur->next; 92 92 if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) { 93 struct aim_snac_destructor *asd = cur->data; 94 cur->data = asd->data; 95 free(asd); 93 free(cur->data); 94 cur->data = NULL; 96 95 } 97 96 return cur; … … 103 102 } 104 103 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 138 139 104 /* 140 105 * This is for cleaning up old SNACs that either don't get replies or … … 144 109 * 145 110 */ 146 faim_ internalvoid aim_cleansnacs(aim_session_t *sess, int maxage)111 faim_export void aim_cleansnacs(aim_session_t *sess, int maxage) 147 112 { 148 113 int i; … … 162 127 *prev = cur->next; 163 128 164 aim_cleansnac(sess, cur); 129 free(cur->data); 130 free(cur); 165 131 } else 166 132 prev = &cur->next; -
libfaim/ssi.c
r862371b re374dee 1 1 /* 2 * Server-Side/Stored Information. 3 * 4 * Relatively new facility that allows storing of certain types of information, 5 * such as a users buddy list, permit/deny list, and permit/deny preferences, 6 * to be stored on the server, so that they can be accessed from any client. 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. 2 * Family 0x0013 - Server-Side/Stored Information. 3 * 4 * Relatively new facility that allows certain types of information, such as 5 * a user's buddy list, permit/deny list, and permit/deny preferences, to be 6 * stored on the server, so that they can be accessed from any client. 7 * 8 * We keep 2 copies of SSI data: 9 * 1) An exact copy of what is stored on the AIM servers. 10 * 2) A local copy that we make changes to, and then send diffs 11 * between this and the exact copy to keep them in sync. 12 * 13 * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list 14 * that is given to them (i.e. they don't send SNACs). 11 15 * 12 16 * The SNAC sending and receiving functions are lower down in the file, and … … 18 22 * You don't know the half of it. 19 23 * 20 * XXX - Test for memory leaks 21 * XXX - Better parsing of rights, and use the rights info to limit adds 24 * XXX - Preserve unknown data in TLV lists 22 25 * 23 26 */ … … 27 30 28 31 /** 32 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. 33 * 34 * @param list A pointer to a pointer to the current list of items. 35 * @param name A null terminated string containing the group name, or NULL 36 * if you want to modify the master group. 37 * @return Return a pointer to the modified item. 38 */ 39 static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name) 40 { 41 int newlen; 42 struct aim_ssi_item *cur, *group; 43 44 if (!list) 45 return NULL; 46 47 /* Find the group */ 48 if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) 49 return NULL; 50 51 /* Free the old data */ 52 aim_freetlvchain(&group->data); 53 group->data = NULL; 54 55 /* Find the length for the new additional data */ 56 newlen = 0; 57 if (group->gid == 0x0000) { 58 for (cur=list; cur; cur=cur->next) 59 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) 60 newlen += 2; 61 } else { 62 for (cur=list; cur; cur=cur->next) 63 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 64 newlen += 2; 65 } 66 67 /* Build the new TLV list */ 68 if (newlen > 0) { 69 fu8_t *newdata; 70 71 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) 72 return NULL; 73 newlen = 0; 74 if (group->gid == 0x0000) { 75 for (cur=list; cur; cur=cur->next) 76 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) 77 newlen += aimutil_put16(newdata+newlen, cur->gid); 78 } else { 79 for (cur=list; cur; cur=cur->next) 80 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 81 newlen += aimutil_put16(newdata+newlen, cur->bid); 82 } 83 aim_addtlvtochain_raw(&group->data, 0x00c8, newlen, newdata); 84 85 free(newdata); 86 } 87 88 return group; 89 } 90 91 /** 29 92 * Locally add a new item to the given item list. 30 93 * 31 94 * @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 no33 * parent group (ie. the group ID# should be 0).34 95 * @param name A null terminated string of the name of the new item, or NULL if the 35 96 * 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) 97 * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something. 98 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something. 99 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc. 100 * @param data The additional data for the new item. 101 * @return A pointer to the newly created item. 102 */ 103 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, fu16_t gid, fu16_t bid, fu16_t type, aim_tlvlist_t *data) 40 104 { 41 105 int i; 42 struct aim_ssi_item *cur, *newitem; 43 44 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 106 struct aim_ssi_item *cur, *new; 107 108 if (!list) 109 return NULL; 110 111 if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 45 112 return NULL; 46 113 47 114 /* Set the name */ 48 115 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); 116 new->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 117 strcpy(new->name, name); 54 118 } else 55 new item->name = NULL;56 57 /* Set the group ID# and thebuddy ID# */58 new item->gid = 0x0000;59 new item->bid = 0x0000;119 new->name = NULL; 120 121 /* Set the group ID# and buddy ID# */ 122 new->gid = gid; 123 new->bid = bid; 60 124 if (type == AIM_SSI_TYPE_GROUP) { 61 if ( name)125 if ((new->gid == 0xFFFF) && name) { 62 126 do { 63 new item->gid += 0x0001;127 new->gid += 0x0001; 64 128 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 65 if ((cur-> gid == newitem->gid) && (cur->gid == newitem->gid))129 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) 66 130 i=1; 67 131 } while (i); 132 } 68 133 } 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. 134 if (new->bid == 0xFFFF) { 135 do { 136 new->bid += 0x0001; 137 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 138 if ((cur->bid == new->bid) && (cur->gid == new->gid)) 139 i=1; 140 } while (i); 141 } 142 } 143 144 /* Set the type */ 145 new->type = type; 146 147 /* Set the TLV list */ 148 new->data = aim_tlvlist_copy(data); 149 150 /* Add the item to the list in the correct numerical position. Fancy, eh? */ 151 if (*list) { 152 if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) { 153 new->next = *list; 154 *list = new; 155 } else { 156 struct aim_ssi_item *prev; 157 for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next); 158 new->next = prev->next; 159 prev->next = new; 160 } 161 } else { 162 new->next = *list; 163 *list = new; 164 } 165 166 return new; 167 } 168 169 /** 170 * Locally delete an item from the given item list. 90 171 * 91 172 * @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.173 * @param del A pointer to the item you want to remove from the list. 93 174 * @return Return 0 if no errors, otherwise return the error number. 94 175 */ 95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) 96 { 97 int newlen; 176 static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del) 177 { 178 if (!list || !(*list) || !del) 179 return -EINVAL; 180 181 /* Remove the item from the list */ 182 if (*list == del) { 183 *list = (*list)->next; 184 } else { 185 struct aim_ssi_item *cur; 186 for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); 187 if (cur->next) 188 cur->next = cur->next->next; 189 } 190 191 /* Free the deleted item */ 192 free(del->name); 193 aim_freetlvchain(&del->data); 194 free(del); 195 196 return 0; 197 } 198 199 /** 200 * Compare two items to see if they have the same data. 201 * 202 * @param cur1 A pointer to a pointer to the first item. 203 * @param cur2 A pointer to a pointer to the second item. 204 * @return Return 0 if no differences, or a number if there are differences. 205 */ 206 static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2) 207 { 208 if (!cur1 || !cur2) 209 return 1; 210 211 if (cur1->data && !cur2->data) 212 return 2; 213 214 if (!cur1->data && cur2->data) 215 return 3; 216 217 if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data))) 218 return 4; 219 220 if (cur1->name && !cur2->name) 221 return 5; 222 223 if (!cur1->name && cur2->name) 224 return 6; 225 226 if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name)) 227 return 7; 228 229 if (cur1->gid != cur2->gid) 230 return 8; 231 232 if (cur1->bid != cur2->bid) 233 return 9; 234 235 if (cur1->type != cur2->type) 236 return 10; 237 238 return 0; 239 } 240 241 faim_export int aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item) 242 { 98 243 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 244 for (cur=list; cur; cur=cur->next) 245 if (cur == item) 246 return 1; 165 247 return 0; 166 248 } … … 208 290 } 209 291 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)))292 } else if (gn) { /* For finding groups */ 293 for (cur=list; cur; cur=cur->next) { 294 if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) { 213 295 return cur; 296 } 297 } 298 299 } else if (sn) { /* For finding permits, denies, and ignores */ 300 for (cur=list; cur; cur=cur->next) { 301 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) { 302 return cur; 303 } 304 } 214 305 215 306 /* For stuff without names--permit deny setting, visibility mask, etc. */ 216 307 } else for (cur=list; cur; cur=cur->next) { 217 if ( cur->type == type)308 if ((cur->type == type) && (!cur->name)) 218 309 return cur; 219 310 } 220 311 312 return NULL; 313 } 314 315 /** 316 * Check if the given buddy exists in any group in the buddy list. 317 * 318 * @param list A pointer to the current list of items. 319 * @param sn The group name of the desired item. 320 * @return Return a pointer to the name of the item if found, else return NULL; 321 */ 322 faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn) 323 { 324 struct aim_ssi_item *cur; 325 if (!list || !sn) 326 return NULL; 327 for (cur=list; cur; cur=cur->next) 328 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn))) 329 return cur; 221 330 return NULL; 222 331 } … … 227 336 * @param list A pointer to the current list of items. 228 337 * @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)338 * @return Return a pointer to the name of the item if found, else return NULL; 339 */ 340 faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn) 232 341 { 233 342 struct aim_ssi_item *cur, *curg; 234 343 if (!list || !sn) 235 344 return NULL; 236 if (!(cur = aim_ssi_itemlist_ finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY)))345 if (!(cur = aim_ssi_itemlist_exists(list, sn))) 237 346 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; 347 if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000))) 348 return NULL; 349 return curg->name; 242 350 } 243 351 … … 285 393 286 394 /** 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. 395 * Locally find the alias of the given buddy. 396 * 397 * @param list A pointer to the current list of items. 398 * @param gn The group of the buddy. 399 * @param sn The name of the buddy. 400 * @return A pointer to a NULL terminated string that is the buddies 401 * alias, or NULL if the buddy has no alias. You should free 402 * this returned value! 403 */ 404 faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn) 405 { 406 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); 407 if (cur) { 408 aim_tlvlist_t *tlvlist = cur->data; 409 if (tlvlist) { 410 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x0131, 1); 411 if (tlv && tlv->length) { 412 char *alias = (char *)malloc((tlv->length+1)*sizeof(char)); 413 strncpy(alias, tlv->value, tlv->length); 414 alias[tlv->length] = 0; 415 return alias; 416 } 417 } 418 } 419 return NULL; 420 } 421 422 /** 423 * Locally find if you are waiting for authorization for a buddy. 424 * 425 * @param list A pointer to the current list of items. 426 * @param gn The group of the buddy. 427 * @param sn The name of the buddy. 428 * @return A pointer to a NULL terminated string that is the buddies 429 * alias, or NULL if the buddy has no alias. You should free 430 * this returned value! 431 */ 432 faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn) 433 { 434 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); 435 if (cur) { 436 aim_tlvlist_t *tlvlist = cur->data; 437 if (tlvlist) 438 if (aim_gettlv(tlvlist, 0x0066, 1)) 439 return 1; 440 } 441 return 0; 442 } 443 444 /** 445 * If there are changes, then create temporary items and 446 * call addmoddel. 290 447 * 291 448 * @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 449 * @return Return 0 if no errors, otherwise return the error number. 295 450 */ 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. 451 static int aim_ssi_sync(aim_session_t *sess) 452 { 453 struct aim_ssi_item *cur1, *cur2; 454 struct aim_ssi_tmp *cur, *new; 455 456 if (!sess) 457 return -EINVAL; 458 459 /* If we're waiting for an ack, we shouldn't do anything else */ 460 if (sess->ssi.waiting_for_ack) 461 return 0; 462 463 /* 464 * Compare the 2 lists and create an aim_ssi_tmp for each difference. 465 * We should only send either additions, modifications, or deletions 466 * before waiting for an acknowledgement. So first do deletions, then 467 * additions, then modifications. Also, both the official and the local 468 * list should be in ascending numerical order for the group ID#s and the 469 * buddy ID#s, which makes things more efficient. I think. 470 */ 471 472 /* Additions */ 473 if (!sess->ssi.pending) { 474 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { 475 if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) { 476 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 477 new->action = AIM_CB_SSI_ADD; 478 new->ack = 0xffff; 479 new->name = NULL; 480 new->item = cur1; 481 new->next = NULL; 482 if (sess->ssi.pending) { 483 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 484 cur->next = new; 485 } else 486 sess->ssi.pending = new; 487 } 488 } 489 } 490 491 /* Deletions */ 492 if (!sess->ssi.pending) { 493 for (cur1=sess->ssi.official; cur1; cur1=cur1->next) { 494 if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) { 495 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 496 new->action = AIM_CB_SSI_DEL; 497 new->ack = 0xffff; 498 new->name = NULL; 499 new->item = cur1; 500 new->next = NULL; 501 if (sess->ssi.pending) { 502 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 503 cur->next = new; 504 } else 505 sess->ssi.pending = new; 506 } 507 } 508 } 509 510 /* Modifications */ 511 if (!sess->ssi.pending) { 512 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { 513 cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid); 514 if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { 515 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 516 new->action = AIM_CB_SSI_MOD; 517 new->ack = 0xffff; 518 new->name = NULL; 519 new->item = cur1; 520 new->next = NULL; 521 if (sess->ssi.pending) { 522 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 523 cur->next = new; 524 } else 525 sess->ssi.pending = new; 526 } 527 } 528 } 529 530 /* We're out of stuff to do, so tell the AIM servers we're done and exit */ 531 if (!sess->ssi.pending) { 532 aim_ssi_modend(sess); 533 return 0; 534 } 535 536 /* Make sure we don't send anything else between now 537 * and when we receive the ack for the following operation */ 538 sess->ssi.waiting_for_ack = 1; 539 540 /* Now go mail off our data and wait 4 to 6 weeks */ 541 aim_ssi_addmoddel(sess); 542 543 return 0; 544 } 545 546 /** 547 * Free all SSI data. 548 * 549 * This doesn't remove it from the server, that's different. 320 550 * 321 551 * @param sess The oscar session. 322 * @param conn The bos connection for this session.323 552 * @return Return 0 if no errors, otherwise return the error number. 324 553 */ 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. 554 static int aim_ssi_freelist(aim_session_t *sess) 555 { 556 struct aim_ssi_item *cur, *del; 557 struct aim_ssi_tmp *curtmp, *deltmp; 558 559 cur = sess->ssi.official; 560 while (cur) { 561 del = cur; 562 cur = cur->next; 563 free(del->name); 564 aim_freetlvchain(&del->data); 565 free(del); 566 } 567 568 cur = sess->ssi.local; 569 while (cur) { 570 del = cur; 571 cur = cur->next; 572 free(del->name); 573 aim_freetlvchain(&del->data); 574 free(del); 575 } 576 577 curtmp = sess->ssi.pending; 578 while (curtmp) { 579 deltmp = curtmp; 580 curtmp = curtmp->next; 581 free(deltmp); 582 } 583 584 sess->ssi.numitems = 0; 585 sess->ssi.official = NULL; 586 sess->ssi.local = NULL; 587 sess->ssi.pending = NULL; 588 sess->ssi.timestamp = (time_t)0; 589 590 return 0; 591 } 592 593 /** 594 * Delete all SSI data. 349 595 * 350 596 * @param sess The oscar session. 351 * @param conn The bos connection for this session.352 597 * @return Return 0 if no errors, otherwise return the error number. 353 598 */ 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. 599 faim_export int aim_ssi_deletelist(aim_session_t *sess) 600 { 601 struct aim_ssi_item *cur, *del; 602 603 if (!sess) 604 return -EINVAL; 605 606 /* Free the local list */ 607 cur = sess->ssi.local; 608 while (cur) { 609 del = cur; 610 cur = cur->next; 611 free(del->name); 612 aim_freetlvchain(&del->data); 613 free(del); 614 } 615 sess->ssi.local = NULL; 616 617 /* Sync our local list with the server list */ 618 aim_ssi_sync(sess); 619 620 return 0; 621 } 622 623 /** 624 * This "cleans" the ssi list. It does the following: 625 * 1) Makes sure all buddies, permits, and denies have names. 626 * 2) Makes sure that all buddies are in a group that exist. 627 * 3) Deletes any empty groups 385 628 * 386 629 * @param sess The oscar session. 387 * @param conn The bos connection for this session.388 630 * @return Return 0 if no errors, otherwise return the error number. 389 631 */ 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; 632 faim_export int aim_ssi_cleanlist(aim_session_t *sess) 633 { 634 struct aim_ssi_item *cur, *next; 635 636 if (!sess) 637 return -EINVAL; 638 639 /* Delete any buddies, permits, or denies with empty names. */ 640 /* If there are any buddies directly in the master group, add them to a real group. */ 641 /* DESTROY any buddies that are directly in the master group. */ 642 /* Do the same for buddies that are in a non-existant group. */ 643 /* This will kind of mess up if you hit the item limit, but this function isn't too critical */ 644 cur = sess->ssi.local; 645 while (cur) { 646 next = cur->next; 647 if (!cur->name) { 648 if (cur->type == AIM_SSI_TYPE_BUDDY) 649 aim_ssi_delbuddy(sess, NULL, NULL); 650 else if (cur->type == AIM_SSI_TYPE_PERMIT) 651 aim_ssi_delpermit(sess, NULL); 652 else if (cur->type == AIM_SSI_TYPE_DENY) 653 aim_ssi_deldeny(sess, NULL); 654 } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) { 655 aim_ssi_addbuddy(sess, cur->name, "orphans", NULL, NULL, NULL, 0); 656 aim_ssi_delbuddy(sess, cur->name, NULL); 408 657 } 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);658 cur = next; 659 } 660 661 /* Check if there are empty groups and delete them */ 662 cur = sess->ssi.local; 663 while (cur) { 664 next = cur->next; 665 if (cur->type == AIM_SSI_TYPE_GROUP) { 666 aim_tlv_t *tlv = aim_gettlv(cur->data, 0x00c8, 1); 667 if (!tlv || !tlv->length) 668 aim_ssi_itemlist_del(&sess->ssi.local, cur); 420 669 } 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); 670 cur = next; 671 } 672 673 /* Check if the master group is empty */ 674 if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data)) 675 aim_ssi_itemlist_del(&sess->ssi.local, cur); 676 677 return 0; 678 } 679 680 /** 681 * Add a buddy to the list. 682 * 683 * @param sess The oscar session. 684 * @param name The name of the item. 685 * @param group The group of the item. 686 * @param alias The alias/nickname of the item, or NULL. 687 * @param comment The buddy comment for the item, or NULL. 688 * @param smsnum The locally assigned SMS number, or NULL. 689 * @return Return 0 if no errors, otherwise return the error number. 690 */ 691 faim_export int aim_ssi_addbuddy(aim_session_t *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth) 692 { 693 struct aim_ssi_item *parent; 694 aim_tlvlist_t *data = NULL; 695 696 if (!sess || !name || !group) 697 return -EINVAL; 698 699 /* Find the parent */ 700 if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { 701 /* Find the parent's parent (the master group) */ 702 if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000))) 703 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) 704 return -ENOMEM; 705 /* Add the parent */ 706 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) 707 return -ENOMEM; 708 709 /* Modify the parent's parent (the master group) */ 710 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); 711 } 712 713 /* Create a TLV list for the new buddy */ 714 if (needauth) 715 aim_addtlvtochain_noval(&data, 0x0066); 716 if (alias) 717 aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias); 718 if (smsnum) 719 aim_addtlvtochain_raw(&data, 0x013a, strlen(smsnum), smsnum); 720 if (comment) 721 aim_addtlvtochain_raw(&data, 0x013c, strlen(comment), comment); 722 723 /* Add that bad boy */ 724 aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data); 725 aim_freetlvchain(&data); 726 727 /* Modify the parent group */ 728 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); 729 730 /* Sync our local list with the server list */ 731 aim_ssi_sync(sess); 732 733 return 0; 734 } 735 736 /** 737 * Add a permit buddy to the list. 738 * 739 * @param sess The oscar session. 740 * @param name The name of the item.. 741 * @return Return 0 if no errors, otherwise return the error number. 742 */ 743 faim_export int aim_ssi_addpermit(aim_session_t *sess, const char *name) 744 { 745 746 if (!sess || !name) 747 return -EINVAL; 748 749 /* Add that bad boy */ 750 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL); 751 752 /* Sync our local list with the server list */ 753 aim_ssi_sync(sess); 754 755 return 0; 756 } 757 758 /** 759 * Add a deny buddy to the list. 760 * 761 * @param sess The oscar session. 762 * @param name The name of the item.. 763 * @return Return 0 if no errors, otherwise return the error number. 764 */ 765 faim_export int aim_ssi_adddeny(aim_session_t *sess, const char *name) 766 { 767 768 if (!sess || !name) 769 return -EINVAL; 770 771 /* Add that bad boy */ 772 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL); 773 774 /* Sync our local list with the server list */ 775 aim_ssi_sync(sess); 776 777 return 0; 778 } 779 780 /** 781 * Deletes a buddy from the list. 782 * 783 * @param sess The oscar session. 784 * @param name The name of the item, or NULL. 785 * @param group The group of the item, or NULL. 786 * @return Return 0 if no errors, otherwise return the error number. 787 */ 788 faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group) 789 { 790 struct aim_ssi_item *del; 791 792 if (!sess) 793 return -EINVAL; 794 795 /* Find the buddy */ 796 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) 797 return -EINVAL; 798 799 /* Remove the item from the list */ 800 aim_ssi_itemlist_del(&sess->ssi.local, del); 801 802 /* Modify the parent group */ 803 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); 804 805 /* Check if we should delete the parent group */ 806 if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) { 807 aim_ssi_itemlist_del(&sess->ssi.local, del); 808 809 /* Modify the parent group */ 810 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); 811 812 /* Check if we should delete the parent's parent (the master group) */ 813 if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) { 814 aim_ssi_itemlist_del(&sess->ssi.local, del); 432 815 } 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. 816 } 817 818 /* Sync our local list with the server list */ 819 aim_ssi_sync(sess); 820 821 return 0; 822 } 823 824 /** 825 * Deletes a permit buddy from the list. 485 826 * 486 827 * @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). 828 * @param name The name of the item, or NULL. 491 829 * @return Return 0 if no errors, otherwise return the error number. 492 830 */ 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. 831 faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name) 832 { 833 struct aim_ssi_item *del; 834 835 if (!sess) 836 return -EINVAL; 837 838 /* Find the item */ 839 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT))) 840 return -EINVAL; 841 842 /* Remove the item from the list */ 843 aim_ssi_itemlist_del(&sess->ssi.local, del); 844 845 /* Sync our local list with the server list */ 846 aim_ssi_sync(sess); 847 848 return 0; 849 } 850 851 /** 852 * Deletes a deny buddy from the list. 546 853 * 547 854 * @param sess The oscar session. 548 * @param conn The bos connection for this session.855 * @param name The name of the item, or NULL. 549 856 * @return Return 0 if no errors, otherwise return the error number. 550 857 */ 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; 858 faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name) 859 { 860 struct aim_ssi_item *del; 861 862 if (!sess) 863 return -EINVAL; 864 865 /* Find the item */ 866 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY))) 867 return -EINVAL; 868 869 /* Remove the item from the list */ 870 aim_ssi_itemlist_del(&sess->ssi.local, del); 871 872 /* Sync our local list with the server list */ 873 aim_ssi_sync(sess); 678 874 679 875 return 0; … … 685 881 * 686 882 * @param sess The oscar session. 687 * @param conn The bos connection for this session.688 883 * @param oldgn The group that the buddy is currently in. 689 884 * @param newgn The group that the buddy should be moved in to. … … 691 886 * @return Return 0 if no errors, otherwise return the error number. 692 887 */ 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?... 888 faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn) 889 { 890 aim_ssi_addbuddy(sess, sn, newgn, aim_ssi_getalias(sess->ssi.local, oldgn, sn), NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn)); 891 aim_ssi_delbuddy(sess, sn, oldgn); 892 return 0; 893 } 894 895 /** 896 * Change the alias stored on the server for a given buddy. 762 897 * 763 898 * @param sess The oscar session. 764 * @param conn The bos connection for this session. 899 * @param gn The group that the buddy is currently in. 900 * @param sn The screen name of the buddy. 901 * @param alias The new alias for the buddy. 902 * @return Return 0 if no errors, otherwise return the error number. 903 */ 904 faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias) 905 { 906 struct aim_ssi_item *tmp; 907 aim_tlvlist_t *data = NULL; 908 909 if (!sess || !gn || !sn) 910 return -EINVAL; 911 912 if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY))) 913 return -EINVAL; 914 915 if (alias && !strlen(alias)) 916 alias = NULL; 917 918 /* Need to add the x0131 TLV to the TLV chain */ 919 if (alias) 920 aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias); 921 922 aim_freetlvchain(&tmp->data); 923 tmp->data = data; 924 925 /* Sync our local list with the server list */ 926 aim_ssi_sync(sess); 927 928 return 0; 929 } 930 931 /** 932 * Rename a group. 933 * 934 * @param sess The oscar session. 765 935 * @param oldgn The old group name. 766 936 * @param newgn The new group name. 767 937 * @return Return 0 if no errors, otherwise return the error number. 768 938 */ 769 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn,const char *oldgn, const char *newgn)939 faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn) 770 940 { 771 941 struct aim_ssi_item *group; 772 942 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 } 943 if (!sess || !oldgn || !newgn) 944 return -EINVAL; 945 946 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) 947 return -EINVAL; 948 949 free(group->name); 950 group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)); 787 951 strcpy(group->name, newgn); 788 952 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. 953 /* Sync our local list with the server list */ 954 aim_ssi_sync(sess); 955 956 return 0; 957 } 958 959 /** 960 * Stores your permit/deny setting on the server, and starts using it. 800 961 * 801 962 * @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 be986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and987 * 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 963 * @param permdeny Your permit/deny setting. Can be one of the following: 1048 964 * 1 - Allow all users … … 1055 971 * @return Return 0 if no errors, otherwise return the error number. 1056 972 */ 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); 973 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask) 974 { 975 struct aim_ssi_item *tmp; 976 aim_tlvlist_t *data = NULL; 977 978 if (!sess) 979 return -EINVAL; 980 981 /* Need to add the x00ca TLV to the TLV chain */ 982 aim_addtlvtochain8(&data, 0x00ca, permdeny); 983 984 /* Need to add the x00cb TLV to the TLV chain */ 985 aim_addtlvtochain32(&data, 0x00cb, vismask); 986 987 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { 988 aim_freetlvchain(&tmp->data); 989 tmp->data = data; 990 } else { 991 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, data); 992 aim_freetlvchain(&data); 993 } 994 995 /* Sync our local list with the server list */ 996 aim_ssi_sync(sess); 997 998 return 0; 999 } 1000 1001 /** 1002 * Set buddy icon information 1003 * 1004 * @param sess The oscar session. 1005 * @param iconcsum The MD5 checksum of the icon you are using. 1006 * @param iconcsumlen Length of the MD5 checksum given above. Should be 0x10 bytes. 1007 * @return Return 0 if no errors, otherwise return the error number. 1008 */ 1009 faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen) 1010 { 1011 struct aim_ssi_item *tmp; 1012 aim_tlvlist_t *data = NULL; 1013 fu8_t *csumdata; 1014 1015 if (!sess || !iconsum || !iconsumlen) 1016 return -EINVAL; 1017 1018 if (!(csumdata = (fu8_t *)malloc((iconsumlen+2)*sizeof(fu8_t)))) 1019 return -ENOMEM; 1020 csumdata[0] = 0x00; 1021 csumdata[1] = 0x10; 1022 memcpy(&csumdata[2], iconsum, iconsumlen); 1023 1024 /* Need to add the x00d5 TLV to the TLV chain */ 1025 aim_addtlvtochain_raw(&data, 0x00d5, (iconsumlen+2) * sizeof(fu8_t), csumdata); 1026 1027 /* This TLV is added to cache the icon. */ 1028 aim_addtlvtochain_noval(&data, 0x0131); 1029 1030 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) { 1031 /* If the new tlvchain and oldtlvchain are the same, then do nothing */ 1032 if (!aim_tlvlist_cmp(tmp->data, data)) { 1033 /* The new tlvlist is the identical to the old one */ 1034 aim_freetlvchain(&data); 1035 free(csumdata); 1036 return 0; 1080 1037 } 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); 1038 aim_freetlvchain(&tmp->data); 1039 tmp->data = data; 1097 1040 } 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 1041 tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, data); 1042 aim_freetlvchain(&data); 1043 } 1044 1045 /* Sync our local list with the server list */ 1046 aim_ssi_sync(sess); 1047 free(csumdata); 1109 1048 return 0; 1110 1049 } … … 1114 1053 * 1115 1054 * @param sess The oscar session. 1116 * @param conn The bos connection for this session.1117 1055 * @param presence I think it's a bitmask, but I only know what one of the bits is: 1118 1056 * 0x00000400 - Allow others to see your idle time 1119 1057 * @return Return 0 if no errors, otherwise return the error number. 1120 1058 */ 1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { 1122 struct aim_ssi_item *cur; 1059 faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence) { 1060 struct aim_ssi_item *tmp; 1061 aim_tlvlist_t *data = NULL; 1062 1063 if (!sess) 1064 return -EINVAL; 1065 1066 /* Need to add the x00c9 TLV to the TLV chain */ 1067 aim_addtlvtochain32(&data, 0x00c9, presence); 1068 1069 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { 1070 aim_freetlvchain(&tmp->data); 1071 tmp->data = data; 1072 } else { 1073 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, data); 1074 aim_freetlvchain(&data); 1075 } 1076 1077 /* Sync our local list with the server list */ 1078 aim_ssi_sync(sess); 1079 1080 return 0; 1081 } 1082 1083 /* 1084 * Subtype 0x0002 - Request SSI Rights. 1085 */ 1086 faim_export int aim_ssi_reqrights(aim_session_t *sess) 1087 { 1088 aim_conn_t *conn; 1089 1090 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1091 return -EINVAL; 1092 1093 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 1094 } 1095 1096 /* 1097 * Subtype 0x0003 - SSI Rights Information. 1098 */ 1099 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1100 { 1101 int ret = 0, i; 1102 aim_rxcallback_t userfunc; 1103 aim_tlvlist_t *tlvlist; 1123 1104 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 1162 /* 1163 * Request SSI Rights. 1164 */ 1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) 1166 { 1167 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 1168 } 1169 1170 /* 1171 * SSI Rights Information. 1172 */ 1173 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1174 { 1175 int ret = 0; 1176 aim_rxcallback_t userfunc; 1105 aim_bstream_t bstream; 1106 fu16_t *maxitems; 1107 1108 /* This SNAC is made up of a bunch of TLVs */ 1109 tlvlist = aim_readtlvchain(bs); 1110 1111 /* TLV 0x0004 contains the maximum number of each item */ 1112 if (!(tlv = aim_gettlv(tlvlist, 0x0004, 1))) { 1113 aim_freetlvchain(&tlvlist); 1114 return 0; 1115 } 1116 1117 aim_bstream_init(&bstream, tlv->value, tlv->length); 1118 1119 if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) { 1120 aim_freetlvchain(&tlvlist); 1121 return 0; 1122 } 1123 1124 for (i=0; i<(tlv->length/2); i++) 1125 maxitems[i] = aimbs_get16(&bstream); 1177 1126 1178 1127 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1179 ret = userfunc(sess, rx); 1128 ret = userfunc(sess, rx, tlv->length/2, maxitems); 1129 1130 aim_freetlvchain(&tlvlist); 1131 free(maxitems); 1180 1132 1181 1133 return ret; … … 1183 1135 1184 1136 /* 1185 * Request SSI Data. 1137 * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and 1138 * revision number. 1139 * 1140 */ 1141 faim_export int aim_ssi_reqdata(aim_session_t *sess) 1142 { 1143 aim_conn_t *conn; 1144 1145 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1146 return -EINVAL; 1147 1148 /* Free any current data, just in case */ 1149 aim_ssi_freelist(sess); 1150 1151 return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQDATA); 1152 } 1153 1154 /* 1155 * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision 1156 * number. 1186 1157 * 1187 1158 * The data will only be sent if it is newer than the posted local … … 1191 1162 * 1192 1163 */ 1193 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev) 1194 { 1164 faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t timestamp, fu16_t numitems) 1165 { 1166 aim_conn_t *conn; 1195 1167 aim_frame_t *fr; 1196 1168 aim_snacid_t snacid; 1197 1169 1198 if (!sess || ! conn)1170 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1199 1171 return -EINVAL; 1200 1172 … … 1202 1174 return -ENOMEM; 1203 1175 1204 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQ LIST, 0x0000, NULL, 0);1205 1206 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQ LIST, 0x0000, snacid);1207 aimbs_put32(&fr->data, localstamp);1208 aimbs_put16(&fr->data, localrev);1176 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, NULL, 0); 1177 1178 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, snacid); 1179 aimbs_put32(&fr->data, timestamp); 1180 aimbs_put16(&fr->data, numitems); 1209 1181 1210 1182 aim_tx_enqueue(sess, fr); 1211 1183 1212 return 0; 1213 } 1214 1215 /* 1216 * SSI Data. 1184 /* Free any current data, just in case */ 1185 aim_ssi_freelist(sess); 1186 1187 return 0; 1188 } 1189 1190 /* 1191 * Subtype 0x0006 - SSI Data. 1217 1192 */ 1218 1193 static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) … … 1220 1195 int ret = 0; 1221 1196 aim_rxcallback_t userfunc; 1222 struct aim_ssi_item *cur = NULL;1223 1197 fu8_t fmtver; /* guess */ 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 */ 1198 fu16_t namelen, gid, bid, type; 1199 char *name; 1200 aim_tlvlist_t *data; 1234 1201 1235 1202 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) ; 1241 1242 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */ 1243 fu16_t namelen, tbslen; 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)); 1255 1203 sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */ 1204 1205 /* Read in the list */ 1206 while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */ 1256 1207 if ((namelen = 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); 1261 1262 if ((tbslen = aimbs_get16(bs))) { 1263 aim_bstream_t tbs; 1264 1265 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen); 1266 cur->data = (void *)aim_readtlvchain(&tbs); 1267 aim_bstream_advance(bs, tbslen); 1268 } 1269 } 1270 1271 timestamp = aimbs_get32(bs); 1272 if (timestamp != 0) 1273 sess->ssi.timestamp = timestamp; 1274 sess->ssi.received_data = 1; 1275 1276 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1277 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items); 1208 name = aimbs_getstr(bs, namelen); 1209 else 1210 name = NULL; 1211 gid = aimbs_get16(bs); 1212 bid = aimbs_get16(bs); 1213 type = aimbs_get16(bs); 1214 data = aim_readtlvchain_len(bs, aimbs_get16(bs)); 1215 aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data); 1216 free(name); 1217 aim_freetlvchain(&data); 1218 } 1219 1220 /* Read in the timestamp */ 1221 sess->ssi.timestamp = aimbs_get32(bs); 1222 1223 if (!(snac->flags & 0x0001)) { 1224 /* Make a copy of the list */ 1225 struct aim_ssi_item *cur; 1226 for (cur=sess->ssi.official; cur; cur=cur->next) 1227 aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data); 1228 1229 sess->ssi.received_data = 1; 1230 1231 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1232 ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp); 1233 } 1278 1234 1279 1235 return ret; … … 1281 1237 1282 1238 /* 1283 * S SI Data Enable Presence.1239 * Subtype 0x0007 - SSI Activate Data. 1284 1240 * 1285 1241 * Should be sent after receiving 13/6 or 13/f to tell the server you … … 1289 1245 * 1290 1246 */ 1291 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn) 1292 { 1247 faim_export int aim_ssi_enable(aim_session_t *sess) 1248 { 1249 aim_conn_t *conn; 1250 1251 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1252 return -EINVAL; 1253 1293 1254 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); 1294 1255 } 1295 1256 1296 1257 /* 1297 * S SI Add/Mod/Del Item(s).1258 * Subtype 0x0008/0x0009/0x000a - SSI Add/Mod/Del Item(s). 1298 1259 * 1299 1260 * Sends the SNAC to add, modify, or delete an item from the server-stored … … 1302 1263 * 1303 1264 */ 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 { 1265 faim_export int aim_ssi_addmoddel(aim_session_t *sess) 1266 { 1267 aim_conn_t *conn; 1306 1268 aim_frame_t *fr; 1307 1269 aim_snacid_t snacid; 1308 int i, snaclen; 1309 1310 if (!sess || !conn || !items || !num) 1311 return -EINVAL; 1312 1270 int snaclen; 1271 struct aim_ssi_tmp *cur; 1272 1273 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sess->ssi.pending || !sess->ssi.pending->item) 1274 return -EINVAL; 1275 1276 /* Calculate total SNAC size */ 1313 1277 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ 1314 for ( i=0; i<num; i++) {1278 for (cur=sess->ssi.pending; cur; cur=cur->next) { 1315 1279 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);1280 if (cur->item->name) 1281 snaclen += strlen(cur->item->name); 1282 if (cur->item->data) 1283 snaclen += aim_sizetlvchain(&cur->item->data); 1320 1284 } 1321 1285 … … 1323 1287 return -ENOMEM; 1324 1288 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) 1289 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0); 1290 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid); 1291 1292 for (cur=sess->ssi.pending; cur; cur=cur->next) { 1293 aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0); 1294 if (cur->item->name) 1295 aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name)); 1296 aimbs_put16(&fr->data, cur->item->gid); 1297 aimbs_put16(&fr->data, cur->item->bid); 1298 aimbs_put16(&fr->data, cur->item->type); 1299 aimbs_put16(&fr->data, cur->item->data ? aim_sizetlvchain(&cur->item->data) : 0); 1300 if (cur->item->data) 1301 aim_writetlvchain(&fr->data, &cur->item->data); 1302 } 1303 1304 aim_tx_enqueue(sess, fr); 1305 1306 return 0; 1307 } 1308 1309 /* 1310 * Subtype 0x0008 - Incoming SSI add. 1311 * 1312 * XXX - It would probably be good for the client to actually do something when it gets this. 1313 */ 1314 static int parseadd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1352 1315 { 1353 1316 int ret = 0; 1354 1317 aim_rxcallback_t userfunc; 1355 1356 sess->ssi.waiting_for_ack = 0; 1357 aim_ssi_dispatch(sess, rx->conn); 1318 char *name; 1319 fu16_t len, gid, bid, type; 1320 aim_tlvlist_t *data; 1321 1322 while (aim_bstream_empty(bs)) { 1323 if ((len = aimbs_get16(bs))) 1324 name = aimbs_getstr(bs, len); 1325 else 1326 name = NULL; 1327 gid = aimbs_get16(bs); 1328 bid = aimbs_get16(bs); 1329 type = aimbs_get16(bs); 1330 if ((len = aimbs_get16(bs))) 1331 data = aim_readtlvchain_len(bs, len); 1332 else 1333 data = NULL; 1334 1335 aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data); 1336 aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data); 1337 free(name); 1338 aim_freetlvchain(&data); 1339 1340 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1341 ret = userfunc(sess, rx); 1342 1343 free(name); 1344 } 1345 1346 return ret; 1347 } 1348 1349 /* 1350 * Subtype 0x0009 - Incoming SSI mod. 1351 * 1352 * XXX - It would probably be good for the client to actually do something when it gets this. 1353 */ 1354 static int parsemod(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1355 { 1356 int ret = 0; 1357 aim_rxcallback_t userfunc; 1358 char *name; 1359 fu16_t len, gid, bid, type; 1360 aim_tlvlist_t *data; 1361 struct aim_ssi_item *item; 1362 1363 while (aim_bstream_empty(bs)) { 1364 if ((len = aimbs_get16(bs))) 1365 name = aimbs_getstr(bs, len); 1366 else 1367 name = NULL; 1368 gid = aimbs_get16(bs); 1369 bid = aimbs_get16(bs); 1370 type = aimbs_get16(bs); 1371 if ((len = aimbs_get16(bs))) 1372 data = aim_readtlvchain_len(bs, len); 1373 else 1374 data = NULL; 1375 1376 /* Replace the 2 local items with the given one */ 1377 if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) { 1378 item->type = type; 1379 free(item->name); 1380 if (name) { 1381 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 1382 strcpy(item->name, name); 1383 } else 1384 item->name = NULL; 1385 aim_freetlvchain(&item->data); 1386 item->data = aim_tlvlist_copy(data); 1387 } 1388 1389 if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) { 1390 item->type = type; 1391 free(item->name); 1392 if (name) { 1393 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 1394 strcpy(item->name, name); 1395 } else 1396 item->name = NULL; 1397 aim_freetlvchain(&item->data); 1398 item->data = aim_tlvlist_copy(data); 1399 } 1400 1401 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1402 ret = userfunc(sess, rx); 1403 1404 free(name); 1405 aim_freetlvchain(&data); 1406 } 1407 1408 return ret; 1409 } 1410 1411 /* 1412 * Subtype 0x000a - Incoming SSI del. 1413 * 1414 * XXX - It would probably be good for the client to actually do something when it gets this. 1415 */ 1416 static int parsedel(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1417 { 1418 int ret = 0; 1419 aim_rxcallback_t userfunc; 1420 fu16_t gid, bid; 1421 struct aim_ssi_item *del; 1422 1423 while (aim_bstream_empty(bs)) { 1424 aim_bstream_advance(bs, aimbs_get16(bs)); 1425 gid = aimbs_get16(bs); 1426 bid = aimbs_get16(bs); 1427 aimbs_get16(bs); 1428 aim_bstream_advance(bs, aimbs_get16(bs)); 1429 1430 if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) 1431 aim_ssi_itemlist_del(&sess->ssi.local, del); 1432 if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) 1433 aim_ssi_itemlist_del(&sess->ssi.official, del); 1434 1435 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1436 ret = userfunc(sess, rx); 1437 } 1438 1439 return ret; 1440 } 1441 1442 /* 1443 * Subtype 0x000e - SSI Add/Mod/Del Ack. 1444 * 1445 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). 1446 * 1447 */ 1448 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1449 { 1450 int ret = 0; 1451 aim_rxcallback_t userfunc; 1452 struct aim_ssi_tmp *cur, *del; 1453 1454 /* Read in the success/failure flags from the ack SNAC */ 1455 cur = sess->ssi.pending; 1456 while (cur && (aim_bstream_empty(bs)>0)) { 1457 cur->ack = aimbs_get16(bs); 1458 cur = cur->next; 1459 } 1460 1461 /* 1462 * If outcome is 0, then add the item to the item list, or replace the other item, 1463 * or remove the old item. If outcome is non-zero, then remove the item from the 1464 * local list, or unmodify it, or add it. 1465 */ 1466 for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) { 1467 if (cur->item) { 1468 if (cur->ack) { 1469 /* Our action was unsuccessful, so change the local list back to how it was */ 1470 if (cur->action == AIM_CB_SSI_ADD) { 1471 /* Remove the item from the local list */ 1472 /* Make sure cur->item is still valid memory */ 1473 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1474 if (cur->item->name) { 1475 cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); 1476 strcpy(cur->name, cur->item->name); 1477 } 1478 aim_ssi_itemlist_del(&sess->ssi.local, cur->item); 1479 } 1480 cur->item = NULL; 1481 1482 } else if (cur->action == AIM_CB_SSI_MOD) { 1483 /* Replace the local item with the item from the official list */ 1484 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1485 struct aim_ssi_item *cur1; 1486 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) { 1487 free(cur->item->name); 1488 if (cur1->name) { 1489 cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char)); 1490 strcpy(cur->item->name, cur1->name); 1491 } else 1492 cur->item->name = NULL; 1493 aim_freetlvchain(&cur->item->data); 1494 cur->item->data = aim_tlvlist_copy(cur1->data); 1495 } 1496 } else 1497 cur->item = NULL; 1498 1499 } else if (cur->action == AIM_CB_SSI_DEL) { 1500 /* Add the item back into the local list */ 1501 if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) { 1502 aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1503 } else 1504 cur->item = NULL; 1505 } 1506 1507 } else { 1508 /* Do the exact opposite */ 1509 if (cur->action == AIM_CB_SSI_ADD) { 1510 /* Add the local item to the official list */ 1511 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1512 aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1513 } else 1514 cur->item = NULL; 1515 1516 } else if (cur->action == AIM_CB_SSI_MOD) { 1517 /* Replace the official item with the item from the local list */ 1518 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1519 struct aim_ssi_item *cur1; 1520 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) { 1521 free(cur1->name); 1522 if (cur->item->name) { 1523 cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); 1524 strcpy(cur1->name, cur->item->name); 1525 } else 1526 cur1->name = NULL; 1527 aim_freetlvchain(&cur1->data); 1528 cur1->data = aim_tlvlist_copy(cur->item->data); 1529 } 1530 } else 1531 cur->item = NULL; 1532 1533 } else if (cur->action == AIM_CB_SSI_DEL) { 1534 /* Remove the item from the official list */ 1535 if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) 1536 aim_ssi_itemlist_del(&sess->ssi.official, cur->item); 1537 cur->item = NULL; 1538 } 1539 1540 } 1541 } /* End if (cur->item) */ 1542 } /* End for loop */ 1543 1544 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1545 ret = userfunc(sess, rx, sess->ssi.pending); 1546 1547 /* Free all aim_ssi_tmp's with an outcome */ 1548 cur = sess->ssi.pending; 1549 while (cur && (cur->ack != 0xffff)) { 1550 del = cur; 1551 cur = cur->next; 1552 free(del->name); 1553 free(del); 1554 } 1555 sess->ssi.pending = cur; 1556 1557 /* If we're not waiting for any more acks, then send more SNACs */ 1558 if (!sess->ssi.pending) { 1559 sess->ssi.pending = NULL; 1560 sess->ssi.waiting_for_ack = 0; 1561 aim_ssi_sync(sess); 1562 } 1563 1564 return ret; 1565 } 1566 1567 /* 1568 * Subtype 0x000f - SSI Data Unchanged. 1569 * 1570 * Response to aim_ssi_reqifchanged() if the server-side data is not newer than 1571 * posted local stamp/revision. 1572 * 1573 */ 1574 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1575 { 1576 int ret = 0; 1577 aim_rxcallback_t userfunc; 1578 1579 sess->ssi.received_data = 1; 1358 1580 1359 1581 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) … … 1364 1586 1365 1587 /* 1366 * S SI Begin Data Modification.1588 * Subtype 0x0011 - SSI Begin Data Modification. 1367 1589 * 1368 1590 * Tells the server you're going to start modifying data. 1369 1591 * 1370 1592 */ 1371 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) 1372 { 1593 faim_export int aim_ssi_modbegin(aim_session_t *sess) 1594 { 1595 aim_conn_t *conn; 1596 1597 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1598 return -EINVAL; 1599 1373 1600 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); 1374 1601 } 1375 1602 1376 1603 /* 1377 * SSI End Data Modification. 1378 * 1379 * Tells the server you're done modifying data. 1380 * 1381 */ 1382 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) 1383 { 1604 * Subtype 0x0012 - SSI End Data Modification. 1605 * 1606 * Tells the server you're finished modifying data. 1607 * 1608 */ 1609 faim_export int aim_ssi_modend(aim_session_t *sess) 1610 { 1611 aim_conn_t *conn; 1612 1613 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1614 return -EINVAL; 1615 1384 1616 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); 1385 1617 } 1386 1618 1387 1619 /* 1388 * SSI Data Unchanged. 1389 * 1390 * Response to aim_ssi_reqdata() if the server-side data is not newer than 1391 * posted local stamp/revision. 1392 * 1393 */ 1394 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1620 * Subtype 0x0014 - Grant authorization 1621 * 1622 * Authorizes a contact so they can add you to their contact list. 1623 * 1624 */ 1625 faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg) 1626 { 1627 aim_conn_t *conn; 1628 aim_frame_t *fr; 1629 aim_snacid_t snacid; 1630 1631 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1632 return -EINVAL; 1633 1634 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) 1635 return -ENOMEM; 1636 1637 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0); 1638 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid); 1639 1640 /* Screen name */ 1641 aimbs_put8(&fr->data, strlen(sn)); 1642 aimbs_putraw(&fr->data, sn, strlen(sn)); 1643 1644 /* Message (null terminated) */ 1645 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); 1646 if (msg) { 1647 aimbs_putraw(&fr->data, msg, strlen(msg)); 1648 aimbs_put8(&fr->data, 0x00); 1649 } 1650 1651 /* Unknown */ 1652 aimbs_put16(&fr->data, 0x0000); 1653 1654 aim_tx_enqueue(sess, fr); 1655 1656 return 0; 1657 } 1658 1659 /* 1660 * Subtype 0x0015 - Receive an authorization grant 1661 */ 1662 static int receiveauthgrant(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1395 1663 { 1396 1664 int ret = 0; 1397 1665 aim_rxcallback_t userfunc; 1398 1399 sess->ssi.received_data = 1; 1666 fu16_t tmp; 1667 char *sn, *msg; 1668 1669 /* Read screen name */ 1670 if ((tmp = aimbs_get8(bs))) 1671 sn = aimbs_getstr(bs, tmp); 1672 else 1673 sn = NULL; 1674 1675 /* Read message (null terminated) */ 1676 if ((tmp = aimbs_get16(bs))) 1677 msg = aimbs_getstr(bs, tmp); 1678 else 1679 msg = NULL; 1680 1681 /* Unknown */ 1682 tmp = aimbs_get16(bs); 1400 1683 1401 1684 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1402 ret = userfunc(sess, rx); 1685 ret = userfunc(sess, rx, sn, msg); 1686 1687 free(sn); 1688 free(msg); 1689 1690 return ret; 1691 } 1692 1693 /* 1694 * Subtype 0x0018 - Send authorization request 1695 * 1696 * Sends a request for authorization to the given contact. The request will either be 1697 * granted, denied, or dropped. 1698 * 1699 */ 1700 faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg) 1701 { 1702 aim_conn_t *conn; 1703 aim_frame_t *fr; 1704 aim_snacid_t snacid; 1705 1706 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1707 return -EINVAL; 1708 1709 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) 1710 return -ENOMEM; 1711 1712 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0); 1713 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid); 1714 1715 /* Screen name */ 1716 aimbs_put8(&fr->data, strlen(sn)); 1717 aimbs_putraw(&fr->data, sn, strlen(sn)); 1718 1719 /* Message (null terminated) */ 1720 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); 1721 if (msg) { 1722 aimbs_putraw(&fr->data, msg, strlen(msg)); 1723 aimbs_put8(&fr->data, 0x00); 1724 } 1725 1726 /* Unknown */ 1727 aimbs_put16(&fr->data, 0x0000); 1728 1729 aim_tx_enqueue(sess, fr); 1730 1731 return 0; 1732 } 1733 1734 /* 1735 * Subtype 0x0019 - Receive an authorization request 1736 */ 1737 static int receiveauthrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1738 { 1739 int ret = 0; 1740 aim_rxcallback_t userfunc; 1741 fu16_t tmp; 1742 char *sn, *msg; 1743 1744 /* Read screen name */ 1745 if ((tmp = aimbs_get8(bs))) 1746 sn = aimbs_getstr(bs, tmp); 1747 else 1748 sn = NULL; 1749 1750 /* Read message (null terminated) */ 1751 if ((tmp = aimbs_get16(bs))) 1752 msg = aimbs_getstr(bs, tmp); 1753 else 1754 msg = NULL; 1755 1756 /* Unknown */ 1757 tmp = aimbs_get16(bs); 1758 1759 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1760 ret = userfunc(sess, rx, sn, msg); 1761 1762 free(sn); 1763 free(msg); 1764 1765 return ret; 1766 } 1767 1768 /* 1769 * Subtype 0x001a - Send authorization reply 1770 * 1771 * Sends a reply to a request for authorization. The reply can either 1772 * grant authorization or deny authorization. 1773 * 1774 * if reply=0x00 then deny 1775 * if reply=0x01 then grant 1776 * 1777 */ 1778 faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg) 1779 { 1780 aim_conn_t *conn; 1781 aim_frame_t *fr; 1782 aim_snacid_t snacid; 1783 1784 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1785 return -EINVAL; 1786 1787 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2))) 1788 return -ENOMEM; 1789 1790 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0); 1791 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid); 1792 1793 /* Screen name */ 1794 aimbs_put8(&fr->data, strlen(sn)); 1795 aimbs_putraw(&fr->data, sn, strlen(sn)); 1796 1797 /* Grant or deny */ 1798 aimbs_put8(&fr->data, reply); 1799 1800 /* Message (null terminated) */ 1801 aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0); 1802 if (msg) { 1803 aimbs_putraw(&fr->data, msg, strlen(msg)); 1804 aimbs_put8(&fr->data, 0x00); 1805 } 1806 1807 /* Unknown */ 1808 aimbs_put16(&fr->data, 0x0000); 1809 1810 aim_tx_enqueue(sess, fr); 1811 1812 return 0; 1813 } 1814 1815 /* 1816 * Subtype 0x001b - Receive an authorization reply 1817 * You get this bad boy when other people respond to the authorization 1818 * request that you have previously sent them. 1819 */ 1820 static int receiveauthreply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1821 { 1822 int ret = 0; 1823 aim_rxcallback_t userfunc; 1824 fu16_t tmp; 1825 fu8_t reply; 1826 char *sn, *msg; 1827 1828 /* Read screen name */ 1829 if ((tmp = aimbs_get8(bs))) 1830 sn = aimbs_getstr(bs, tmp); 1831 else 1832 sn = NULL; 1833 1834 /* Read reply */ 1835 reply = aimbs_get8(bs); 1836 1837 /* Read message (null terminated) */ 1838 if ((tmp = aimbs_get16(bs))) 1839 msg = aimbs_getstr(bs, tmp); 1840 else 1841 msg = NULL; 1842 1843 /* Unknown */ 1844 tmp = aimbs_get16(bs); 1845 1846 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1847 ret = userfunc(sess, rx, sn, reply, msg); 1848 1849 free(sn); 1850 free(msg); 1851 1852 return ret; 1853 } 1854 1855 /* 1856 * Subtype 0x001c - Receive a message telling you someone added you to their list. 1857 */ 1858 static int receiveadded(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1859 { 1860 int ret = 0; 1861 aim_rxcallback_t userfunc; 1862 fu16_t tmp; 1863 char *sn; 1864 1865 /* Read screen name */ 1866 if ((tmp = aimbs_get8(bs))) 1867 sn = aimbs_getstr(bs, tmp); 1868 else 1869 sn = NULL; 1870 1871 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1872 ret = userfunc(sess, rx, sn); 1873 1874 free(sn); 1403 1875 1404 1876 return ret; … … 1412 1884 else if (snac->subtype == AIM_CB_SSI_LIST) 1413 1885 return parsedata(sess, mod, rx, snac, bs); 1886 else if (snac->subtype == AIM_CB_SSI_ADD) 1887 return parseadd(sess, mod, rx, snac, bs); 1888 else if (snac->subtype == AIM_CB_SSI_MOD) 1889 return parsemod(sess, mod, rx, snac, bs); 1890 else if (snac->subtype == AIM_CB_SSI_DEL) 1891 return parsedel(sess, mod, rx, snac, bs); 1414 1892 else if (snac->subtype == AIM_CB_SSI_SRVACK) 1415 1893 return parseack(sess, mod, rx, snac, bs); 1416 1894 else if (snac->subtype == AIM_CB_SSI_NOLIST) 1417 1895 return parsedataunchanged(sess, mod, rx, snac, bs); 1896 else if (snac->subtype == AIM_CB_SSI_RECVAUTH) 1897 return receiveauthgrant(sess, mod, rx, snac, bs); 1898 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ) 1899 return receiveauthrequest(sess, mod, rx, snac, bs); 1900 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP) 1901 return receiveauthreply(sess, mod, rx, snac, bs); 1902 else if (snac->subtype == AIM_CB_SSI_ADDED) 1903 return receiveadded(sess, mod, rx, snac, bs); 1418 1904 1419 1905 return 0; … … 1431 1917 1432 1918 mod->family = AIM_CB_FAM_SSI; 1433 mod->version = 0x000 1;1919 mod->version = 0x0004; 1434 1920 mod->toolid = 0x0110; 1435 mod->toolversion = 0x0 47b;1921 mod->toolversion = 0x0629; 1436 1922 mod->flags = 0; 1437 1923 strncpy(mod->name, "ssi", sizeof(mod->name)); -
libfaim/stats.c
r862371b re374dee 9 9 static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 10 10 { 11 int ret = 0; 12 aim_rxcallback_t userfunc; 11 13 fu16_t interval; 12 aim_rxcallback_t userfunc;13 14 14 15 interval = aimbs_get16(bs); 15 16 16 17 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 17 ret urnuserfunc(sess, rx, interval);18 ret = userfunc(sess, rx, interval); 18 19 19 return 0;20 return ret; 20 21 } 21 22 -
libfaim/tlv.c
r862371b re374dee 114 114 * There are a number of places where you want to read in a tlvchain, 115 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 .116 * preceeded by the number of TLVs. So you can limit that with this. 117 117 * 118 118 * Reads and parses a series of TLV patterns from a data buffer; the … … 131 131 { 132 132 aim_tlvlist_t *list = NULL, *cur; 133 133 134 134 while ((aim_bstream_empty(bs) > 0) && (num != 0)) { 135 135 fu16_t type, length; … … 159 159 cur->tlv->type = type; 160 160 if ((cur->tlv->length = length)) { 161 cur->tlv->value = aimbs_getraw(bs, length); 161 cur->tlv->value = aimbs_getraw(bs, length); 162 162 if (!cur->tlv->value) { 163 163 freetlv(&cur->tlv); … … 177 177 178 178 /** 179 * aim_readtlvchain_len - Read a TLV chain from a buffer. 180 * @param bs Input bstream 181 * @param len The max length in bytes that will be read. 182 * There are a number of places where you want to read in a tlvchain, 183 * but the chain is not at the end of the SNAC, and the chain is 184 * preceeded by the length of the TLVs. So you can limit that with this. 185 * 186 * Reads and parses a series of TLV patterns from a data buffer; the 187 * returned structure is manipulatable with the rest of the TLV 188 * routines. When done with a TLV chain, aim_freetlvchain() should 189 * be called to free the dynamic substructures. 190 * 191 * XXX There should be a flag setable here to have the tlvlist contain 192 * bstream references, so that at least the ->value portion of each 193 * element doesn't need to be malloc/memcpy'd. This could prove to be 194 * just as effecient as the in-place TLV parsing used in a couple places 195 * in libfaim. 196 * 197 */ 198 faim_internal aim_tlvlist_t *aim_readtlvchain_len(aim_bstream_t *bs, fu16_t len) 199 { 200 aim_tlvlist_t *list = NULL, *cur; 201 202 while ((aim_bstream_empty(bs) > 0) && (len > 0)) { 203 fu16_t type, length; 204 205 type = aimbs_get16(bs); 206 length = aimbs_get16(bs); 207 208 if (length > aim_bstream_empty(bs)) { 209 aim_freetlvchain(&list); 210 return NULL; 211 } 212 213 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); 214 if (!cur) { 215 aim_freetlvchain(&list); 216 return NULL; 217 } 218 219 memset(cur, 0, sizeof(aim_tlvlist_t)); 220 221 cur->tlv = createtlv(); 222 if (!cur->tlv) { 223 free(cur); 224 aim_freetlvchain(&list); 225 return NULL; 226 } 227 cur->tlv->type = type; 228 if ((cur->tlv->length = length)) { 229 cur->tlv->value = aimbs_getraw(bs, length); 230 if (!cur->tlv->value) { 231 freetlv(&cur->tlv); 232 free(cur); 233 aim_freetlvchain(&list); 234 return NULL; 235 } 236 } 237 238 len -= aim_sizetlvchain(&cur); 239 cur->next = list; 240 list = cur; 241 } 242 243 return list; 244 } 245 246 /** 247 * aim_tlvlist_copy - Duplicate a TLV chain. 248 * @param orig 249 * 250 * This is pretty pelf exslanatory. 251 * 252 */ 253 faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig) 254 { 255 aim_tlvlist_t *new = NULL; 256 257 while (orig) { 258 aim_addtlvtochain_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value); 259 orig = orig->next; 260 } 261 262 return new; 263 } 264 265 /* 266 * Compare two TLV lists for equality. This probably is not the most 267 * efficient way to do this. 268 * 269 * @param one One of the TLV chains to compare. 270 * @param two The other TLV chain to compare. 271 * @preturn Retrun 0 if the lists are the same, return 1 if they are different. 272 */ 273 faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two) 274 { 275 aim_bstream_t bs1, bs2; 276 277 if (aim_sizetlvchain(&one) != aim_sizetlvchain(&two)) 278 return 1; 279 280 aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_sizetlvchain(&one)*sizeof(fu8_t))), aim_sizetlvchain(&one)); 281 aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_sizetlvchain(&two)*sizeof(fu8_t))), aim_sizetlvchain(&two)); 282 283 aim_writetlvchain(&bs1, &one); 284 aim_writetlvchain(&bs2, &two); 285 286 if (memcmp(bs1.data, bs2.data, bs1.len)) { 287 free(bs1.data); 288 free(bs2.data); 289 return 1; 290 } 291 292 free(bs1.data); 293 free(bs2.data); 294 295 return 0; 296 } 297 298 /** 179 299 * aim_freetlvchain - Free a TLV chain structure 180 300 * @list: Chain to be freed … … 463 583 464 584 /* do an initial run to test total length */ 465 for (cur = *list, goodbuflen = 0; cur; cur = cur->next) { 466 goodbuflen += 2 + 2; /* type + len */ 467 goodbuflen += cur->tlv->length; 468 } 585 goodbuflen = aim_sizetlvchain(list); 469 586 470 587 if (goodbuflen > aim_bstream_empty(bs)) -
libfaim/txqueue.c
r862371b re374dee 29 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) 30 30 { 31 aim_frame_t *fr; 32 33 if (!conn) { 34 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); 35 return NULL; 36 } 37 38 /* For sanity... */ 39 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || 40 (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { 41 if (framing != AIM_FRAMETYPE_OFT) { 42 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); 43 return NULL; 44 } 45 } else { 46 if (framing != AIM_FRAMETYPE_FLAP) { 47 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); 48 return NULL; 49 } 50 } 51 52 if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) 53 return NULL; 54 memset(fr, 0, sizeof(aim_frame_t)); 55 56 fr->conn = conn; 57 58 fr->hdrtype = framing; 59 60 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { 61 62 fr->hdr.flap.type = chan; 63 64 } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) { 65 66 fr->hdr.rend.type = chan; 67 68 } else 69 faimdprintf(sess, 0, "tx_new: unknown framing\n"); 70 71 if (datalen > 0) { 72 fu8_t *data; 73 74 if (!(data = (unsigned char *)malloc(datalen))) { 75 aim_frame_destroy(fr); 76 return NULL; 77 } 78 79 aim_bstream_init(&fr->data, data, datalen); 80 } 81 82 return fr; 31 aim_frame_t *fr; 32 33 if (!conn) { 34 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); 35 return NULL; 36 } 37 38 /* For sanity... */ 39 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_LISTENER)) { 40 if (framing != AIM_FRAMETYPE_OFT) { 41 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); 42 return NULL; 43 } 44 } else { 45 if (framing != AIM_FRAMETYPE_FLAP) { 46 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); 47 return NULL; 48 } 49 } 50 51 if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) return NULL; 52 memset(fr, 0, sizeof(aim_frame_t)); 53 54 fr->conn = conn; 55 fr->hdrtype = framing; 56 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { 57 fr->hdr.flap.type = chan; 58 } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) { 59 fr->hdr.rend.type = chan; 60 } else { 61 faimdprintf(sess, 0, "tx_new: unknown framing\n"); 62 } 63 64 if (datalen > 0) { 65 fu8_t *data; 66 if (!(data = (unsigned char *)malloc(datalen))) { 67 aim_frame_destroy(fr); 68 return NULL; 69 } 70 aim_bstream_init(&fr->data, data, datalen); 71 } 72 73 return fr; 83 74 } 84 75 … … 99 90 static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr) 100 91 { 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 92 93 if (!fr->conn) { 94 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); 95 fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); 96 } 97 98 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { 99 /* assign seqnum -- XXX should really not assign until hardxmit */ 100 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); 101 } 102 103 fr->handled = 0; /* not sent yet */ 104 105 /* see overhead note in aim_rxqueue counterpart */ 106 if (!sess->queue_outgoing) 107 sess->queue_outgoing = fr; 108 else { 109 aim_frame_t *cur; 110 111 for (cur = sess->queue_outgoing; cur->next; cur = cur->next) 112 ; 113 cur->next = fr; 114 } 115 116 return 0; 126 117 } 127 118 … … 140 131 { 141 132 142 if (!fr->conn) { 143 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); 144 aim_frame_destroy(fr); 145 return 0; 146 } 147 148 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) 149 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); 150 151 fr->handled = 0; /* not sent yet */ 152 153 aim_tx_sendframe(sess, fr); 154 155 aim_frame_destroy(fr); 156 157 return 0; 133 if (!fr->conn) { 134 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); 135 aim_frame_destroy(fr); 136 return 0; 137 } 138 139 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); 140 fr->handled = 0; /* not sent yet */ 141 aim_tx_sendframe(sess, fr); 142 aim_frame_destroy(fr); 143 144 return 0; 158 145 } 159 146 160 147 faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *)) 161 148 { 162 163 if (what == AIM_TX_QUEUED) 164 sess->tx_enqueue = &aim_tx_enqueue__queuebased; 165 else if (what == AIM_TX_IMMEDIATE) 166 sess->tx_enqueue = &aim_tx_enqueue__immediate; 167 else if (what == AIM_TX_USER) { 168 if (!func) 169 return -EINVAL; 170 sess->tx_enqueue = func; 171 } else 172 return -EINVAL; /* unknown action */ 173 174 return 0; 149 if (what == AIM_TX_QUEUED) { 150 sess->tx_enqueue = &aim_tx_enqueue__queuebased; 151 } else if (what == AIM_TX_IMMEDIATE) { 152 sess->tx_enqueue = &aim_tx_enqueue__immediate; 153 } else if (what == AIM_TX_USER) { 154 if (!func) return -EINVAL; 155 sess->tx_enqueue = func; 156 } else { 157 return -EINVAL; /* unknown action */ 158 } 159 160 return 0; 175 161 } 176 162 177 163 faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr) 178 164 { 179 180 181 182 183 184 185 186 187 188 189 190 165 166 /* 167 * If we want to send a connection thats inprogress, we have to force 168 * them to use the queue based version. Otherwise, use whatever they 169 * want. 170 */ 171 if (fr && fr->conn && 172 (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) { 173 return aim_tx_enqueue__queuebased(sess, fr); 174 } 175 176 return (*sess->tx_enqueue)(sess, fr); 191 177 } 192 178 … … 202 188 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn) 203 189 { 204 flap_seqnum_t ret; 205 206 ret = ++conn->seqnum; 207 208 return ret; 190 flap_seqnum_t ret; 191 ret = ++conn->seqnum; 192 return ret; 209 193 } 210 194 211 195 static int aim_send(int fd, const void *buf, size_t count) 212 196 { 213 int left, cur; 214 215 for (cur = 0, left = count; left; ) { 216 int ret; 217 218 ret = send(fd, ((unsigned char *)buf)+cur, left, 0); 219 if (ret == -1) 220 return -1; 221 else if (ret == 0) 222 return cur; 223 224 cur += ret; 225 left -= ret; 226 } 227 228 return cur; 197 int left, cur; 198 199 for (cur = 0, left = count; left; ) { 200 int ret; 201 202 ret = send(fd, ((unsigned char *)buf)+cur, left, 0); 203 if (ret == -1) { 204 return -1; 205 } else if (ret == 0) { 206 return cur; 207 } 208 209 cur += ret; 210 left -= ret; 211 } 212 213 return cur; 229 214 } 230 215 231 216 static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) 232 217 { 233 int wrote = 0; 234 if (!bs || !conn || (count < 0)) 235 return -EINVAL; 236 237 if (count > aim_bstream_empty(bs)) 238 count = aim_bstream_empty(bs); /* truncate to remaining space */ 239 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 262 263 if (((aim_session_t *)conn->sessv)->debug >= 2) { 264 int i; 265 aim_session_t *sess = (aim_session_t *)conn->sessv; 266 267 faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote); 268 for (i = 0; i < wrote; i++) { 269 if (!(i % 8)) 270 faimdprintf(sess, 2, "\n\t"); 271 faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i)); 272 } 273 faimdprintf(sess, 2, "\n"); 274 } 275 276 277 bs->offset += wrote; 278 279 return wrote; 218 int wrote = 0; 219 if (!bs || !conn || (count < 0)) 220 return -EINVAL; 221 222 if (count > aim_bstream_empty(bs)) 223 count = aim_bstream_empty(bs); /* truncate to remaining space */ 224 225 if (count) { 226 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) && 227 (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { 228 /* I strongly suspect that this is a horrible thing to do 229 * and I feel really guilty doing it. */ 230 const char *sn = aim_odc_getsn(conn); 231 aim_rxcallback_t userfunc; 232 while (count - wrote > 1024) { 233 wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, 1024); 234 if ((userfunc=aim_callhandler(conn->sessv, conn, 235 AIM_CB_FAM_SPECIAL, 236 AIM_CB_SPECIAL_IMAGETRANSFER))) 237 userfunc(conn->sessv, NULL, sn, 238 count-wrote>1024 ? ((double)wrote / count) : 1); 239 } 240 } 241 if (count - wrote) { 242 wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote); 243 } 244 245 } 246 247 if (((aim_session_t *)conn->sessv)->debug >= 2) { 248 int i; 249 aim_session_t *sess = (aim_session_t *)conn->sessv; 250 251 faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote); 252 for (i = 0; i < wrote; i++) { 253 if (!(i % 8)) 254 faimdprintf(sess, 2, "\n\t"); 255 faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i)); 256 } 257 faimdprintf(sess, 2, "\n"); 258 } 259 260 bs->offset += wrote; 261 262 return wrote; 280 263 } 281 264 282 265 static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr) 283 266 { 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 267 aim_bstream_t obs; 268 fu8_t *obs_raw; 269 int payloadlen, err = 0, obslen; 270 271 payloadlen = aim_bstream_curpos(&fr->data); 272 273 if (!(obs_raw = malloc(6 + payloadlen))) 274 return -ENOMEM; 275 276 aim_bstream_init(&obs, obs_raw, 6 + payloadlen); 277 278 /* FLAP header */ 279 aimbs_put8(&obs, 0x2a); 280 aimbs_put8(&obs, fr->hdr.flap.type); 281 aimbs_put16(&obs, fr->hdr.flap.seqnum); 282 aimbs_put16(&obs, payloadlen); 283 284 /* payload */ 285 aim_bstream_rewind(&fr->data); 286 aimbs_putbs(&obs, &fr->data, payloadlen); 287 288 obslen = aim_bstream_curpos(&obs); 289 aim_bstream_rewind(&obs); 290 if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) 291 err = -errno; 292 293 free(obs_raw); /* XXX aim_bstream_free */ 294 295 fr->handled = 1; 296 fr->conn->lastactivity = time(NULL); 297 298 return err; 316 299 } 317 300 -
libfaim/util.c
r862371b re374dee 1 1 /* 2 * 3 * 4 * 2 * A little bit of this 3 * A little bit of that 4 * It started with a kiss 5 * Now we're up to bat 5 6 */ 6 7 … … 9 10 #include <ctype.h> 10 11 11 faim_export faim_shortfunc int aimutil_putstr(u_char *dest, const char *src, int len) 12 #ifdef _WIN32 13 #include "win32dep.h" 14 #endif 15 16 faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...) 17 { 18 if (!sess) { 19 fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); 20 return; 21 } 22 if ((dlevel <= sess->debug) && sess->debugcb) { 23 va_list ap; 24 va_start(ap, format); 25 sess->debugcb(sess, dlevel, format, ap); 26 va_end(ap); 27 } 28 29 return; 30 } 31 32 faim_export int aimutil_putstr(char *dest, const char *src, int len) 12 33 { 13 34 memcpy(dest, src, len); … … 20 41 * 21 42 */ 22 faim_export int aimutil_tokslen(char *toSearch, int index, char dl)43 faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl) 23 44 { 24 45 int curCount = 1; … … 30 51 next = strchr(toSearch, dl); 31 52 32 while(curCount < index && next != NULL) {53 while(curCount < theindex && next != NULL) { 33 54 curCount++; 34 55 last = next + 1; … … 36 57 } 37 58 38 if ((curCount < index) || (next == NULL))59 if ((curCount < theindex) || (next == NULL)) 39 60 toReturn = strlen(toSearch) - (curCount - 1); 40 61 else … … 61 82 } 62 83 63 faim_export char *aimutil_itemi dx(char *toSearch, intindex, char dl)84 faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl) 64 85 { 65 86 int curCount; … … 73 94 next = strchr(toSearch, dl); 74 95 75 while (curCount < index && next != NULL) {96 while (curCount < theindex && next != NULL) { 76 97 curCount++; 77 98 last = next + 1; … … 79 100 } 80 101 81 if (curCount < index) {102 if (curCount < theindex) { 82 103 toReturn = malloc(sizeof(char)); 83 104 *toReturn = '\0'; … … 85 106 next = strchr(last, dl); 86 107 87 if (curCount < index) {108 if (curCount < theindex) { 88 109 toReturn = malloc(sizeof(char)); 89 110 *toReturn = '\0'; … … 101 122 } 102 123 124 /** 125 * Calculate the checksum of a given icon. 126 * 127 */ 128 faim_export fu16_t aimutil_iconsum(const fu8_t *buf, int buflen) 129 { 130 fu32_t sum; 131 int i; 132 133 for (i=0, sum=0; i+1<buflen; i+=2) 134 sum += (buf[i+1] << 8) + buf[i]; 135 if (i < buflen) 136 sum += buf[i]; 137 sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff); 138 139 return sum; 140 } 141 142 faim_export int aim_util_getlocalip(fu8_t *ip) 143 { 144 struct hostent *hptr; 145 char localhost[129]; 146 147 /* XXX if available, use getaddrinfo() */ 148 /* XXX allow client to specify which IP to use for multihomed boxes */ 149 150 if (gethostname(localhost, 128) < 0) 151 return -1; 152 153 if (!(hptr = gethostbyname(localhost))) 154 return -1; 155 memcpy(ip, hptr->h_addr_list[0], 4); 156 157 return 0; 158 } 159 103 160 /* 104 161 * int snlen(const char *) … … 112 169 { 113 170 int i = 0; 114 const char *curPtr = NULL;115 171 116 172 if (!sn) 117 173 return 0; 118 174 119 curPtr = sn; 120 while ( (*curPtr) != (char) NULL) { 121 if ((*curPtr) != ' ') 122 i++; 123 curPtr++; 175 while (*sn != '\0') { 176 if (*sn != ' ') 177 i++; 178 sn++; 124 179 } 125 180 … … 133 188 * on screen names for AIM/AOL. Mainly, this means case and space 134 189 * insensitivity (all case differences and spacing differences are 135 * ignored). 190 * ignored, with the exception that screen names can not start with 191 * a space). 136 192 * 137 193 * Return: 0 if equal … … 141 197 faim_export int aim_sncmp(const char *sn1, const char *sn2) 142 198 { 143 const char *curPtr1 = NULL, *curPtr2 = NULL; 144 145 if (aim_snlen(sn1) != aim_snlen(sn2)) 146 return 1; 147 148 curPtr1 = sn1; 149 curPtr2 = sn2; 150 while ( (*curPtr1 != (char) NULL) && (*curPtr2 != (char) NULL) ) { 151 if ( (*curPtr1 == ' ') || (*curPtr2 == ' ') ) { 152 if (*curPtr1 == ' ') 153 curPtr1++; 154 if (*curPtr2 == ' ') 155 curPtr2++; 156 } else { 157 if ( toupper(*curPtr1) != toupper(*curPtr2)) 158 return 1; 159 curPtr1++; 160 curPtr2++; 161 } 162 } 163 164 /* Should both be NULL */ 165 if (*curPtr1 != *curPtr2) 166 return 1; 199 200 do { 201 while (*sn2 == ' ') 202 sn2++; 203 while (*sn1 == ' ') 204 sn1++; 205 if (toupper(*sn1) != toupper(*sn2)) 206 return 1; 207 } while ((*sn1 != '\0') && sn1++ && sn2++); 167 208 168 209 return 0; 169 210 } 170 171 /* strsep Copyright (C) 1992, 1993 Free Software Foundation, Inc.172 strsep is part of the GNU C Library.173 174 The GNU C Library is free software; you can redistribute it and/or175 modify it under the terms of the GNU Library General Public License as176 published by the Free Software Foundation; either version 2 of the177 License, or (at your option) any later version.178 179 The GNU C Library is distributed in the hope that it will be useful,180 but WITHOUT ANY WARRANTY; without even the implied warranty of181 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU182 Library General Public License for more details.183 184 You should have received a copy of the GNU Library General Public185 License along with the GNU C Library; see the file COPYING.LIB. If186 not, write to the Free Software Foundation, Inc., 675 Mass Ave,187 Cambridge, MA 02139, USA. */188 189 /* Minor changes by and1000 on 15/1/97 to make it go under Nemesis */190 191 faim_export char *aim_strsep(char **pp, const char *delim)192 {193 char *p, *q;194 195 if (!(p = *pp))196 return 0;197 198 if ((q = strpbrk (p, delim))) {199 *pp = q + 1;200 *q = '\0';201 } else202 *pp = 0;203 204 return p;205 }
Note: See TracChangeset
for help on using the changeset viewer.