src/protocols/oscar/im.c

changeset 4617
35d860860593
parent 4173
e2528bd24e6f
child 4650
5b2338bb19fd
equal deleted inserted replaced
4616:177e05ba38a3 4617:35d860860593
1 /* 1 /*
2 * Family 0x0004 - Routines for sending/receiving Instant Messages. 2 * Family 0x0004 - Routines for sending/receiving Instant Messages.
3 * 3 *
4 * Note the term ICBM (Inter-Client Basic Message) which blankets 4 * Note the term ICBM (Inter-Client Basic Message) which blankets
5 * all types of genericly routed through-server messages. Within 5 * all types of genericly routed through-server messages. Within
6 * the ICBM types (family 4), a channel is defined. Each channel 6 * the ICBM types (family 4), a channel is defined. Each channel
7 * represents a different type of message. Channel 1 is used for 7 * represents a different type of message. Channel 1 is used for
8 * what would commonly be called an "instant message". Channel 2 8 * what would commonly be called an "instant message". Channel 2
9 * is used for negotiating "rendezvous". These transactions end in 9 * is used for negotiating "rendezvous". These transactions end in
10 * something more complex happening, such as a chat invitation, or 10 * something more complex happening, such as a chat invitation, or
11 * a file transfer. Channel 3 is used for chat messages (not in 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 12 * the same family as these channels). Channel 4 is used for
13 * various ICQ messages. Examples are normal messages, URLs, and 13 * various ICQ messages. Examples are normal messages, URLs, and
14 * old-style authorization. 14 * old-style authorization.
15 * 15 *
16 * In addition to the channel, every ICBM contains a cookie. For 16 * In addition to the channel, every ICBM contains a cookie. For
17 * standard IMs, these are only used for error messages. However, 17 * standard IMs, these are only used for error messages. However,
18 * the more complex rendezvous messages make suitably more complex 18 * the more complex rendezvous messages make suitably more complex
19 * use of this field. 19 * use of this field.
20 * 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
23 #define FAIM_INTERNAL 29 #define FAIM_INTERNAL
24 #include <aim.h> 30 #include <aim.h>
25 31
26 #ifdef _WIN32 32 #ifdef _WIN32
27 #include "win32dep.h" 33 #include "win32dep.h"
28 #endif 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 /*
31 * Takes a msghdr (and a length) and returns a client type 56 * Takes a msghdr (and a length) and returns a client type
32 * code. Note that this is *only a guess* and has a low likelihood 57 * code. Note that this is *only a guess* and has a low likelihood
33 * of actually being accurate. 58 * of actually being accurate.
49 * 74 *
50 * Note that in this function, only the feature bytes are tested, since 75 * Note that in this function, only the feature bytes are tested, since
51 * the rest will always be the same. 76 * the rest will always be the same.
52 * 77 *
53 */ 78 */
54 faim_export fu16_t aim_fingerprintclient(fu8_t *msghdr, int len) 79 faim_export fu16_t aim_im_fingerprint(fu8_t *msghdr, int len)
55 { 80 {
56 static const struct { 81 static const struct {
57 fu16_t clientid; 82 fu16_t clientid;
58 int len; 83 int len;
59 fu8_t data[10]; 84 fu8_t data[10];
89 } 114 }
90 115
91 return AIM_CLIENTTYPE_UNKNOWN; 116 return AIM_CLIENTTYPE_UNKNOWN;
92 } 117 }
93 118
94 /* 119 /**
95 * Subtype 0x0002 120 * Subtype 0x0002 - Set ICBM parameters.
96 * 121 *
97 * I definitly recommend sending this. If you don't, you'll be stuck 122 * I definitly recommend sending this. If you don't, you'll be stuck
98 * with the rather unreasonable defaults. You don't want those. Send this. 123 * with the rather unreasonable defaults.
99 * 124 *
100 */ 125 */
101 faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params) 126 faim_export int aim_im_setparams(aim_session_t *sess, struct aim_icbmparameters *params)
102 { 127 {
103 aim_conn_t *conn; 128 aim_conn_t *conn;
104 aim_frame_t *fr; 129 aim_frame_t *fr;
105 aim_snacid_t snacid; 130 aim_snacid_t snacid;
106 131
129 aim_tx_enqueue(sess, fr); 154 aim_tx_enqueue(sess, fr);
130 155
131 return 0; 156 return 0;
132 } 157 }
133 158
134 /* Subtype 0x0004 - Request ICBM parameter information. */ 159 /**
135 faim_export int aim_reqicbmparams(aim_session_t *sess) 160 * Subtype 0x0004 - Request ICBM parameter information.
161 *
162 */
163 faim_export int aim_im_reqparams(aim_session_t *sess)
136 { 164 {
137 aim_conn_t *conn; 165 aim_conn_t *conn;
138 166
139 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 167 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
140 return -EINVAL; 168 return -EINVAL;
141 169
142 return aim_genericreq_n(sess, conn, 0x0004, 0x0004); 170 return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
143 } 171 }
144 172
145 /* Subtype 0x0005 */ 173 /**
146 static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 174 * Subtype 0x0005 - Receive parameter information.
147 { 175 *
176 */
177 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)
178 {
179 aim_rxcallback_t userfunc;
148 struct aim_icbmparameters params; 180 struct aim_icbmparameters params;
149 aim_rxcallback_t userfunc;
150 181
151 params.maxchan = aimbs_get16(bs); 182 params.maxchan = aimbs_get16(bs);
152 params.flags = aimbs_get32(bs); 183 params.flags = aimbs_get32(bs);
153 params.maxmsglen = aimbs_get16(bs); 184 params.maxmsglen = aimbs_get16(bs);
154 params.maxsenderwarn = aimbs_get16(bs); 185 params.maxsenderwarn = aimbs_get16(bs);
159 return userfunc(sess, rx, &params); 190 return userfunc(sess, rx, &params);
160 191
161 return 0; 192 return 0;
162 } 193 }
163 194
164 /* This should be endian-safe now... but who knows... */ 195 /**
165 faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen)
166 {
167 fu32_t sum;
168 int i;
169
170 for (i = 0, sum = 0; i + 1 < buflen; i += 2)
171 sum += (buf[i+1] << 8) + buf[i];
172 if (i < buflen)
173 sum += buf[i];
174
175 sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
176
177 return (fu16_t)sum;
178 }
179
180 /*
181 * Subtype 0x0006 - Send an ICBM (instant message). 196 * Subtype 0x0006 - Send an ICBM (instant message).
182 * 197 *
183 * 198 *
184 * Possible flags: 199 * Possible flags:
185 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse 200 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse
218 * in all of libfaim, it is written with performance in mind. As such, 233 * in all of libfaim, it is written with performance in mind. As such,
219 * it is not as clear as it could be in respect to how this message is 234 * it is not as clear as it could be in respect to how this message is
220 * supposed to be layed out. Most obviously, tlvlists should be used 235 * supposed to be layed out. Most obviously, tlvlists should be used
221 * instead of writing out the bytes manually. 236 * instead of writing out the bytes manually.
222 * 237 *
223 * XXX more precise verification that we never send SNACs larger than 8192 238 * XXX - more precise verification that we never send SNACs larger than 8192
224 * XXX check SNAC size for multipart 239 * XXX - check SNAC size for multipart
225 * 240 *
226 */ 241 */
227 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args) 242 faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args)
228 { 243 {
229 static const fu8_t deffeatures[] = {
230 0x01, 0x01, 0x01, 0x02
231 };
232 aim_conn_t *conn; 244 aim_conn_t *conn;
233 int i, msgtlvlen;
234 aim_frame_t *fr; 245 aim_frame_t *fr;
235 aim_snacid_t snacid; 246 aim_snacid_t snacid;
247 fu8_t ck[8];
248 int i, msgtlvlen;
249 static const fu8_t deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };
236 250
237 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 251 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
238 return -EINVAL; 252 return -EINVAL;
239 253
240 if (!args) 254 if (!args)
273 } 287 }
274 288
275 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) 289 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128)))
276 return -ENOMEM; 290 return -ENOMEM;
277 291
278 /* XXX should be optional */ 292 /* XXX - should be optional */
279 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); 293 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
280 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 294 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
281 295
282 /* 296 /*
283 * Generate a random message cookie 297 * Generate a random message cookie
284 * 298 *
285 * We could cache these like we do SNAC IDs. (In fact, it 299 * We could cache these like we do SNAC IDs. (In fact, it
286 * might be a good idea.) In the message error functions, 300 * might be a good idea.) In the message error functions,
287 * the 8byte message cookie is returned as well as the 301 * the 8byte message cookie is returned as well as the
288 * SNAC ID. 302 * SNAC ID.
289 * 303 *
290 */ 304 */
291 for (i = 0; i < 8; i++) 305 for (i = 0; i < 8; i++)
292 aimbs_put8(&fr->data, (fu8_t) rand()); 306 ck[i] = (fu8_t)rand();
293 307
294 /* 308 /* ICBM header */
295 * Channel ID 309 aim_im_puticbm(&fr->data, ck, 0x0001, args->destsn);
296 */ 310
297 aimbs_put16(&fr->data, 0x0001); 311 /* Message TLV (type 0x0002) */
298
299 /*
300 * Destination SN (prepended with byte length)
301 */
302 aimbs_put8(&fr->data, strlen(args->destsn));
303 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn));
304
305 /*
306 * Message TLV (type 2).
307 */
308 aimbs_put16(&fr->data, 0x0002); 312 aimbs_put16(&fr->data, 0x0002);
309 aimbs_put16(&fr->data, msgtlvlen); 313 aimbs_put16(&fr->data, msgtlvlen);
310 314
311 /* 315 /* Features TLV (type 0x0501) */
312 * Features 316 aimbs_put16(&fr->data, 0x0501);
313 *
314 */
315 aimbs_put8(&fr->data, 0x05);
316 aimbs_put8(&fr->data, 0x01);
317
318 if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { 317 if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
319 aimbs_put16(&fr->data, args->featureslen); 318 aimbs_put16(&fr->data, args->featureslen);
320 aimbs_putraw(&fr->data, args->features, args->featureslen); 319 aimbs_putraw(&fr->data, args->features, args->featureslen);
321 } else { 320 } else {
322 aimbs_put16(&fr->data, sizeof(deffeatures)); 321 aimbs_put16(&fr->data, sizeof(deffeatures));
324 } 323 }
325 324
326 if (args->flags & AIM_IMFLAGS_MULTIPART) { 325 if (args->flags & AIM_IMFLAGS_MULTIPART) {
327 aim_mpmsg_section_t *sec; 326 aim_mpmsg_section_t *sec;
328 327
328 /* Insert each message part in a TLV (type 0x0101) */
329 for (sec = args->mpmsg->parts; sec; sec = sec->next) { 329 for (sec = args->mpmsg->parts; sec; sec = sec->next) {
330 aimbs_put16(&fr->data, 0x0101); 330 aimbs_put16(&fr->data, 0x0101);
331 aimbs_put16(&fr->data, sec->datalen + 4); 331 aimbs_put16(&fr->data, sec->datalen + 4);
332 aimbs_put16(&fr->data, sec->charset); 332 aimbs_put16(&fr->data, sec->charset);
333 aimbs_put16(&fr->data, sec->charsubset); 333 aimbs_put16(&fr->data, sec->charsubset);
334 aimbs_putraw(&fr->data, sec->data, sec->datalen); 334 aimbs_putraw(&fr->data, sec->data, sec->datalen);
335 } 335 }
336 336
337 } else { 337 } else {
338 338
339 /* Insert message text in a TLV (type 0x0101) */
339 aimbs_put16(&fr->data, 0x0101); 340 aimbs_put16(&fr->data, 0x0101);
340 341
341 /* 342 /* Message block length */
342 * Message block length.
343 */
344 aimbs_put16(&fr->data, args->msglen + 0x04); 343 aimbs_put16(&fr->data, args->msglen + 0x04);
345 344
346 /* 345 /* Character set */
347 * Character set.
348 */
349 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) { 346 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) {
350
351 aimbs_put16(&fr->data, args->charset); 347 aimbs_put16(&fr->data, args->charset);
352 aimbs_put16(&fr->data, args->charsubset); 348 aimbs_put16(&fr->data, args->charsubset);
353
354 } else { 349 } else {
355 if (args->flags & AIM_IMFLAGS_UNICODE) 350 if (args->flags & AIM_IMFLAGS_UNICODE)
356 aimbs_put16(&fr->data, 0x0002); 351 aimbs_put16(&fr->data, 0x0002);
357 else if (args->flags & AIM_IMFLAGS_ISO_8859_1) 352 else if (args->flags & AIM_IMFLAGS_ISO_8859_1)
358 aimbs_put16(&fr->data, 0x0003); 353 aimbs_put16(&fr->data, 0x0003);
360 aimbs_put16(&fr->data, 0x0000); 355 aimbs_put16(&fr->data, 0x0000);
361 356
362 aimbs_put16(&fr->data, 0x0000); 357 aimbs_put16(&fr->data, 0x0000);
363 } 358 }
364 359
365 /* 360 /* Message. Not terminated */
366 * Message. Not terminated.
367 */
368 aimbs_putraw(&fr->data, args->msg, args->msglen); 361 aimbs_putraw(&fr->data, args->msg, args->msglen);
369 } 362 }
370 363
371 /* 364 /* Set the Request Acknowledge flag */
372 * Set the Request Acknowledge flag.
373 */
374 if (args->flags & AIM_IMFLAGS_ACK) { 365 if (args->flags & AIM_IMFLAGS_ACK) {
375 aimbs_put16(&fr->data, 0x0003); 366 aimbs_put16(&fr->data, 0x0003);
376 aimbs_put16(&fr->data, 0x0000); 367 aimbs_put16(&fr->data, 0x0000);
377 } 368 }
378 369
379 /* 370 /* Set the Autoresponse flag */
380 * Set the Autoresponse flag.
381 */
382 if (args->flags & AIM_IMFLAGS_AWAY) { 371 if (args->flags & AIM_IMFLAGS_AWAY) {
383 aimbs_put16(&fr->data, 0x0004); 372 aimbs_put16(&fr->data, 0x0004);
384 aimbs_put16(&fr->data, 0x0000); 373 aimbs_put16(&fr->data, 0x0000);
385 } 374 }
386 375
412 aimbs_put16(&fr->data, 0x0000); 401 aimbs_put16(&fr->data, 0x0000);
413 } 402 }
414 403
415 aim_tx_enqueue(sess, fr); 404 aim_tx_enqueue(sess, fr);
416 405
406 /* Move this to receive aim_flap_nop and send aim_flap_nop */
417 if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) 407 if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM))
418 aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */ 408 aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */
419 409
420 return 0; 410 return 0;
421 } 411 }
422 412
423 /* 413 /*
424 * Simple wrapper for aim_send_im_ext() 414 * Simple wrapper for aim_im_sendch1_ext()
425 * 415 *
426 * You cannot use aim_send_im if you need the HASICON flag. You must 416 * You cannot use aim_send_im if you need the HASICON flag. You must
427 * use aim_send_im_ext directly for that. 417 * use aim_im_sendch1_ext directly for that.
428 * 418 *
429 * aim_send_im also cannot be used if you require UNICODE messages, because 419 * aim_send_im also cannot be used if you require UNICODE messages, because
430 * that requires an explicit message length. Use aim_send_im_ext(). 420 * that requires an explicit message length. Use aim_im_sendch1_ext().
431 * 421 *
432 */ 422 */
433 faim_export int aim_send_im(aim_session_t *sess, const char *destsn, fu16_t flags, const char *msg) 423 faim_export int aim_im_sendch1(aim_session_t *sess, const char *sn, fu16_t flags, const char *msg)
434 { 424 {
435 struct aim_sendimext_args args; 425 struct aim_sendimext_args args;
436 426
437 args.destsn = destsn; 427 args.destsn = sn;
438 args.flags = flags; 428 args.flags = flags;
439 args.msg = msg; 429 args.msg = msg;
440 args.msglen = strlen(msg); 430 args.msglen = strlen(msg);
441 431
442 /* Make these don't get set by accident -- they need aim_send_im_ext */ 432 /* Make these don't get set by accident -- they need aim_im_sendch1_ext */
443 args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART); 433 args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART);
444 434
445 return aim_send_im_ext(sess, &args); 435 return aim_im_sendch1_ext(sess, &args);
446 } 436 }
447 437
448 /* 438 /**
449 * Subtype 0x0006 439 * Subtype 0x0006 - Send your icon to a given user.
450 * 440 *
451 * This is also performance sensitive. (If you can believe it...) 441 * This is also performance sensitive. (If you can believe it...)
452 * 442 *
453 */ 443 */
454 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) 444 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)
455 { 445 {
456 aim_conn_t *conn; 446 aim_conn_t *conn;
457 int i;
458 fu8_t ck[8];
459 aim_frame_t *fr; 447 aim_frame_t *fr;
460 aim_snacid_t snacid; 448 aim_snacid_t snacid;
449 fu8_t ck[8];
450 int i;
461 451
462 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 452 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
463 return -EINVAL; 453 return -EINVAL;
464 454
465 if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) 455 if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
466 return -EINVAL; 456 return -EINVAL;
467 457
468 for (i = 0; i < 8; i++) 458 for (i = 0; i < 8; i++)
469 aimutil_put8(ck+i, (fu8_t) rand()); 459 ck[i] = (fu8_t)rand();
470 460
471 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))) 461 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)))
472 return -ENOMEM; 462 return -ENOMEM;
473 463
474 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 464 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
475 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 465 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
476 466
477 /* 467 /* ICBM header */
478 * Cookie 468 aim_im_puticbm(&fr->data, ck, 0x0002, sn);
479 */
480 aimbs_putraw(&fr->data, ck, 8);
481
482 /*
483 * Channel (2)
484 */
485 aimbs_put16(&fr->data, 0x0002);
486
487 /*
488 * Dest sn
489 */
490 aimbs_put8(&fr->data, strlen(sn));
491 aimbs_putraw(&fr->data, sn, strlen(sn));
492 469
493 /* 470 /*
494 * TLV t(0005) 471 * TLV t(0005)
495 * 472 *
496 * Encompasses everything below. 473 * Encompasses everything below.
529 506
530 return 0; 507 return 0;
531 } 508 }
532 509
533 /* 510 /*
534 * Subtype 0x0006 511 * Subtype 0x0006 - Send a rich text message.
535 * 512 *
536 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only 513 * This only works for ICQ 2001b (thats 2001 not 2000). Better, only
537 * send it to clients advertising the RTF capability. In fact, if you send 514 * send it to clients advertising the RTF capability. In fact, if you send
538 * it to a client that doesn't support that capability, the server will gladly 515 * it to a client that doesn't support that capability, the server will gladly
539 * bounce it back to you. 516 * bounce it back to you.
543 * be an exception, since Rendezvous IMs are external of the Oscar core, 520 * be an exception, since Rendezvous IMs are external of the Oscar core,
544 * and therefore are undefined. Really I just need to think of a good way to 521 * and therefore are undefined. Really I just need to think of a good way to
545 * make an interface similar to what AOL actually uses. But I'm not using COM. 522 * make an interface similar to what AOL actually uses. But I'm not using COM.
546 * 523 *
547 */ 524 */
548 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args) 525 faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args)
549 { 526 {
550 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */
551 aim_conn_t *conn; 527 aim_conn_t *conn;
552 int i;
553 fu8_t ck[8];
554 aim_frame_t *fr; 528 aim_frame_t *fr;
555 aim_snacid_t snacid; 529 aim_snacid_t snacid;
556 int servdatalen; 530 fu8_t ck[8];
531 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */
532 int i, servdatalen;
557 533
558 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 534 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
559 return -EINVAL; 535 return -EINVAL;
560 536
561 if (!args || !args->destsn || !args->rtfmsg) 537 if (!args || !args->destsn || !args->rtfmsg)
562 return -EINVAL; 538 return -EINVAL;
563 539
564 servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1; 540 servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1;
565 541
566 for (i = 0; i < 8; i++) 542 for (i = 0; i < 8; i++)
567 aimutil_put8(ck+i, (fu8_t) rand()); 543 ck[i] = (fu8_t)rand();
568 544
569 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen))) 545 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen)))
570 return -ENOMEM; 546 return -ENOMEM;
571 547
572 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 548 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
573 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 549 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
574 550
575 /* 551 /* ICBM header */
576 * Cookie 552 aim_im_puticbm(&fr->data, ck, 0x0002, args->destsn);
577 */ 553
578 aimbs_putraw(&fr->data, ck, 8); 554 /* TLV t(0005) - Encompasses everything below. */
579
580 /*
581 * Channel (2)
582 */
583 aimbs_put16(&fr->data, 0x0002);
584
585 /*
586 * Dest sn
587 */
588 aimbs_put8(&fr->data, strlen(args->destsn));
589 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn));
590
591 /*
592 * TLV t(0005)
593 *
594 * Encompasses everything below.
595 */
596 aimbs_put16(&fr->data, 0x0005); 555 aimbs_put16(&fr->data, 0x0005);
597 aimbs_put16(&fr->data, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen); 556 aimbs_put16(&fr->data, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen);
598 557
599 aimbs_put16(&fr->data, 0x0000); 558 aimbs_put16(&fr->data, 0x0000);
600 aimbs_putraw(&fr->data, ck, 8); 559 aimbs_putraw(&fr->data, ck, 8);
601 aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY); 560 aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY);
602 561
603 /* 562 /* t(000a) l(0002) v(0001) */
604 * t(000a) l(0002) v(0001)
605 */
606 aimbs_put16(&fr->data, 0x000a); 563 aimbs_put16(&fr->data, 0x000a);
607 aimbs_put16(&fr->data, 0x0002); 564 aimbs_put16(&fr->data, 0x0002);
608 aimbs_put16(&fr->data, 0x0001); 565 aimbs_put16(&fr->data, 0x0001);
609 566
610 /* 567 /* t(000f) l(0000) v() */
611 * t(000f) l(0000) v()
612 */
613 aimbs_put16(&fr->data, 0x000f); 568 aimbs_put16(&fr->data, 0x000f);
614 aimbs_put16(&fr->data, 0x0000); 569 aimbs_put16(&fr->data, 0x0000);
615 570
616 /* 571 /* Service Data TLV */
617 * Service Data TLV
618 */
619 aimbs_put16(&fr->data, 0x2711); 572 aimbs_put16(&fr->data, 0x2711);
620 aimbs_put16(&fr->data, servdatalen); 573 aimbs_put16(&fr->data, servdatalen);
621 574
622 aimbs_putle16(&fr->data, 11 + 16 /* 11 + (sizeof CLSID) */); 575 aimbs_putle16(&fr->data, 11 + 16 /* 11 + (sizeof CLSID) */);
623 aimbs_putle16(&fr->data, 9); 576 aimbs_putle16(&fr->data, 9);
646 aim_tx_enqueue(sess, fr); 599 aim_tx_enqueue(sess, fr);
647 600
648 return 0; 601 return 0;
649 } 602 }
650 603
651 /* Subtype 0x0006 */ 604 /**
652 faim_internal int aim_request_directim(aim_session_t *sess, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret) 605 * Subtype 0x0006 - Send an "I want to directly connect to you" message
606 *
607 */
608 faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port)
653 { 609 {
654 aim_conn_t *conn; 610 aim_conn_t *conn;
655 fu8_t ck[8];
656 aim_frame_t *fr; 611 aim_frame_t *fr;
657 aim_snacid_t snacid; 612 aim_snacid_t snacid;
613 fu8_t ck[8];
658 aim_tlvlist_t *tl = NULL, *itl = NULL; 614 aim_tlvlist_t *tl = NULL, *itl = NULL;
659 int hdrlen, i; 615 int hdrlen, i;
660 fu8_t *hdr; 616 fu8_t *hdr;
661 aim_bstream_t hdrbs; 617 aim_bstream_t hdrbs;
662 618
663 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 619 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
664 return -EINVAL; 620 return -EINVAL;
665 621
666 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(destsn)))) 622 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(sn))))
667 return -ENOMEM; 623 return -ENOMEM;
668 624
669 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 625 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
670 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 626 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
671 627
673 * Generate a random message cookie 629 * Generate a random message cookie
674 * 630 *
675 * This cookie needs to be alphanumeric and NULL-terminated to be 631 * This cookie needs to be alphanumeric and NULL-terminated to be
676 * TOC-compatible. 632 * TOC-compatible.
677 * 633 *
678 * XXX have I mentioned these should be generated in msgcookie.c? 634 * XXX - have I mentioned these should be generated in msgcookie.c?
679 * 635 *
680 */ 636 */
681 for (i = 0; i < 7; i++) 637 for (i = 0; i < 7; i++)
682 ck[i] = 0x30 + ((fu8_t) rand() % 10); 638 ck[i] = 0x30 + ((fu8_t) rand() % 10);
683 ck[7] = '\0'; 639 ck[7] = '\0';
684 640
685 if (ckret) 641 if (cookie)
686 memcpy(ckret, ck, 8); 642 memcpy(cookie, ck, 8);
687 643
688 /* Cookie */ 644 /* ICBM header */
689 aimbs_putraw(&fr->data, ck, 8); 645 aim_im_puticbm(&fr->data, ck, 0x0002, sn);
690
691 /* Channel */
692 aimbs_put16(&fr->data, 0x0002);
693
694 /* Destination SN */
695 aimbs_put8(&fr->data, strlen(destsn));
696 aimbs_putraw(&fr->data, destsn, strlen(destsn));
697 646
698 aim_addtlvtochain_noval(&tl, 0x0003); 647 aim_addtlvtochain_noval(&tl, 0x0003);
699 648
700 hdrlen = 2+8+16+6+8+6+4; 649 hdrlen = 2+8+16+6+8+6+4;
701 hdr = malloc(hdrlen); 650 hdr = malloc(hdrlen);
723 aim_tx_enqueue(sess, fr); 672 aim_tx_enqueue(sess, fr);
724 673
725 return 0; 674 return 0;
726 } 675 }
727 676
728 /* Subtype 0x0006 */ 677 /**
729 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) 678 * Subtype 0x0006 - Send an "I want to send you this file" message
679 *
680 */
681 faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port, const char *filename, fu16_t numfiles, fu32_t totsize)
730 { 682 {
731 aim_conn_t *conn; 683 aim_conn_t *conn;
732 int i;
733 fu8_t ck[8];
734 aim_frame_t *fr; 684 aim_frame_t *fr;
735 aim_snacid_t snacid; 685 aim_snacid_t snacid;
736 struct aim_snac_destructor snacdest; 686 aim_tlvlist_t *tl=NULL, *subtl=NULL;
687 fu8_t *ck;
688 int i;
737 689
738 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) 690 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
739 return -EINVAL; 691 return -EINVAL;
740 692
741 if (!sn || !filename) 693 if (!sn || !filename)
742 return -EINVAL; 694 return -EINVAL;
743 695
744 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))) 696 /* XXX - Should be like "21CBF95" and null terminated */
697 ck = (fu8_t *)malloc(8*sizeof(fu8_t));
698 for (i = 0; i < 7; i++)
699 ck[i] = 0x30 + ((fu8_t)rand() % 10);
700 ck[7] = '\0';
701 if (cookie)
702 memcpy(cookie, ck, 8);
703
704 { /* Create the subTLV chain */
705 fu8_t *buf;
706 int buflen;
707 aim_bstream_t bs;
708
709 aim_addtlvtochain16(&subtl, 0x000a, 0x0001);
710 aim_addtlvtochain_noval(&subtl, 0x000f);
711 /* aim_addtlvtochain_raw(&subtl, 0x000e, 2, "en");
712 aim_addtlvtochain_raw(&subtl, 0x000d, 8, "us-ascii");
713 aim_addtlvtochain_raw(&subtl, 0x000c, 24, "Please accept this file."); */
714 aim_addtlvtochain_raw(&subtl, 0x0003, 4, ip);
715 aim_addtlvtochain16(&subtl, 0x0005, port);
716
717 /* TLV t(2711) */
718 buflen = 2+2+4+63;
719 buf = malloc(buflen);
720 aim_bstream_init(&bs, buf, buflen);
721 aimbs_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001);
722 aimbs_put16(&bs, numfiles);
723 aimbs_put32(&bs, totsize);
724
725 /* Filename is a fixed size of 63 bytes, so pad with 0's */
726 aimbs_putraw(&bs, filename, strlen(filename));
727 for (i=0; i<(63-strlen(filename)); i++)
728 aimbs_put8(&bs, 0x00);
729
730 aim_addtlvtochain_raw(&subtl, 0x2711, bs.len, bs.data);
731 free(buf);
732 }
733
734 { /* Create the main TLV chain */
735 fu8_t *buf;
736 int buflen;
737 aim_bstream_t bs;
738
739 /* TLV t(0005) - Encompasses everything from above. Gee. */
740 buflen = 2+8+16+aim_sizetlvchain(&subtl);
741 buf = malloc(buflen);
742 aim_bstream_init(&bs, buf, buflen);
743 aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE);
744 aimbs_putraw(&bs, ck, 8);
745 aim_putcap(&bs, AIM_CAPS_SENDFILE);
746 aim_writetlvchain(&bs, &subtl);
747 aim_freetlvchain(&subtl);
748 aim_addtlvtochain_raw(&tl, 0x0005, bs.len, bs.data);
749 free(buf);
750
751 /* TLV t(0003) - Request an ack */
752 aim_addtlvtochain_noval(&tl, 0x0003);
753 }
754
755 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + aim_sizetlvchain(&tl))))
745 return -ENOMEM; 756 return -ENOMEM;
746 757
747 for (i = 0; i < 7; i++) 758 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, ck, sizeof(ck));
748 aimutil_put8(ck+i, 0x30 + ((fu8_t) rand() % 10));
749 ck[7] = '\0';
750
751 if (ckret)
752 memcpy(ckret, ck, 8);
753
754 /* Fill in the snac destructor so we know if the request
755 * times out. Use the cookie in the data field, so we
756 * know what request to cancel if there is an error.
757 */
758 snacdest.data = malloc(8);
759 memcpy(snacdest.data, ck, 8);
760 snacdest.conn = conn;
761 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, &snacdest, sizeof(snacdest));
762 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 759 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
763 760
764 /* 761 /* ICBM header */
765 * Cookie 762 aim_im_puticbm(&fr->data, ck, 0x0002, sn);
766 */ 763
767 aimbs_putraw(&fr->data, ck, 8); 764 /* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */
768 765 aim_writetlvchain(&fr->data, &tl);
769 /* 766 aim_freetlvchain(&tl);
770 * Channel (2) 767
771 */ 768 aim_tx_enqueue(sess, fr);
772 aimbs_put16(&fr->data, 0x0002); 769
773 770 return 0;
774 /* 771 }
775 * Dest sn 772
776 */ 773 /**
777 aimbs_put8(&fr->data, strlen(sn)); 774 * Subtype 0x0006 - Send an "I will accept this file" message?
778 aimbs_putraw(&fr->data, sn, strlen(sn)); 775 *
779 776 * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE)
780 /* 777 */
781 * TLV t(0005) 778 faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid)
782 * 779 {
783 * Encompasses everything below. Gee. 780 aim_conn_t *conn;
784 */ 781 aim_frame_t *fr;
782 aim_snacid_t snacid;
783
784 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn)
785 return -EINVAL;
786
787 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16)))
788 return -ENOMEM;
789
790 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
791 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
792
793 /* ICBM header */
794 aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
795
785 aimbs_put16(&fr->data, 0x0005); 796 aimbs_put16(&fr->data, 0x0005);
786 aimbs_put16(&fr->data, 2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4); 797 aimbs_put16(&fr->data, 0x001a);
787 798 aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT);
788 aimbs_put16(&fr->data, 0x0000); 799 aimbs_putraw(&fr->data, cookie, 8);
789 aimbs_putraw(&fr->data, ck, 8); 800 aim_putcap(&fr->data, rendid);
790 aim_putcap(&fr->data, AIM_CAPS_SENDFILE); 801
791 802 aim_tx_enqueue(sess, fr);
792 /* TLV t(000a) */ 803
793 aimbs_put16(&fr->data, 0x000a); 804 return 0;
794 aimbs_put16(&fr->data, 0x0002); 805 }
795 aimbs_put16(&fr->data, 0x0001); 806
796 807 /**
797 /* TLV t(0003) (IP) */ 808 * Subtype 0x0006 - Send a "cancel this file transfer" message?
798 aimbs_put16(&fr->data, 0x0003); 809 *
799 aimbs_put16(&fr->data, 0x0004); 810 */
800 aimbs_putraw(&fr->data, ip, 4); 811 faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid)
801 812 {
802 /* TLV t(0005) (port) */ 813 aim_conn_t *conn;
814 aim_frame_t *fr;
815 aim_snacid_t snacid;
816
817 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn)
818 return -EINVAL;
819
820 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16)))
821 return -ENOMEM;
822
823 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
824 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
825
826 /* ICBM header */
827 aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
828
803 aimbs_put16(&fr->data, 0x0005); 829 aimbs_put16(&fr->data, 0x0005);
804 aimbs_put16(&fr->data, 0x0002); 830 aimbs_put16(&fr->data, 0x001a);
805 aimbs_put16(&fr->data, port); 831 aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL);
806 832 aimbs_putraw(&fr->data, cookie, 8);
807 /* TLV t(000f) */ 833 aim_putcap(&fr->data, rendid);
808 aimbs_put16(&fr->data, 0x000f);
809 aimbs_put16(&fr->data, 0x0000);
810
811 /* TLV t(2711) */
812 aimbs_put16(&fr->data, 0x2711);
813 aimbs_put16(&fr->data, 2+2+4+strlen(filename)+4);
814
815 /* ? */
816 aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001);
817 aimbs_put16(&fr->data, numfiles);
818 aimbs_put32(&fr->data, totsize);
819 aimbs_putraw(&fr->data, filename, strlen(filename));
820
821 /* ? */
822 aimbs_put32(&fr->data, 0x00000000);
823
824 #if 0
825 /* Newer clients seem to send this (?) -- wtm */
826 aimbs_put32(&fr->data, 0x00030000);
827 #endif
828 834
829 aim_tx_enqueue(sess, fr); 835 aim_tx_enqueue(sess, fr);
830 836
831 return 0; 837 return 0;
832 } 838 }
838 * @param sn The UIN of the user of whom you wish to request info. 844 * @param sn The UIN of the user of whom you wish to request info.
839 * @param type The type of info you wish to request. This should be the current 845 * @param type The type of info you wish to request. This should be the current
840 * state of the user, as one of the AIM_ICQ_STATE_* defines. 846 * state of the user, as one of the AIM_ICQ_STATE_* defines.
841 * @return Return 0 if no errors, otherwise return the error number. 847 * @return Return 0 if no errors, otherwise return the error number.
842 */ 848 */
843 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type) 849 faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type)
844 { 850 {
845 aim_conn_t *conn; 851 aim_conn_t *conn;
852 aim_frame_t *fr;
853 aim_snacid_t snacid;
846 int i; 854 int i;
847 fu8_t ck[8]; 855 fu8_t ck[8];
848 aim_frame_t *fr;
849 aim_snacid_t snacid;
850 856
851 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn) 857 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn)
852 return -EINVAL; 858 return -EINVAL;
853 859
854 for (i = 0; i < 8; i++) 860 for (i = 0; i < 8; i++)
855 aimutil_put8(ck+i, (fu8_t) rand()); 861 ck[i] = (fu8_t)rand();
856 862
857 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4))) 863 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4)))
858 return -ENOMEM; 864 return -ENOMEM;
859 865
860 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 866 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
861 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 867 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
862 868
863 /* Cookie */ 869 /* ICBM header */
864 aimbs_putraw(&fr->data, ck, 8); 870 aim_im_puticbm(&fr->data, ck, 0x0002, sn);
865
866 /* Channel (2) */
867 aimbs_put16(&fr->data, 0x0002);
868
869 /* Dest sn */
870 aimbs_put8(&fr->data, strlen(sn));
871 aimbs_putraw(&fr->data, sn, strlen(sn));
872 871
873 /* TLV t(0005) - Encompasses almost everything below. */ 872 /* TLV t(0005) - Encompasses almost everything below. */
874 aimbs_put16(&fr->data, 0x0005); /* T */ 873 aimbs_put16(&fr->data, 0x0005); /* T */
875 aimbs_put16(&fr->data, 0x005e); /* L */ 874 aimbs_put16(&fr->data, 0x005e); /* L */
876 { /* V */ 875 { /* V */
937 936
938 return 0; 937 return 0;
939 } 938 }
940 939
941 /** 940 /**
942 * Subtype 0x0006 941 * Subtype 0x0006 - Send an ICQ-esque ICBM.
943 * 942 *
944 * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way." 943 * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way."
945 * The new way is to use SSI. I like the new way a lot better. This seems like such a hack, 944 * The new way is to use SSI. I like the new way a lot better. This seems like such a hack,
946 * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while, 945 * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while,
947 * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people 946 * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people
950 * @param sn The destination screen name. 949 * @param sn The destination screen name.
951 * @param type The type of message. 0x0007 for authorization denied. 0x0008 for authorization granted. 950 * @param type The type of message. 0x0007 for authorization denied. 0x0008 for authorization granted.
952 * @param message The message you want to send, it should be null terminated. 951 * @param message The message you want to send, it should be null terminated.
953 * @return Return 0 if no errors, otherwise return the error number. 952 * @return Return 0 if no errors, otherwise return the error number.
954 */ 953 */
955 faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message) 954 faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)
956 { 955 {
957 aim_conn_t *conn; 956 aim_conn_t *conn;
958 aim_frame_t *fr; 957 aim_frame_t *fr;
959 aim_snacid_t snacid; 958 aim_snacid_t snacid;
960 int i; 959 int i;
960 char ck[8];
961 961
962 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002))) 962 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
963 return -EINVAL; 963 return -EINVAL;
964 964
965 if (!sn || !type || !message) 965 if (!sn || !type || !message)
969 return -ENOMEM; 969 return -ENOMEM;
970 970
971 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); 971 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
972 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); 972 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
973 973
974 /* 974 /* Cookie */
975 * Cookie
976 */
977 for (i=0; i<8; i++) 975 for (i=0; i<8; i++)
978 aimbs_put8(&fr->data, (fu8_t)rand()); 976 ck[i] = (fu8_t)rand();
979 977
980 /* 978 /* ICBM header */
981 * Channel (4) 979 aim_im_puticbm(&fr->data, ck, 0x0004, sn);
982 */
983 aimbs_put16(&fr->data, 0x0004);
984
985 /*
986 * Dest sn
987 */
988 aimbs_put8(&fr->data, strlen(sn));
989 aimbs_putraw(&fr->data, sn, strlen(sn));
990 980
991 /* 981 /*
992 * TLV t(0005) 982 * TLV t(0005)
993 * 983 *
994 * ICQ data (the UIN and the message). 984 * ICQ data (the UIN and the message).
1017 aim_tx_enqueue(sess, fr); 1007 aim_tx_enqueue(sess, fr);
1018 1008
1019 return 0; 1009 return 0;
1020 } 1010 }
1021 1011
1012 /*
1013 * XXX - I don't see when this would ever get called...
1014 */
1022 static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1015 static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
1023 { 1016 {
1024 int i, ret = 0; 1017 int i, ret = 0;
1025 aim_rxcallback_t userfunc; 1018 aim_rxcallback_t userfunc;
1026 fu8_t cookie[8]; 1019 fu8_t cookie[8];
1172 } 1165 }
1173 1166
1174 return 0; 1167 return 0;
1175 } 1168 }
1176 1169
1177 /* XXX should provide a way of saying ISO-8859-1 specifically */ 1170 /* XXX - should provide a way of saying ISO-8859-1 specifically */
1178 faim_export int aim_mpmsg_addascii(aim_session_t *sess, aim_mpmsg_t *mpm, const char *ascii) 1171 faim_export int aim_mpmsg_addascii(aim_session_t *sess, aim_mpmsg_t *mpm, const char *ascii)
1179 { 1172 {
1180 fu8_t *dup; 1173 fu8_t *dup;
1181 1174
1182 if (!(dup = strdup(ascii))) 1175 if (!(dup = strdup(ascii)))
1275 * always pad the ending with a NULL. This makes it easier 1268 * always pad the ending with a NULL. This makes it easier
1276 * to treat ASCII sections as strings. It won't matter for 1269 * to treat ASCII sections as strings. It won't matter for
1277 * UNICODE or binary data, as you should never read past 1270 * UNICODE or binary data, as you should never read past
1278 * the specified data length, which will not include the pad. 1271 * the specified data length, which will not include the pad.
1279 * 1272 *
1280 * XXX There's an API bug here. For sending, the UNICODE is 1273 * XXX - There's an API bug here. For sending, the UNICODE is
1281 * given in host byte order (aim_mpmsg_addunicode), but here 1274 * given in host byte order (aim_mpmsg_addunicode), but here
1282 * the received messages are given in network byte order. 1275 * the received messages are given in network byte order.
1283 * 1276 *
1284 */ 1277 */
1285 msgbuf = aimbs_getstr(&mbs, msglen); 1278 msgbuf = aimbs_getstr(&mbs, msglen);
1326 ; /* standard subencoding? */ 1319 ; /* standard subencoding? */
1327 else if (args->charsubset == 0x000b) 1320 else if (args->charsubset == 0x000b)
1328 args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; 1321 args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH;
1329 else if (args->charsubset == 0xffff) 1322 else if (args->charsubset == 0xffff)
1330 ; /* no subencoding */ 1323 ; /* no subencoding */
1331 #if 0
1332 /* XXX this isn't really necesary... */
1333 if ( ((args.flag1 != 0x0000) &&
1334 (args.flag1 != 0x0002) &&
1335 (args.flag1 != 0x0003) &&
1336 (args.flag1 != 0xffff)) ||
1337 ((args.flag2 != 0x0000) &&
1338 (args.flag2 != 0x000b) &&
1339 (args.flag2 != 0xffff))) {
1340 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2);
1341 }
1342 #endif
1343 1324
1344 args->msg = sec->data; 1325 args->msg = sec->data;
1345 args->msglen = sec->datalen; 1326 args->msglen = sec->datalen;
1346 1327
1347 return 0; 1328 return 0;
1414 1395
1415 args.icbmflags |= AIM_IMFLAGS_AWAY; 1396 args.icbmflags |= AIM_IMFLAGS_AWAY;
1416 1397
1417 } else if (type == 0x0006) { /* Message was received offline. */ 1398 } else if (type == 0x0006) { /* Message was received offline. */
1418 1399
1419 /* XXX not sure if this actually gets sent. */ 1400 /* XXX - not sure if this actually gets sent. */
1420 args.icbmflags |= AIM_IMFLAGS_OFFLINE; 1401 args.icbmflags |= AIM_IMFLAGS_OFFLINE;
1421 1402
1422 } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ 1403 } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
1423 1404
1424 args.iconlen = aimbs_get32(bs); 1405 args.iconlen = aimbs_get32(bs);
1550 } 1531 }
1551 1532
1552 static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args) 1533 static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
1553 { 1534 {
1554 1535
1555 /* XXX aim_chat_roominfo_free() */ 1536 /* XXX - aim_chat_roominfo_free() */
1556 free(args->info.chat.roominfo.name); 1537 free(args->info.chat.roominfo.name);
1557 1538
1558 return; 1539 return;
1559 } 1540 }
1560 1541
1611 args->info.rtfmsg.bgcolor = aimbs_getle32(servdata); 1592 args->info.rtfmsg.bgcolor = aimbs_getle32(servdata);
1612 1593
1613 hdrlen = aimbs_getle32(servdata); 1594 hdrlen = aimbs_getle32(servdata);
1614 aim_bstream_advance(servdata, hdrlen); 1595 aim_bstream_advance(servdata, hdrlen);
1615 1596
1616 /* XXX This is such a hack. */ 1597 /* XXX - This is such a hack. */
1617 args->reqclass = AIM_CAPS_ICQRTF; 1598 args->reqclass = AIM_CAPS_ICQRTF;
1618 1599
1619 args->destructor = (void *)incomingim_ch2_icqserverrelay_free; 1600 args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
1620 1601
1621 return; 1602 return;
1629 static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata) 1610 static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata)
1630 { 1611 {
1631 1612
1632 args->destructor = (void *)incomingim_ch2_sendfile_free; 1613 args->destructor = (void *)incomingim_ch2_sendfile_free;
1633 1614
1634 if (servdata) { 1615 /* Maybe there is a better way to tell what kind of sendfile
1616 * this is? Maybe TLV t(000a)? */
1617 if (servdata) { /* Someone is sending us a file */
1635 int flen; 1618 int flen;
1636 1619
1637 /* subtype is one of AIM_OFT_SUBTYPE_* */ 1620 /* subtype is one of AIM_OFT_SUBTYPE_* */
1638 args->info.sendfile.subtype = aimbs_get16(servdata); 1621 args->info.sendfile.subtype = aimbs_get16(servdata);
1639 args->info.sendfile.totfiles = aimbs_get16(servdata); 1622 args->info.sendfile.totfiles = aimbs_get16(servdata);
1640 args->info.sendfile.totsize = aimbs_get32(servdata); 1623 args->info.sendfile.totsize = aimbs_get32(servdata);
1641 1624
1642 /* XXX - create an aimbs_getnullstr function */ 1625 /*
1626 * I hope to God I'm right when I guess that there is a
1627 * 32 char max filename length for single files. I think
1628 * OFT tends to do that. Gotta love inconsistency. I saw
1629 * a 26 byte filename?
1630 */
1631 /* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */
1643 /* Use an inelegant way of getting the null-terminated filename, 1632 /* Use an inelegant way of getting the null-terminated filename,
1644 * since there's no easy bstream routine. */ 1633 * since there's no easy bstream routine. */
1645 for (flen = 0; aimbs_get8(servdata); flen++); 1634 for (flen = 0; aimbs_get8(servdata); flen++);
1646 aim_bstream_advance(servdata, -flen -1); 1635 aim_bstream_advance(servdata, -flen -1);
1647 args->info.sendfile.filename = aimbs_getstr(servdata, flen); 1636 args->info.sendfile.filename = aimbs_getstr(servdata, flen);
1648 1637
1649 /* There is sometimes more after the null-terminated filename, 1638 /* There is sometimes more after the null-terminated filename,
1650 * but I'm unsure of its format. */ 1639 * but I'm unsure of its format. */
1640 /* I don't believe him. */
1651 } 1641 }
1652 1642
1653 return; 1643 return;
1654 } 1644 }
1655 1645
1707 */ 1697 */
1708 list2 = aim_readtlvchain(&bbs); 1698 list2 = aim_readtlvchain(&bbs);
1709 1699
1710 /* 1700 /*
1711 * IP address from the perspective of the client. 1701 * IP address from the perspective of the client.
1702 *
1703 * XXX - I don't like this. Maybe just read in an int? Or inet_ntoa...
1712 */ 1704 */
1713 if (aim_gettlv(list2, 0x0002, 1)) { 1705 if (aim_gettlv(list2, 0x0002, 1)) {
1714 aim_tlv_t *iptlv; 1706 aim_tlv_t *iptlv;
1715 1707
1716 iptlv = aim_gettlv(list2, 0x0002, 1); 1708 iptlv = aim_gettlv(list2, 0x0002, 1);
1759 */ 1751 */
1760 if (aim_gettlv(list2, 0x0005, 1)) 1752 if (aim_gettlv(list2, 0x0005, 1))
1761 args.port = aim_gettlv16(list2, 0x0005, 1); 1753 args.port = aim_gettlv16(list2, 0x0005, 1);
1762 1754
1763 /* 1755 /*
1756 * Something to do with ft -- two bytes
1757 * 0x0001 - "I want to send you this file"
1758 * 0x0002 - "I will accept this file from you"
1759 */
1760 if (aim_gettlv(list2, 0x000a, 1))
1761 ;
1762
1763 /*
1764 * Error code. 1764 * Error code.
1765 */ 1765 */
1766 if (aim_gettlv(list2, 0x000b, 1)) 1766 if (aim_gettlv(list2, 0x000b, 1))
1767 args.errorcode = aim_gettlv16(list2, 0x000b, 1); 1767 args.errorcode = aim_gettlv16(list2, 0x000b, 1);
1768 1768
1781 /* 1781 /*
1782 * Language. 1782 * Language.
1783 */ 1783 */
1784 if (aim_gettlv(list2, 0x000e, 1)) 1784 if (aim_gettlv(list2, 0x000e, 1))
1785 args.language = aim_gettlv_str(list2, 0x000e, 1); 1785 args.language = aim_gettlv_str(list2, 0x000e, 1);
1786
1787 /* Unknown -- two bytes = 0x0001 */
1788 if (aim_gettlv(list2, 0x000a, 1))
1789 ;
1790 1786
1791 /* Unknown -- no value */ 1787 /* Unknown -- no value */
1792 if (aim_gettlv(list2, 0x000f, 1)) 1788 if (aim_gettlv(list2, 0x000f, 1))
1793 ; 1789 ;
1794 1790
1798 args.clientip2 = (char *)clientip2; 1794 args.clientip2 = (char *)clientip2;
1799 if (strlen(verifiedip)) 1795 if (strlen(verifiedip))
1800 args.verifiedip = (char *)verifiedip; 1796 args.verifiedip = (char *)verifiedip;
1801 1797
1802 /* 1798 /*
1803 * This is must be present in PROPOSALs, but will probably not 1799 * This must be present in PROPOSALs, but will probably not
1804 * exist in CANCELs and ACCEPTs. 1800 * exist in CANCELs and ACCEPTs.
1805 * 1801 *
1806 * Service Data blocks are module-specific in format. 1802 * Service Data blocks are module-specific in format.
1807 */ 1803 */
1808 if ((servdatatlv = aim_gettlv(list2, 0x2711 /* 10001 */, 1))) { 1804 if ((servdatatlv = aim_gettlv(list2, 0x2711 /* 10001 */, 1))) {
1902 cookie[i] = aimbs_get8(bs); 1898 cookie[i] = aimbs_get8(bs);
1903 1899
1904 /* 1900 /*
1905 * Channel ID. 1901 * Channel ID.
1906 * 1902 *
1907 * Channel 0x0001 is the message channel. There are 1903 * Channel 0x0001 is the message channel. It is
1908 * other channels for things called "rendevous" 1904 * used to send basic ICBMs.
1909 * which represent chat and some of the other new
1910 * features of AIM2/3/3.5.
1911 * 1905 *
1912 * Channel 0x0002 is the Rendevous channel, which 1906 * Channel 0x0002 is the Rendevous channel, which
1913 * is where Chat Invitiations and various client-client 1907 * is where Chat Invitiations and various client-client
1914 * connection negotiations come from. 1908 * connection negotiations come from.
1909 *
1910 * Channel 0x0003 is used for chat messages.
1915 * 1911 *
1916 * Channel 0x0004 is used for ICQ authorization, or 1912 * Channel 0x0004 is used for ICQ authorization, or
1917 * possibly any system notice. 1913 * possibly any system notice.
1918 * 1914 *
1919 */ 1915 */
1977 1973
1978 return ret; 1974 return ret;
1979 } 1975 }
1980 1976
1981 /* 1977 /*
1982 * Subtype 0x0008 - Send a warning to destsn. 1978 * Subtype 0x0008 - Send a warning to sn.
1983 * 1979 *
1984 * Flags: 1980 * Flags:
1985 * AIM_WARN_ANON Send as an anonymous (doesn't count as much) 1981 * AIM_WARN_ANON Send as an anonymous (doesn't count as much)
1986 * 1982 *
1987 * returns -1 on error (couldn't alloc packet), 0 on success. 1983 * returns -1 on error (couldn't alloc packet), 0 on success.
1988 * 1984 *
1989 */ 1985 */
1990 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags) 1986 faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu32_t flags)
1991 { 1987 {
1992 aim_frame_t *fr; 1988 aim_frame_t *fr;
1993 aim_snacid_t snacid; 1989 aim_snacid_t snacid;
1994 fu16_t outflags = 0x0000; 1990
1995 1991 if (!sess || !conn || !sn)
1996 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13))) 1992 return -EINVAL;
1993
1994 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13)))
1997 return -ENOMEM; 1995 return -ENOMEM;
1998 1996
1999 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); 1997 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
2000
2001 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); 1998 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
2002 1999
2003 if (flags & AIM_WARN_ANON) 2000 aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
2004 outflags |= 0x0001; 2001 aimbs_put8(&fr->data, strlen(sn));
2005 2002 aimbs_putraw(&fr->data, sn, strlen(sn));
2006 aimbs_put16(&fr->data, outflags);
2007 aimbs_put8(&fr->data, strlen(destsn));
2008 aimbs_putraw(&fr->data, destsn, strlen(destsn));
2009 2003
2010 aim_tx_enqueue(sess, fr); 2004 aim_tx_enqueue(sess, fr);
2011 2005
2012 return 0; 2006 return 0;
2013 } 2007 }
2041 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" 2035 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
2042 * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer" 2036 * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
2043 * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" 2037 * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
2044 * 2038 *
2045 */ 2039 */
2046 faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code) 2040 faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, fu16_t code)
2047 { 2041 {
2048 aim_conn_t *conn; 2042 aim_conn_t *conn;
2049 aim_frame_t *fr; 2043 aim_frame_t *fr;
2050 aim_snacid_t snacid; 2044 aim_snacid_t snacid;
2051 aim_tlvlist_t *tl = NULL; 2045 aim_tlvlist_t *tl = NULL;
2093 snlen = aimbs_get8(bs); 2087 snlen = aimbs_get8(bs);
2094 sn = aimbs_getstr(bs, snlen); 2088 sn = aimbs_getstr(bs, snlen);
2095 reason = aimbs_get16(bs); 2089 reason = aimbs_get16(bs);
2096 2090
2097 if (channel == 0x0002) { /* File transfer declined */ 2091 if (channel == 0x0002) { /* File transfer declined */
2092 aimbs_get16(bs); /* Unknown */
2093 aimbs_get16(bs); /* Unknown */
2098 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2094 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2099 ret = userfunc(sess, rx, channel, sn, reason, ck); 2095 ret = userfunc(sess, rx, channel, sn, reason, ck);
2100 } else if (channel == 0x0004) { /* ICQ message */ 2096 } else if (channel == 0x0004) { /* ICQ message */
2101 switch (reason) { 2097 switch (reason) {
2102 case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */ 2098 case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */
2156 free(sn); 2152 free(sn);
2157 2153
2158 return ret; 2154 return ret;
2159 } 2155 }
2160 2156
2161 /* Subtype 0x000c */ 2157 /*
2158 * Subtype 0x000c - Receive an ack after sending an ICBM.
2159 *
2160 * You have to have send the message with the AIM_IMFLAGS_ACK flag set
2161 * (TLV t(0003)). The ack contains the ICBM header of the message you
2162 * sent.
2163 *
2164 */
2162 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2165 static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2163 { 2166 {
2164 aim_rxcallback_t userfunc; 2167 aim_rxcallback_t userfunc;
2165 fu16_t type; 2168 fu16_t ch;
2166 fu8_t snlen, *ck; 2169 fu8_t *ck;
2167 char *sn; 2170 char *sn;
2168 int ret = 0; 2171 int ret = 0;
2169 2172
2170 ck = aimbs_getraw(bs, 8); 2173 ck = aimbs_getraw(bs, 8);
2171 type = aimbs_get16(bs); 2174 ch = aimbs_get16(bs);
2172 snlen = aimbs_get8(bs); 2175 sn = aimbs_getstr(bs, aimbs_get8(bs));
2173 sn = aimbs_getstr(bs, snlen);
2174 2176
2175 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 2177 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
2176 ret = userfunc(sess, rx, type, sn); 2178 ret = userfunc(sess, rx, ch, sn);
2177 2179
2178 free(sn); 2180 free(sn);
2179 free(ck); 2181 free(ck);
2180 2182
2181 return ret; 2183 return ret;
2186 * 2188 *
2187 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 2189 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
2188 * and Gaim 0.60 and newer. 2190 * and Gaim 0.60 and newer.
2189 * 2191 *
2190 */ 2192 */
2191 faim_export int aim_mtn_send(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2) 2193 faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, char *sn, fu16_t type2)
2192 { 2194 {
2193 aim_conn_t *conn; 2195 aim_conn_t *conn;
2194 aim_frame_t *fr; 2196 aim_frame_t *fr;
2195 aim_snacid_t snacid; 2197 aim_snacid_t snacid;
2196 2198
2267 2269
2268 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 2270 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
2269 { 2271 {
2270 2272
2271 if (snac->subtype == 0x0005) 2273 if (snac->subtype == 0x0005)
2272 return paraminfo(sess, mod, rx, snac, bs); 2274 return aim_im_paraminfo(sess, mod, rx, snac, bs);
2273 else if (snac->subtype == 0x0006) 2275 else if (snac->subtype == 0x0006)
2274 return outgoingim(sess, mod, rx, snac, bs); 2276 return outgoingim(sess, mod, rx, snac, bs);
2275 else if (snac->subtype == 0x0007) 2277 else if (snac->subtype == 0x0007)
2276 return incomingim(sess, mod, rx, snac, bs); 2278 return incomingim(sess, mod, rx, snac, bs);
2277 else if (snac->subtype == 0x000a) 2279 else if (snac->subtype == 0x000a)
2284 return mtn_receive(sess, mod, rx, snac, bs); 2286 return mtn_receive(sess, mod, rx, snac, bs);
2285 2287
2286 return 0; 2288 return 0;
2287 } 2289 }
2288 2290
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 faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod) 2291 faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod)
2303 { 2292 {
2304 2293
2305 mod->family = 0x0004; 2294 mod->family = 0x0004;
2306 mod->version = 0x0001; 2295 mod->version = 0x0001;
2307 mod->toolid = 0x0110; 2296 mod->toolid = 0x0110;
2308 mod->toolversion = 0x0629; 2297 mod->toolversion = 0x0629;
2309 mod->flags = 0; 2298 mod->flags = 0;
2310 strncpy(mod->name, "messaging", sizeof(mod->name)); 2299 strncpy(mod->name, "messaging", sizeof(mod->name));
2311 mod->snachandler = snachandler; 2300 mod->snachandler = snachandler;
2312 mod->snacdestructor = snacdestructor;
2313 2301
2314 return 0; 2302 return 0;
2315 } 2303 }

mercurial