- 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
-
admin.c (modified) (4 diffs)
-
aim.h (modified) (41 diffs)
-
aim_cbtypes.h (modified) (8 diffs)
-
aim_internal.h (modified) (9 diffs)
-
auth.c (modified) (18 diffs)
-
bos.c (modified) (3 diffs)
-
bstream.c (modified) (1 diff)
-
buddylist.c (modified) (3 diffs)
-
chat.c (modified) (14 diffs)
-
chatnav.c (modified) (1 diff)
-
configure (modified) (1 diff)
-
configure.in (modified) (1 diff)
-
conn.c (modified) (7 diffs)
-
email.c (modified) (3 diffs)
-
ft.c (modified) (14 diffs)
-
icq.c (modified) (7 diffs)
-
im.c (modified) (71 diffs)
-
info.c (modified) (18 diffs)
-
invite.c (modified) (1 diff)
-
meta.c (modified) (2 diffs)
-
msgcookie.c (modified) (3 diffs)
-
newsearch.c (modified) (2 diffs)
-
rxhandlers.c (modified) (5 diffs)
-
rxqueue.c (modified) (4 diffs)
-
search.c (modified) (2 diffs)
-
service.c (modified) (16 diffs)
-
snac.c (modified) (4 diffs)
-
ssi.c (modified) (21 diffs)
-
stats.c (modified) (1 diff)
-
tlv.c (modified) (5 diffs)
-
txqueue.c (modified) (4 diffs)
-
util.c (modified) (13 diffs)
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 0x0001230 #define AIM_CONN_SUBTYPE_OFT_GETFILE 0x0002231 #define AIM_CONN_SUBTYPE_OFT_SENDFILE 0x0003232 #define AIM_CONN_SUBTYPE_OFT_BUDDYICON 0x0004233 #define AIM_CONN_SUBTYPE_OFT_VOICE 0x0005286 #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 0x0001239 #define AIM_CONN_STATUS_INTERNALERR 0x0002240 #define AIM_CONN_STATUS_RESOLVERR 0x0040241 #define AIM_CONN_STATUS_CONNERR 0x0080242 #define AIM_CONN_STATUS_INPROGRESS 0x0100243 244 #define AIM_FRAMETYPE_FLAP 0x0000245 #define AIM_FRAMETYPE_OFT 0x0001295 #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; /* the connection it came in on... */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 0x0000832 #define AIM_RENDEZVOUS_CANCEL 0x0001833 #define AIM_RENDEZVOUS_ACCEPT 0x0002799 #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 0x0006874 #define AIM_ICQMSG_AUTHDENIED 0x0007875 #define AIM_ICQMSG_AUTHGRANTED 0x0008841 #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 AOL Mobile Communicator, WinAIM 1.0.41441 * 0501 0003 0101 0201 01 WinAIM 2.0.847, 2.1.1187, 3.0.1464,42 * 4.3.2229, 4.4.228643 * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here)44 * 0501 0003 0101 02 WinAIM 545 * 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 if (!fr->conn) {103 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");104 fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);105 }106 107 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {108 /* assign seqnum -- XXX should really not assign until hardxmit */109 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);110 }111 112 fr->handled = 0; /* not sent yet */113 114 /* see overhead note in aim_rxqueue counterpart */115 if (!sess->queue_outgoing)116 sess->queue_outgoing = fr;117 else {118 aim_frame_t *cur;119 120 for (cur = sess->queue_outgoing; cur->next; cur = cur->next)121 ;122 cur->next = fr;123 }124 125 return 0;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 * If we want to send a connection thats inprogress, we have to force182 * them to use the queue based version. Otherwise, use whatever they183 * want.184 */185 if (fr && fr->conn &&186 (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {187 return aim_tx_enqueue__queuebased(sess, fr);188 }189 190 return (*sess->tx_enqueue)(sess, fr);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 aim_bstream_t obs;285 fu8_t *obs_raw;286 int payloadlen, err = 0, obslen;287 288 payloadlen = aim_bstream_curpos(&fr->data);289 290 if (!(obs_raw = malloc(6 + payloadlen)))291 return -ENOMEM;292 293 aim_bstream_init(&obs, obs_raw, 6 + payloadlen);294 295 /* FLAP header */296 aimbs_put8(&obs, 0x2a);297 aimbs_put8(&obs, fr->hdr.flap.type);298 aimbs_put16(&obs, fr->hdr.flap.seqnum);299 aimbs_put16(&obs, payloadlen);300 301 /* payload */302 aim_bstream_rewind(&fr->data);303 aimbs_putbs(&obs, &fr->data, payloadlen);304 305 obslen = aim_bstream_curpos(&obs);306 aim_bstream_rewind(&obs);307 if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)308 err = -errno;309 310 free(obs_raw); /* XXX aim_bstream_free */311 312 fr->handled = 1;313 fr->conn->lastactivity = time(NULL);314 315 return err;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.
