Mercurial > pidgin.yaz
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 ߪ 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 /* |