comparison libfaim/im.c @ 1899:a2624692260b

[gaim-migrate @ 1909] this is part two of three committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 28 May 2001 03:53:23 +0000
parents 109cacf1ff97
children
comparison
equal deleted inserted replaced
1898:73d73939f698 1899:a2624692260b
63 } 63 }
64 64
65 return AIM_CLIENTTYPE_UNKNOWN; 65 return AIM_CLIENTTYPE_UNKNOWN;
66 } 66 }
67 67
68 /* This should be endian-safe now... but who knows... */
69 faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen)
70 {
71 unsigned long sum;
72 int i;
73
74 for (i = 0, sum = 0; i < buflen; i += 2)
75 sum += (buf[i+1] << 8) + buf[i];
76
77 sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
78
79 return sum & 0xffff;
80 }
81
68 /* 82 /*
69 * Send an ICBM (instant message). 83 * Send an ICBM (instant message).
70 * 84 *
71 * 85 *
72 * Possible flags: 86 * Possible flags:
73 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse 87 * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse
74 * AIM_IMFLAGS_ACK -- Requests that the server send an ack 88 * AIM_IMFLAGS_ACK -- Requests that the server send an ack
75 * when the message is received (of type 0x0004/0x000c) 89 * when the message is received (of type 0x0004/0x000c)
90 * AIM_IMFLAGS_UNICODE--Instead of ASCII7, the passed message is
91 * made up of UNICODE duples. If you set
92 * this, you'd better be damn sure you know
93 * what you're doing.
94 * AIM_IMFLAGS_ISO_8859_1 -- The message contains the ASCII8 subset
95 * known as ISO-8859-1.
96 *
97 * Generally, you should use the lowest encoding possible to send
98 * your message. If you only use basic punctuation and the generic
99 * Latin alphabet, use ASCII7 (no flags). If you happen to use non-ASCII7
100 * characters, but they are all clearly defined in ISO-8859-1, then
101 * use that. Keep in mind that not all characters in the PC ASCII8
102 * character set are defined in the ISO standard. For those cases (most
103 * notably when the (r) symbol is used), you must use the full UNICODE
104 * encoding for your message. In UNICODE mode, _all_ characters must
105 * occupy 16bits, including ones that are not special. (Remember that
106 * the first 128 UNICODE symbols are equivelent to ASCII7, however they
107 * must be prefixed with a zero high order byte.)
108 *
109 * I strongly discourage the use of UNICODE mode, mainly because none
110 * of the clients I use can parse those messages (and besides that,
111 * wchars are difficult and non-portable to handle in most UNIX environments).
112 * If you really need to include special characters, use the HTML UNICODE
113 * entities. These are of the form &#2026; where 2026 is the hex
114 * representation of the UNICODE index (in this case, UNICODE
115 * "Horizontal Ellipsis", or 133 in in ASCII8).
76 * 116 *
77 */ 117 */
78 faim_export unsigned long aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg, int msglen) 118 faim_export unsigned long aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_sendimext_args *args)
79 { 119 {
80 int curbyte,i; 120 int curbyte,i;
81 struct command_tx_struct *newpacket; 121 struct command_tx_struct *newpacket;
82 122
83 if (!msg || (msglen <= 0)) 123 if (!sess || !conn || !args)
84 return -1; 124 return -1;
85 125
86 if (msglen >= MAXMSGLEN) 126 if (!args->msg || (args->msglen <= 0))
87 return -1; 127 return -1;
88 128
89 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, msglen+256))) 129 if (args->msglen >= MAXMSGLEN)
130 return -1;
131
132 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, args->msglen+512)))
90 return -1; 133 return -1;
91 134
92 newpacket->lock = 1; /* lock struct */ 135 newpacket->lock = 1; /* lock struct */
93 136
94 curbyte = 0; 137 curbyte = 0;
102 * might be a good idea.) In the message error functions, 145 * might be a good idea.) In the message error functions,
103 * the 8byte message cookie is returned as well as the 146 * the 8byte message cookie is returned as well as the
104 * SNAC ID. 147 * SNAC ID.
105 * 148 *
106 */ 149 */
107 for (i=0;i<8;i++) 150 for (i = 0; i < 8; i++)
108 curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) rand()); 151 curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) rand());
109 152
110 /* 153 /*
111 * Channel ID 154 * Channel ID
112 */ 155 */
113 curbyte += aimutil_put16(newpacket->data+curbyte,0x0001); 156 curbyte += aimutil_put16(newpacket->data+curbyte,0x0001);
114 157
115 /* 158 /*
116 * Destination SN (prepended with byte length) 159 * Destination SN (prepended with byte length)
117 */ 160 */
118 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); 161 curbyte += aimutil_put8(newpacket->data+curbyte, strlen(args->destsn));
119 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); 162 curbyte += aimutil_putstr(newpacket->data+curbyte, args->destsn, strlen(args->destsn));
120 163
121 /* 164 /*
122 * metaTLV start. 165 * metaTLV start.
123 */ 166 */
124 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); 167 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
125 curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x10); 168 curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x10);
126 169
127 /* 170 /*
128 * Flag data / ICBM Parameters? 171 * Flag data / ICBM Parameters?
129 * 172 *
130 * I don't know what these are... 173 * I don't know what these are...
143 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101); 186 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101);
144 187
145 /* 188 /*
146 * Message block length. 189 * Message block length.
147 */ 190 */
148 curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x04); 191 curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x04);
149 192
150 /* 193 /*
151 * Character set data? 194 * Character set.
152 */ 195 */
196 if (args->flags & AIM_IMFLAGS_UNICODE)
197 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
198 else if (args->flags & AIM_IMFLAGS_ISO_8859_1)
199 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
200 else
201 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
202
153 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 203 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
154 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
155 204
156 /* 205 /*
157 * Message. Not terminated. 206 * Message. Not terminated.
158 */ 207 */
159 curbyte += aimutil_putstr(newpacket->data+curbyte,msg, msglen); 208 curbyte += aimutil_putstr(newpacket->data+curbyte, args->msg, args->msglen);
160 209
161 /* 210 /*
162 * Set the Request Acknowledge flag. 211 * Set the Request Acknowledge flag.
163 */ 212 */
164 if (flags & AIM_IMFLAGS_ACK) { 213 if (args->flags & AIM_IMFLAGS_ACK) {
165 curbyte += aimutil_put16(newpacket->data+curbyte,0x0003); 214 curbyte += aimutil_put16(newpacket->data+curbyte,0x0003);
166 curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); 215 curbyte += aimutil_put16(newpacket->data+curbyte,0x0000);
167 } 216 }
168 217
169 /* 218 /*
170 * Set the Autoresponse flag. 219 * Set the Autoresponse flag.
171 */ 220 */
172 if (flags & AIM_IMFLAGS_AWAY) { 221 if (args->flags & AIM_IMFLAGS_AWAY) {
173 curbyte += aimutil_put16(newpacket->data+curbyte,0x0004); 222 curbyte += aimutil_put16(newpacket->data+curbyte,0x0004);
174 curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); 223 curbyte += aimutil_put16(newpacket->data+curbyte,0x0000);
175 } 224 }
176 225
226 /*
227 * Set the Buddy Icon Requested flag.
228 */
229 if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
230 curbyte += aimutil_put16(newpacket->data+curbyte,0x0009);
231 curbyte += aimutil_put16(newpacket->data+curbyte,0x0000);
232 }
233
234 /*
235 * Set the I HAVE A REALLY PURTY ICON flag (with timestamp).
236 */
237 if (args->flags & AIM_IMFLAGS_HASICON) {
238 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0008);
239 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
240 curbyte += aimutil_put32(newpacket->data+curbyte, args->iconlen);
241 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
242 curbyte += aimutil_put16(newpacket->data+curbyte, args->iconsum);
243 curbyte += aimutil_put32(newpacket->data+curbyte, args->iconstamp);
244 }
245
177 newpacket->commandlen = curbyte; 246 newpacket->commandlen = curbyte;
178 newpacket->lock = 0; 247 newpacket->lock = 0;
179 248
180 aim_tx_enqueue(sess, newpacket); 249 aim_tx_enqueue(sess, newpacket);
181 250
182 aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, destsn, strlen(destsn)+1); 251 #if 1 /* XXX do this with autoconf or something... */
252 aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
183 aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */ 253 aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */
254 #endif
184 255
185 return sess->snac_nextid; 256 return sess->snac_nextid;
257 }
258
259 /*
260 * Simple wrapper for aim_send_im_ext()
261 *
262 * You cannot use aim_send_im if you need the HASICON flag. You must
263 * use aim_send_im_ext directly for that.
264 *
265 * aim_send_im also cannot be used if you require UNICODE messages, because
266 * that requires an explicit message length. Use aim_send_im_ext().
267 *
268 */
269 faim_export unsigned long aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg)
270 {
271 struct aim_sendimext_args args;
272
273 args.destsn = destsn;
274 args.flags = flags;
275 args.msg = msg;
276 args.msglen = strlen(msg);
277
278 return aim_send_im_ext(sess, conn, &args);
279 }
280
281 faim_export int aim_send_icon(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum)
282 {
283 struct command_tx_struct *np;
284 int i,curbyte = 0;
285 unsigned char ck[8];
286
287 if (!sess || !conn || !sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
288 return -1;
289
290 if (conn->type != AIM_CONN_TYPE_BOS)
291 return -1;
292
293 for (i = 0, curbyte = 0; i < 8; i++)
294 curbyte += aimutil_put8(ck+curbyte, (u_char)rand());
295
296 if (!(np = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 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)))
297 return -1;
298
299 np->lock = 1;
300
301 curbyte = aim_putsnac(np->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
302
303 /*
304 * Cookie
305 */
306 memcpy(np->data+curbyte, ck, 8);
307 curbyte += 8;
308
309 /*
310 * Channel (2)
311 */
312 curbyte += aimutil_put16(np->data+curbyte, 0x0002);
313
314 /*
315 * Dest sn
316 */
317 curbyte += aimutil_put8(np->data+curbyte, strlen(sn));
318 curbyte += aimutil_putstr(np->data+curbyte, sn, strlen(sn));
319
320 /*
321 * TLV t(0005)
322 */
323 curbyte += aimutil_put16(np->data+curbyte, 0x0005);
324 curbyte += aimutil_put16(np->data+curbyte, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
325
326 curbyte += aimutil_put16(np->data+curbyte, 0x0000);
327
328 memcpy(np->data+curbyte, ck, 8);
329 curbyte += 8;
330
331 curbyte += aim_putcap(np->data+curbyte, 16, AIM_CAPS_BUDDYICON);
332
333 /* TLV t(000a) */
334 curbyte += aimutil_put16(np->data+curbyte, 0x000a);
335 curbyte += aimutil_put16(np->data+curbyte, 0x0002);
336 curbyte += aimutil_put16(np->data+curbyte, 0x0001);
337
338 /* TLV t(000f) */
339 curbyte += aimutil_put16(np->data+curbyte, 0x000f);
340 curbyte += aimutil_put16(np->data+curbyte, 0x0000);
341
342 /* TLV t(2711) */
343 curbyte += aimutil_put16(np->data+curbyte, 0x2711);
344 curbyte += aimutil_put16(np->data+curbyte, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
345 curbyte += aimutil_put16(np->data+curbyte, 0x0000);
346 curbyte += aimutil_put16(np->data+curbyte, iconsum);
347 curbyte += aimutil_put32(np->data+curbyte, iconlen);
348 curbyte += aimutil_put32(np->data+curbyte, stamp);
349 memcpy(np->data+curbyte, icon, iconlen);
350 curbyte += iconlen;
351 memcpy(np->data+curbyte, AIM_ICONIDENT, strlen(AIM_ICONIDENT));
352 curbyte += strlen(AIM_ICONIDENT);
353
354 /* TLV t(0003) */
355 curbyte += aimutil_put16(np->data+curbyte, 0x0003);
356 curbyte += aimutil_put16(np->data+curbyte, 0x0000);
357
358 np->commandlen = curbyte;
359 np->lock = 0;
360 aim_tx_enqueue(sess, np);
361
362 return 0;
186 } 363 }
187 364
188 static int outgoingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 365 static int outgoingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
189 { 366 {
190 unsigned int i, ret = 0; 367 unsigned int i, ret = 0;
248 aim_freetlvchain(&tlvlist); 425 aim_freetlvchain(&tlvlist);
249 426
250 return ret; 427 return ret;
251 } 428 }
252 429
253 static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) 430 static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, unsigned char *data, int datalen, unsigned char *cookie)
254 { 431 {
432 unsigned short type, length;
255 aim_rxcallback_t userfunc; 433 aim_rxcallback_t userfunc;
256 int i, j = 0, y = 0, z = 0, ret = 0; 434 int i, ret = 0;
257 char *msg = NULL; 435 struct aim_incomingim_ch1_args args;
258 unsigned long icbmflags = 0; 436
259 struct aim_tlv_t *msgblocktlv; 437 memset(&args, 0, sizeof(args));
260 unsigned char *msgblock; 438
261 unsigned short flag1, flag2; 439 /*
262 int finlen = 0; 440 * This used to be done using tlvchains. For performance reasons,
263 unsigned char fingerprint[10]; 441 * I've changed it to process the TLVs in-place. This avoids lots
264 unsigned short wastebits; 442 * of per-IM memory allocations.
265 443 */
266 /* 444 for (i = 0; i < datalen; ) {
267 * Check Autoresponse status. If it is an autoresponse,
268 * it will contain a type 0x0004 TLV, with zero length.
269 */
270 if (aim_gettlv(tlvlist, 0x0004, 1))
271 icbmflags |= AIM_IMFLAGS_AWAY;
272 445
273 /* 446 type = aimutil_get16(data+i);
274 * Check Ack Request status. 447 i += 2;
275 */
276 if (aim_gettlv(tlvlist, 0x0003, 1))
277 icbmflags |= AIM_IMFLAGS_ACK;
278 448
279 /* 449 length = aimutil_get16(data+i);
280 * Message block. 450 i += 2;
281 */ 451
282 msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); 452 if (type == 0x0002) { /* Message Block */
283 if (!msgblocktlv || !(msgblock = msgblocktlv->value)) { 453 unsigned short wastebits;
284 faimdprintf(sess, 0, "icbm: major error! no message block TLV found!\n"); 454 unsigned char *msgblock;
285 return 0; 455 int j = 0, y = 0, z = 0;
286 } 456
457 msgblock = data+i;
287 458
288 /* 459 /*
289 * Extracting the message from the unknown cruft. 460 * Extracting the message from the unknown cruft.
290 * 461 *
291 * This is a bit messy, and I'm not really qualified, 462 * This is a bit messy, and I'm not really qualified,
292 * even as the author, to comment on it. At least 463 * even as the author, to comment on it. At least
293 * its not as bad as a while loop shooting into infinity. 464 * its not as bad as a while loop shooting into infinity.
294 * 465 *
295 * "Do you believe in magic?" 466 * "Do you believe in magic?"
296 * 467 *
297 */ 468 */
298 469
299 wastebits = aimutil_get8(msgblock+j++); 470 wastebits = aimutil_get8(msgblock+j++);
300 wastebits = aimutil_get8(msgblock+j++); 471 wastebits = aimutil_get8(msgblock+j++);
301 472
302 y = aimutil_get16(msgblock+j); 473 y = aimutil_get16(msgblock+j);
303 j += 2; 474 j += 2;
304 for (z = 0; z < y; z++) 475 for (z = 0; z < y; z++)
305 wastebits = aimutil_get8(msgblock+j++); 476 wastebits = aimutil_get8(msgblock+j++);
306 wastebits = aimutil_get8(msgblock+j++); 477 wastebits = aimutil_get8(msgblock+j++);
307 wastebits = aimutil_get8(msgblock+j++); 478 wastebits = aimutil_get8(msgblock+j++);
308 479
309 finlen = j; 480 args.finlen = j;
310 if (finlen > sizeof(fingerprint)) 481 if (args.finlen > sizeof(args.fingerprint))
311 finlen = sizeof(fingerprint); 482 args.finlen = sizeof(args.fingerprint);
312 memcpy(fingerprint, msgblocktlv->value, finlen); 483 memcpy(args.fingerprint, msgblock, args.finlen);
313 484
314 /* 485 /* Message string length, including flag words. */
315 * Message string length, including flag words. 486 args.msglen = aimutil_get16(msgblock+j);
316 */ 487 j += 2;
317 i = aimutil_get16(msgblock+j); 488
318 j += 2; 489 /* Flag words. */
319 490 args.flag1 = aimutil_get16(msgblock+j);
320 /* 491 if (args.flag1 == 0x0002)
321 * Flag words. 492 args.icbmflags |= AIM_IMFLAGS_UNICODE;
322 * 493 else if (args.flag1 == 0x0003)
323 * Its rumored that these can kick in some funky 494 args.icbmflags |= AIM_IMFLAGS_ISO_8859_1;
324 * 16bit-wide char stuff that used to really kill 495 j += 2;
325 * libfaim. Hopefully the latter is no longer true. 496
326 * 497 args.flag2 = aimutil_get16(msgblock+j);
327 * Though someone should investiagte the former. 498 j += 2;
328 *
329 */
330 flag1 = aimutil_get16(msgblock+j);
331 j += 2;
332 flag2 = aimutil_get16(msgblock+j);
333 j += 2;
334 499
335 if (flag1 || flag2) 500 if ((args.flag1 && (args.flag1 != 0x0002) && (args.flag1 != 0x0003)) || args.flag2)
336 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); 501 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2);
337 502
338 /* 503 /* Message string. */
339 * Message string. 504 args.msglen -= 4;
340 */ 505 if (args.icbmflags & AIM_IMFLAGS_UNICODE) {
341 i -= 4; 506 args.msg = malloc(args.msglen+2);
342 msg = (char *)malloc(i+1); 507 memcpy(args.msg, msgblock+j, args.msglen);
343 memcpy(msg, msgblock+j, i); 508 args.msg[args.msglen] = '\0'; /* wide NULL */
344 msg[i] = '\0'; 509 args.msg[args.msglen+1] = '\0';
510 } else {
511 args.msg = malloc(args.msglen+1);
512 memcpy(args.msg, msgblock+j, args.msglen);
513 args.msg[args.msglen] = '\0';
514 }
515
516 } else if (type == 0x0003) { /* Server Ack Requested */
517
518 args.icbmflags |= AIM_IMFLAGS_ACK;
519
520 } else if (type == 0x0004) { /* Message is Auto Response */
521
522 args.icbmflags |= AIM_IMFLAGS_AWAY;
523
524 } else if ((type == 0x0008) &&
525 (length == 0x000c)) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
526
527 args.iconstamp = aimutil_get32(data+i+8);
528 args.icbmflags |= AIM_IMFLAGS_HASICON;
529
530 } else if (type == 0x0009) {
531
532 args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;
533
534 } else {
535 fprintf(stderr, "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length);
536 }
537
538 i += length;
539 }
540
345 541
346 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 542 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
347 ret = userfunc(sess, rx, channel, userinfo, msg, icbmflags, flag1, flag2, finlen, fingerprint); 543 ret = userfunc(sess, rx, channel, userinfo, &args);
348 544
349 free(msg); 545 free(args.msg);
350 546
351 return ret; 547 return ret;
352 } 548 }
353 549
354 static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) 550 static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie)
355 { 551 {
356 aim_rxcallback_t userfunc; 552 aim_rxcallback_t userfunc;
357 struct aim_tlv_t *block1; 553 struct aim_tlv_t *block1;
358 struct aim_tlvlist_t *list2; 554 struct aim_tlvlist_t *list2;
359 unsigned short reqclass = 0;
360 unsigned short status = 0;
361 int ret = 0; 555 int ret = 0;
556 struct aim_incomingim_ch2_args args;
557
558 memset(&args, 0, sizeof(args));
362 559
363 /* 560 /*
364 * There's another block of TLVs embedded in the type 5 here. 561 * There's another block of TLVs embedded in the type 5 here.
365 */ 562 */
366 block1 = aim_gettlv(tlvlist, 0x0005, 1); 563 block1 = aim_gettlv(tlvlist, 0x0005, 1);
372 /* 569 /*
373 * First two bytes represent the status of the connection. 570 * First two bytes represent the status of the connection.
374 * 571 *
375 * 0 is a request, 2 is an accept 572 * 0 is a request, 2 is an accept
376 */ 573 */
377 status = aimutil_get16(block1->value+0); 574 args.status = aimutil_get16(block1->value+0);
378 575
379 /* 576 /*
380 * Next comes the cookie. Should match the ICBM cookie. 577 * Next comes the cookie. Should match the ICBM cookie.
381 */ 578 */
382 if (memcmp(block1->value+2, cookie, 8) != 0) 579 if (memcmp(block1->value+2, cookie, 8) != 0)
392 * developers. Thanks! 589 * developers. Thanks!
393 * 590 *
394 * Read off one capability string and we should have it ID'd. 591 * Read off one capability string and we should have it ID'd.
395 * 592 *
396 */ 593 */
397 reqclass = aim_getcap(sess, block1->value+2+8, 0x10); 594 if ((args.reqclass = aim_getcap(sess, block1->value+2+8, 0x10)) == 0x0000) {
398 if (reqclass == 0x0000) {
399 faimdprintf(sess, 0, "rend: no ID block\n"); 595 faimdprintf(sess, 0, "rend: no ID block\n");
400 return 0; 596 return 0;
401 } 597 }
402 598
403 /* 599 /*
406 * 602 *
407 * Ack packets for instance have nothing more to them. 603 * Ack packets for instance have nothing more to them.
408 */ 604 */
409 list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); 605 list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16);
410 606
411 if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { 607 if (!list2 || ((args.reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) {
412 struct aim_msgcookie_t *cook; 608 struct aim_msgcookie_t *cook;
413 int type; 609 int type;
414 610
415 type = aim_msgcookie_gettype(reqclass); /* XXX: fix this shitty code */ 611 type = aim_msgcookie_gettype(args.reqclass); /* XXX: fix this shitty code */
416 612
417 if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { 613 if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) {
418 faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie); 614 faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie);
419 aim_freetlvchain(&list2); 615 aim_freetlvchain(&list2);
420 return 0; 616 return 0;
426 if (cook->data) { 622 if (cook->data) {
427 int errorcode = -1; /* XXX shouldnt this be 0? */ 623 int errorcode = -1; /* XXX shouldnt this be 0? */
428 624
429 ft = (struct aim_filetransfer_priv *)cook->data; 625 ft = (struct aim_filetransfer_priv *)cook->data;
430 626
431 if(status != 0x0002) { 627 if (args.status != 0x0002) {
628
432 if (aim_gettlv(list2, 0x000b, 1)) 629 if (aim_gettlv(list2, 0x000b, 1))
433 errorcode = aim_gettlv16(list2, 0x000b, 1); 630 errorcode = aim_gettlv16(list2, 0x000b, 1);
434 631
435 /* XXX this should make it up to the client, you know.. */ 632 /* XXX this should make it up to the client, you know.. */
436 if (errorcode) 633 if (errorcode)
451 } 648 }
452 649
453 /* 650 /*
454 * The rest of the handling depends on what type it is. 651 * The rest of the handling depends on what type it is.
455 */ 652 */
456 if (reqclass & AIM_CAPS_BUDDYICON) { 653 if (args.reqclass & AIM_CAPS_BUDDYICON) {
457 654 struct aim_tlv_t *miscinfo;
458 /* XXX implement this (its in ActiveBuddy...) */ 655 int curpos = 0;
656
657 miscinfo = aim_gettlv(list2, 0x2711, 1);
658
659 /* aimutil_get32(miscinfo->value+curpos); i don't know what this is */
660 curpos += 4;
661 args.info.icon.length = aimutil_get32(miscinfo->value+curpos);
662 curpos += 4;
663 args.info.icon.timestamp = aimutil_get32(miscinfo->value+curpos);
664 curpos += 4;
665 args.info.icon.icon = malloc(args.info.icon.length);
666 memcpy(args.info.icon.icon, miscinfo->value+curpos, args.info.icon.length);
667
459 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 668 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
460 ret = userfunc(sess, rx, channel, reqclass, userinfo); 669 ret = userfunc(sess, rx, channel, userinfo, &args);
461 670
462 } else if (reqclass & AIM_CAPS_VOICE) { 671 free(args.info.icon.icon);
672
673 } else if (args.reqclass & AIM_CAPS_VOICE) {
463 struct aim_msgcookie_t *cachedcook; 674 struct aim_msgcookie_t *cachedcook;
464 675
465 faimdprintf(sess, 0, "rend: voice!\n"); 676 faimdprintf(sess, 0, "rend: voice!\n");
466 677
467 if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) { 678 if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) {
477 faimdprintf(sess, 0, "ERROR caching message cookie\n"); 688 faimdprintf(sess, 0, "ERROR caching message cookie\n");
478 689
479 /* XXX: implement all this */ 690 /* XXX: implement all this */
480 691
481 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 692 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
482 ret = userfunc(sess, rx, channel, reqclass, &userinfo); 693 ret = userfunc(sess, rx, channel, userinfo, &args);
483 694
484 } else if ((reqclass & AIM_CAPS_IMIMAGE) || 695 } else if (args.reqclass & AIM_CAPS_IMIMAGE) {
485 (reqclass & AIM_CAPS_BUDDYICON)) {
486 char ip[30]; 696 char ip[30];
487 struct aim_directim_priv *priv; 697 struct aim_directim_priv *priv;
488 698
489 memset(ip, 0, sizeof(ip)); 699 memset(ip, 0, sizeof(ip));
490 700
508 /* 718 /*
509 * XXX: there are a couple of different request packets for 719 * XXX: there are a couple of different request packets for
510 * different things 720 * different things
511 */ 721 */
512 722
513 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); 723 args.info.directim = priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv));
514 memcpy(priv->ip, ip, sizeof(priv->ip)); 724 memcpy(priv->ip, ip, sizeof(priv->ip));
515 memcpy(priv->sn, userinfo->sn, sizeof(priv->sn)); 725 memcpy(priv->sn, userinfo->sn, sizeof(priv->sn));
516 memcpy(priv->cookie, cookie, sizeof(priv->cookie)); 726 memcpy(priv->cookie, cookie, sizeof(priv->cookie));
517 727
518 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 728 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
519 ret = userfunc(sess, rx, channel, reqclass, userinfo, priv); 729 ret = userfunc(sess, rx, channel, userinfo, &args);
520 730
521 } else if (reqclass & AIM_CAPS_CHAT) { 731 } else if (args.reqclass & AIM_CAPS_CHAT) {
522 struct aim_tlv_t *miscinfo; 732 struct aim_tlv_t *miscinfo;
523 struct aim_chat_roominfo roominfo;
524 char *msg=NULL,*encoding=NULL,*lang=NULL;
525 733
526 miscinfo = aim_gettlv(list2, 0x2711, 1); 734 miscinfo = aim_gettlv(list2, 0x2711, 1);
527 aim_chat_readroominfo(miscinfo->value, &roominfo); 735 aim_chat_readroominfo(miscinfo->value, &args.info.chat.roominfo);
528 736
529 if (aim_gettlv(list2, 0x000c, 1)) 737 if (aim_gettlv(list2, 0x000c, 1))
530 msg = aim_gettlv_str(list2, 0x000c, 1); 738 args.info.chat.msg = aim_gettlv_str(list2, 0x000c, 1);
531 739
532 if (aim_gettlv(list2, 0x000d, 1)) 740 if (aim_gettlv(list2, 0x000d, 1))
533 encoding = aim_gettlv_str(list2, 0x000d, 1); 741 args.info.chat.encoding = aim_gettlv_str(list2, 0x000d, 1);
534 742
535 if (aim_gettlv(list2, 0x000e, 1)) 743 if (aim_gettlv(list2, 0x000e, 1))
536 lang = aim_gettlv_str(list2, 0x000e, 1); 744 args.info.chat.lang = aim_gettlv_str(list2, 0x000e, 1);
537 745
538 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 746 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
539 ret = userfunc(sess, rx, channel, reqclass, userinfo, &roominfo, msg, encoding?encoding+1:NULL, lang?lang+1:NULL); 747 ret = userfunc(sess, rx, channel, userinfo, &args);
540 748
541 free(roominfo.name); 749 free(args.info.chat.roominfo.name);
542 free(msg); 750 free(args.info.chat.msg);
543 free(encoding); 751 free(args.info.chat.encoding);
544 free(lang); 752 free(args.info.chat.lang);
545 753
546 } else if (reqclass & AIM_CAPS_GETFILE) { 754 } else if (args.reqclass & AIM_CAPS_GETFILE) {
547 char ip[30]; 755 char ip[30];
548 struct aim_msgcookie_t *cachedcook; 756 struct aim_msgcookie_t *cachedcook;
549 struct aim_tlv_t *miscinfo; 757 struct aim_tlv_t *miscinfo;
550 struct aim_tlv_t *iptlv, *porttlv; 758 struct aim_tlv_t *iptlv, *porttlv;
551 759
571 aimutil_get8(iptlv->value+2), 779 aimutil_get8(iptlv->value+2),
572 aimutil_get8(iptlv->value+3), 780 aimutil_get8(iptlv->value+3),
573 aimutil_get16(porttlv->value)); 781 aimutil_get16(porttlv->value));
574 782
575 faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo->sn, ip); 783 faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo->sn, ip);
784
785 args.info.getfile.ip = ip;
786 args.info.getfile.cookie = cookie;
787
576 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 788 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
577 ret = userfunc(sess, rx, channel, reqclass, userinfo, ip, cookie); 789 ret = userfunc(sess, rx, channel, userinfo, &args);
578 790
579 } else if (reqclass & AIM_CAPS_SENDFILE) { 791 } else if (args.reqclass & AIM_CAPS_SENDFILE) {
580 #if 0 792 #if 0
581 char ip[30]; 793 char ip[30];
582 struct aim_msgcookie_t *cachedcook; 794 struct aim_msgcookie_t *cachedcook;
583 struct aim_tlv_t *miscinfo; 795 struct aim_tlv_t *miscinfo;
584 struct aim_tlv_t *iptlv, *porttlv; 796 struct aim_tlv_t *iptlv, *porttlv;
629 841
630 if (desc) 842 if (desc)
631 free(desc); 843 free(desc);
632 844
633 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 845 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
634 ret = userfunc(sess, rx, channel, reqclass, userinfo); 846 ret = userfunc(sess, rx, channel, userinfo, &args);
635 847
636 #endif 848 #endif
637 } else 849 } else
638 faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", reqclass); 850 faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", args.reqclass);
639 851
640 aim_freetlvchain(&list2); 852 aim_freetlvchain(&list2);
641 853
642 return ret; 854 return ret;
643 } 855 }
656 static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 868 static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
657 { 869 {
658 int i, ret = 0; 870 int i, ret = 0;
659 unsigned char cookie[8]; 871 unsigned char cookie[8];
660 int channel; 872 int channel;
661 struct aim_tlvlist_t *tlvlist;
662 struct aim_userinfo_s userinfo; 873 struct aim_userinfo_s userinfo;
663 874
664 memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); 875 memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s));
665 876
666 /* 877 /*
710 * 921 *
711 */ 922 */
712 i += aim_extractuserinfo(sess, data+i, &userinfo); 923 i += aim_extractuserinfo(sess, data+i, &userinfo);
713 924
714 /* 925 /*
715 * Read block of TLVs (not including the userinfo data). All
716 * further data is derived from what is parsed here.
717 */
718 tlvlist = aim_readtlvchain(data+i, datalen-i);
719
720 /*
721 * From here on, its depends on what channel we're on. 926 * From here on, its depends on what channel we're on.
722 */ 927 *
723 if (channel == 1) 928 * Technically all channels have a TLV list have this, however,
724 ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); 929 * for the common channel 1 case, in-place parsing is used for
725 else if (channel == 0x0002) 930 * performance reasons (less memory allocation).
931 */
932 if (channel == 1) {
933
934 ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, data+i, datalen-i, cookie);
935
936 } else if (channel == 0x0002) {
937 struct aim_tlvlist_t *tlvlist;
938
939 /*
940 * Read block of TLVs (not including the userinfo data). All
941 * further data is derived from what is parsed here.
942 */
943 tlvlist = aim_readtlvchain(data+i, datalen-i);
944
726 ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); 945 ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
727 946
728 /* 947 /*
729 * Free up the TLV chain. 948 * Free up the TLV chain.
730 */ 949 */
731 aim_freetlvchain(&tlvlist); 950 aim_freetlvchain(&tlvlist);
951 }
732 952
733 return ret; 953 return ret;
734 } 954 }
735 955
736 /* 956 /*