]>
Commit | Line | Data |
---|---|---|
9de3ca7e | 1 | /* |
2 | * aim_im.c | |
3 | * | |
4 | * The routines for sending/receiving Instant Messages. | |
5 | * | |
6 | */ | |
7 | ||
8 | #include "aim.h" | |
9 | ||
10 | /* | |
11 | * Send an ICBM (instant message). | |
12 | * | |
13 | * | |
14 | * Possible flags: | |
15 | * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse | |
16 | * AIM_IMFLAGS_ACK -- Requests that the server send an ack | |
17 | * when the message is received (of type 0x0004/0x000c) | |
18 | * | |
19 | * | |
20 | * The first one is newer, but it seems to be broken. Beware. Use the | |
21 | * second one for normal use...for now. | |
22 | * | |
23 | * | |
24 | */ | |
25 | ||
26 | #if 0 /* preliminary new fangled routine */ | |
27 | u_long aim_send_im(struct aim_conn_t *conn, char *destsn, int flags, char *msg) | |
28 | { | |
29 | ||
30 | int curbyte; | |
31 | struct command_tx_struct newpacket; | |
32 | ||
33 | newpacket.lock = 1; /* lock struct */ | |
34 | newpacket.type = 0x02; /* IMs are always family 0x02 */ | |
35 | if (conn) | |
36 | newpacket.conn = conn; | |
37 | else | |
38 | newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); | |
39 | ||
40 | newpacket.commandlen = 20+1+strlen(destsn)+1+1+2+7+2+4+strlen(msg)+2; | |
41 | ||
42 | if (flags & AIM_IMFLAGS_ACK) | |
43 | newpacket.commandlen += 4; | |
44 | if (flags & AIM_IMFLAGS_AWAY) | |
45 | newpacket.commandlen += 4; | |
46 | ||
47 | newpacket.data = (char *) calloc(1, newpacket.commandlen); | |
48 | ||
49 | curbyte = 0; | |
50 | curbyte += aim_putsnac(newpacket.data+curbyte, 0x0004, 0x0006, 0x0000, aim_snac_nextid); | |
51 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
52 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
53 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
54 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
55 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0001); | |
56 | curbyte += aimutil_put8(newpacket.data+curbyte,strlen(destsn)); | |
57 | curbyte += aimutil_putstr(newpacket.data+curbyte, destsn, strlen(destsn)); | |
58 | ||
59 | if (flags & AIM_IMFLAGS_ACK) | |
60 | { | |
61 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0003); | |
62 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
63 | } | |
64 | ||
65 | if (flags & AIM_IMFLAGS_AWAY) | |
66 | { | |
67 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0004); | |
68 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
69 | } | |
70 | ||
71 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0002); | |
72 | curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+0xf); | |
73 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0501); | |
74 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0001); | |
75 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0101); | |
76 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0101); | |
77 | curbyte += aimutil_put8(newpacket.data+curbyte,0x01); | |
78 | curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+4); | |
79 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
80 | curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); | |
81 | curbyte += aimutil_putstr(newpacket.data+curbyte, msg, strlen(msg)); | |
82 | ||
83 | aim_tx_enqueue(&newpacket); | |
84 | ||
85 | #ifdef USE_SNAC_FOR_IMS | |
86 | { | |
87 | struct aim_snac_t snac; | |
88 | ||
89 | snac.id = aim_snac_nextid; | |
90 | snac.family = 0x0004; | |
91 | snac.type = 0x0006; | |
92 | snac.flags = 0x0000; | |
93 | ||
94 | snac.data = malloc(strlen(destsn)+1); | |
95 | memcpy(snac.data, destsn, strlen(destsn)+1); | |
96 | ||
97 | aim_newsnac(&snac); | |
98 | } | |
99 | ||
100 | aim_cleansnacs(60); /* clean out all SNACs over 60sec old */ | |
101 | #endif | |
102 | ||
103 | return (aim_snac_nextid++); | |
104 | } | |
105 | #else | |
106 | u_long aim_send_im(struct aim_conn_t *conn, char *destsn, int flags, char *msg) | |
107 | { | |
108 | ||
109 | int i; | |
110 | struct command_tx_struct newpacket; | |
111 | ||
112 | newpacket.lock = 1; /* lock struct */ | |
113 | newpacket.type = 0x02; /* IMs are always family 0x02 */ | |
114 | if (conn) | |
115 | newpacket.conn = conn; | |
116 | else | |
117 | newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); | |
118 | ||
119 | i = strlen(destsn); /* used as offset later */ | |
120 | newpacket.commandlen = 20+1+strlen(destsn)+1+1+2+7+2+4+strlen(msg); | |
121 | ||
122 | if (flags & AIM_IMFLAGS_ACK) | |
123 | newpacket.commandlen += 4; | |
124 | if (flags & AIM_IMFLAGS_AWAY) | |
125 | newpacket.commandlen += 4; | |
126 | ||
127 | newpacket.data = (char *) malloc(newpacket.commandlen); | |
128 | memset(newpacket.data, 0x00, newpacket.commandlen); | |
129 | ||
130 | aim_putsnac(newpacket.data, 0x0004, 0x0006, 0x0000, aim_snac_nextid); | |
131 | ||
132 | newpacket.data[18] = 0x00; | |
133 | newpacket.data[19] = 0x01; | |
134 | ||
135 | newpacket.data[20] = i; | |
136 | memcpy(&(newpacket.data[21]), destsn, i); | |
137 | ||
138 | if (flags & AIM_IMFLAGS_ACK) | |
139 | { | |
140 | /* add TLV t(0004) l(0000) v(NULL) */ | |
141 | newpacket.data[21+i] = 0x00; | |
142 | newpacket.data[22+i] = 0x03; | |
143 | newpacket.data[23+i] = 0x00; | |
144 | newpacket.data[24+i] = 0x00; | |
145 | i += 4; | |
146 | } | |
147 | if (flags & AIM_IMFLAGS_AWAY) | |
148 | { | |
149 | /* add TLV t(0004) l(0000) v(NULL) */ | |
150 | newpacket.data[21+i] = 0x00; | |
151 | newpacket.data[22+i] = 0x04; | |
152 | newpacket.data[23+i] = 0x00; | |
153 | newpacket.data[24+i] = 0x00; | |
154 | i += 4; | |
155 | } | |
156 | ||
157 | newpacket.data[21+i] = 0x00; | |
158 | ||
159 | newpacket.data[22+i] = 0x02; | |
160 | ||
161 | newpacket.data[23+i] = (char) ( (strlen(msg) + 0xD) >> 8); | |
162 | newpacket.data[24+i] = (char) ( (strlen(msg) + 0xD) & 0xFF); | |
163 | ||
164 | newpacket.data[25+i] = 0x05; | |
165 | newpacket.data[26+i] = 0x01; | |
166 | newpacket.data[27+i] = 0x00; | |
167 | newpacket.data[28+i] = 0x01; | |
168 | newpacket.data[29+i] = 0x01; | |
169 | newpacket.data[30+i] = 0x01; | |
170 | newpacket.data[31+i] = 0x01; | |
171 | ||
172 | newpacket.data[32+i] = (char) ( (strlen(msg) + 4) >> 8); | |
173 | newpacket.data[33+i] = (char) ( (strlen(msg) + 4) & 0xFF); | |
174 | ||
175 | memcpy(&(newpacket.data[38+i]), msg, strlen(msg)); | |
176 | ||
177 | aim_tx_enqueue(&newpacket); | |
178 | #ifdef USE_SNAC_FOR_IMS | |
179 | { | |
180 | struct aim_snac_t snac; | |
181 | ||
182 | snac.id = aim_snac_nextid; | |
183 | snac.family = 0x0004; | |
184 | snac.type = 0x0006; | |
185 | snac.flags = 0x0000; | |
186 | ||
187 | snac.data = malloc(strlen(destsn)+1); | |
188 | memcpy(snac.data, destsn, strlen(destsn)+1); | |
189 | ||
190 | aim_newsnac(&snac); | |
191 | } | |
192 | ||
193 | aim_cleansnacs(60); /* clean out all SNACs over 60sec old */ | |
194 | #endif | |
195 | ||
196 | return (aim_snac_nextid++); | |
197 | } | |
198 | ||
199 | #endif | |
200 | ||
201 | #if 0 /* this is the prelim work on a new routine */ | |
202 | int aim_parse_incoming_im_middle(struct command_rx_struct *command) | |
203 | { | |
204 | int i = 0; | |
205 | char *srcsn = NULL; | |
206 | char *msg = NULL; | |
207 | u_int msglen = 0; | |
208 | int warninglevel = 0; | |
209 | int tlvcnt = 0; | |
210 | int class = 0; | |
211 | u_long membersince = 0; | |
212 | u_long onsince = 0; | |
213 | int idletime = 0; | |
214 | int isautoreply = 0; | |
215 | rxcallback_t userfunc = NULL; | |
216 | ||
217 | int unknown_f = -1; | |
218 | int unknown_10 = -1; | |
219 | ||
220 | i = 20; /* skip SNAC header and message cookie */ | |
221 | ||
222 | srcsn = malloc(command->data[i] + 1); | |
223 | memcpy(srcsn, &(command->data[i+1]), command->data[i]); | |
224 | srcsn[(int)command->data[i]] = '\0'; | |
225 | ||
226 | i += (int) command->data[i] + 1; /* add SN len */ | |
227 | ||
228 | /* warning level */ | |
229 | warninglevel = (command->data[i] << 8); | |
230 | warninglevel += (command->data[i+1]); | |
231 | i += 2; | |
232 | ||
233 | /* | |
234 | * This is suppose to be the number of TLVs that follow. However, | |
235 | * its not nearly as accurate as we need it to be, so we just run | |
236 | * the TLV parser all the way to the end of the frame. | |
237 | */ | |
238 | tlvcnt = ((command->data[i++]) << 8) & 0xFF00; | |
239 | tlvcnt += (command->data[i++]) & 0x00FF; | |
240 | ||
241 | /* a mini TLV parser */ | |
242 | { | |
243 | int curtlv = 0; | |
244 | int count_t4 = 0, count_t3 = 0, count_t2 = 0, count_t1 = 0; | |
245 | ||
246 | while (i+4 < command->commandlen) | |
247 | { | |
248 | if ((command->data[i] == 0x00) && | |
249 | (command->data[i+1] == 0x01) ) | |
250 | { | |
251 | if (count_t1 == 0) | |
252 | { | |
253 | /* t(0001) = class */ | |
254 | if (command->data[i+3] != 0x02) | |
255 | printf("faim: userinfo: **warning: strange v(%x) for t(1)\n", command->data[i+3]); | |
256 | class = ((command->data[i+4]) << 8) & 0xFF00; | |
257 | class += (command->data[i+5]) & 0x00FF; | |
258 | } | |
259 | else | |
260 | printf("faim: icbm: unexpected extra TLV t(0001)\n"); | |
261 | count_t1++; | |
262 | } | |
263 | else if ((command->data[i] == 0x00) && | |
264 | (command->data[i+1] == 0x02)) | |
265 | { | |
266 | if (count_t2 == 0) | |
267 | { | |
268 | /* t(0002) = member since date */ | |
269 | if (command->data[i+3] != 0x04) | |
270 | printf("faim: userinfo: **warning: strange v(%x) for t(2)\n", command->data[i+3]); | |
271 | ||
272 | membersince = ((command->data[i+4]) << 24) & 0xFF000000; | |
273 | membersince += ((command->data[i+5]) << 16) & 0x00FF0000; | |
274 | membersince += ((command->data[i+6]) << 8) & 0x0000FF00; | |
275 | membersince += ((command->data[i+7]) ) & 0x000000FF; | |
276 | } | |
277 | else if (count_t2 == 1) | |
278 | { | |
279 | int biglen = 0, innerlen = 0; | |
280 | int j; | |
281 | ||
282 | /* message */ | |
283 | ||
284 | /* | |
285 | * Check for message signature (0x0501). I still don't really | |
286 | * like this, but it is better than the old way, and it does | |
287 | * seem to be consistent as long as AOL doesn't do any more | |
288 | * big changes. | |
289 | */ | |
290 | if ( (command->data[i+4] != 0x05) || | |
291 | (command->data[i+5] != 0x01) ) | |
292 | printf("faim: icbm: warning: message signature not present, trying to recover\n"); | |
293 | ||
294 | biglen = ((command->data[i+2] << 8) + command->data[i+3]) & 0xffff; | |
295 | ||
296 | printf("faim: icbm: biglen = %02x\n", biglen); | |
297 | ||
298 | j = 0; | |
299 | while (j+3 < (biglen-6)) | |
300 | { | |
301 | if ( (command->data[i+6+j+0] == 0x00) && | |
302 | (command->data[i+6+j+1] == 0x00) && | |
303 | (command->data[i+6+j+2] == 0x00) ) | |
304 | { | |
305 | ||
306 | innerlen = (command->data[i+6+j]<<8) + command->data[i+6+j+1]; | |
307 | break; | |
308 | } | |
309 | j++; | |
310 | } | |
311 | if (!innerlen) | |
312 | { | |
313 | printf("faim: icbm: unable to find holy zeros; skipping message\n"); | |
314 | msglen = 0; | |
315 | msg = NULL; | |
316 | } | |
317 | else | |
318 | { | |
319 | printf("faim: icbm: innerlen = %d\n", innerlen); | |
320 | ||
321 | msglen = innerlen - 4; | |
322 | printf("faim: icbm: msglen = %u\n", msglen); | |
323 | ||
324 | msg = malloc(msglen +1); | |
325 | memcpy(msg, &(command->data[i+6+j+4+1]), msglen); | |
326 | msg[msglen] = '\0'; | |
327 | } | |
328 | } | |
329 | else | |
330 | printf("faim: icbm: **warning: extra TLV t(0002)\n"); | |
331 | count_t2++; | |
332 | } | |
333 | else if ((command->data[i] == 0x00) && | |
334 | (command->data[i+1] == 0x03)) | |
335 | { | |
336 | if (count_t3 == 0) | |
337 | { | |
338 | /* t(0003) = on since date */ | |
339 | if (command->data[i+3] != 0x04) | |
340 | printf("faim: userinfo: **warning: strange v(%x) for t(3)\n", command->data[i+3]); | |
341 | ||
342 | onsince = ((command->data[i+4]) << 24) & 0xFF000000; | |
343 | onsince += ((command->data[i+5]) << 16) & 0x00FF0000; | |
344 | onsince += ((command->data[i+6]) << 8) & 0x0000FF00; | |
345 | onsince += ((command->data[i+7]) ) & 0x000000FF; | |
346 | } | |
347 | else if (count_t3 == 1) | |
348 | printf("faim: icbm: request for acknowledgment ignored\n"); | |
349 | else | |
350 | printf("faim: icbm: unexpected extra TLV t(0003)\n"); | |
351 | count_t3++; | |
352 | } | |
353 | else if ((command->data[i] == 0x00) && | |
354 | (command->data[i+1] == 0x04) ) | |
355 | { | |
356 | if (count_t4 == 0) | |
357 | { | |
358 | /* t(0004) = idle time */ | |
359 | if (command->data[i+3] != 0x02) | |
360 | printf("faim: userinfo: **warning: strange v(%x) for t(4)\n", command->data[i+3]); | |
361 | idletime = ((command->data[i+4]) << 8) & 0xFF00; | |
362 | idletime += (command->data[i+5]) & 0x00FF; | |
363 | } | |
364 | else if ((count_t4 == 1) && (((command->data[i+2]<<8)+command->data[i+3])==0x0000)) | |
365 | isautoreply = 1; | |
366 | else | |
367 | printf("faim: icbm: unexpected extra TLV t(0004)\n"); | |
368 | count_t4++; | |
369 | } | |
370 | else if ((command->data[i] == 0x00) && | |
371 | (command->data[i+1] == 0x0f)) | |
372 | { | |
373 | /* t(000f) = unknown...usually from AIM3 users */ | |
374 | if (command->data[i+3] != 0x04) | |
375 | printf("faim: userinfo: **warning: strange v(%x) for t(f)\n", command->data[i+3]); | |
376 | unknown_f = (command->data[i+4] << 24) & 0xff000000; | |
377 | unknown_f += (command->data[i+5] << 16) & 0x00ff0000; | |
378 | unknown_f += (command->data[i+6] << 8) & 0x0000ff00; | |
379 | unknown_f += (command->data[i+7]) & 0x000000ff; | |
380 | } | |
381 | else if ((command->data[i] == 0x00) && | |
382 | (command->data[i+1] == 0x10)) | |
383 | { | |
384 | /* t(0010) = unknown...usually from AOL users */ | |
385 | if (command->data[i+3] != 0x04) | |
386 | printf("faim: userinfo: **warning: strange v(%x) for t(10)\n", command->data[i+3]); | |
387 | unknown_10 = (command->data[i+4] << 24) & 0xff000000; | |
388 | unknown_10 += (command->data[i+5] << 16) & 0x00ff0000; | |
389 | unknown_10 += (command->data[i+6] << 8) & 0x0000ff00; | |
390 | unknown_10 += (command->data[i+7]) & 0x000000ff; | |
391 | } | |
392 | else | |
393 | { | |
394 | printf("faim: userinfo: **warning: unexpected TLV t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]); | |
395 | } | |
396 | i += (2 + 2 + ((command->data[i+2] << 8) + command->data[i+3])); | |
397 | curtlv++; | |
398 | } | |
399 | } | |
400 | ||
401 | #if 0 | |
402 | { | |
403 | /* detect if this is an auto-response or not */ | |
404 | /* auto-responses can be detected by the presence of a *second* TLV with | |
405 | t(0004), but of zero length (and therefore no value portion) */ | |
406 | struct aim_tlv_t *tsttlv = NULL; | |
407 | tsttlv = aim_grabtlv((u_char *) &(command->data[i])); | |
408 | if (tsttlv->type == 0x04) | |
409 | isautoreply = 1; | |
410 | aim_freetlv(&tsttlv); | |
411 | } | |
412 | ||
413 | i += 2; | |
414 | ||
415 | i += 2; /* skip first msglen */ | |
416 | i += 7; /* skip garbage */ | |
417 | i -= 4; | |
418 | ||
419 | /* oh boy is this terrible... this comes from a specific of the spec */ | |
420 | while(1) | |
421 | { | |
422 | if ( ( (command->data[i] == 0x00) && | |
423 | (command->data[i+1] == 0x00) && | |
424 | (command->data[i+2] == 0x00) && | |
425 | (command->data[i+3] == 0x00) ) && | |
426 | (i < command->commandlen) ) /* prevent infinity */ | |
427 | break; | |
428 | else | |
429 | i++; | |
430 | } | |
431 | ||
432 | i -= 2; | |
433 | ||
434 | if ( (command->data[i] == 0x00) && | |
435 | (command->data[i+1] == 0x00) ) | |
436 | i += 2; | |
437 | ||
438 | msglen = ( (( (u_int) command->data[i]) & 0xFF ) << 8); | |
439 | msglen += ( (u_int) command->data[i+1]) & 0xFF; /* mask off garbage */ | |
440 | i += 2; | |
441 | ||
442 | msglen -= 4; /* skip four 0x00s */ | |
443 | i += 4; | |
444 | ||
445 | msg = malloc(msglen +1); | |
446 | ||
447 | memcpy(msg, &(command->data[i]), msglen); | |
448 | msg[msglen] = '\0'; | |
449 | #endif | |
450 | userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); | |
451 | if (userfunc) | |
452 | i = userfunc(command, srcsn, msg, warninglevel, class, membersince, onsince, idletime, isautoreply, unknown_f, unknown_10); | |
453 | else | |
454 | i = 0; | |
455 | ||
456 | free(srcsn); | |
457 | free(msg); | |
458 | ||
459 | return i; | |
460 | } | |
461 | #else /* older routine, with new fixes */ | |
462 | int aim_parse_incoming_im_middle(struct command_rx_struct *command) | |
463 | { | |
464 | struct aim_userinfo_s userinfo; | |
465 | u_int i = 0; | |
466 | char *msg = NULL; | |
467 | u_int msglen = 0; | |
468 | int isautoreply = 0; | |
469 | rxcallback_t userfunc = NULL; | |
470 | ||
471 | i = 20; | |
472 | i += aim_extractuserinfo(command->data+i, &userinfo); | |
473 | ||
474 | { | |
475 | /* | |
476 | * Auto-responses can be detected by the presence of a *second* TLV with | |
477 | * t(0004), but of zero length (and therefore no value portion) | |
478 | */ | |
479 | struct aim_tlv_t *tsttlv = NULL; | |
480 | tsttlv = aim_grabtlv((u_char *) &(command->data[i])); | |
481 | if (tsttlv->type == 0x04) | |
482 | isautoreply = 1; | |
483 | #if 0 | |
484 | else if (tsttlv->type == 0x03) | |
485 | { | |
486 | printf("faim: icbm: ack requested, ignored\n"); | |
487 | i += 2 + 2 + tsttlv->length; | |
488 | aim_freetlv(&tsttlv); | |
489 | tsttlv = aim_grabtlv((u_char *) &(command->data[i])); | |
490 | if (tsttlv->type == 0x04) | |
491 | isautoreply = 1; | |
492 | } | |
493 | #endif | |
494 | aim_freetlv(&tsttlv); | |
495 | } | |
496 | ||
497 | i += 2; | |
498 | ||
499 | i += 2; /* skip first msglen */ | |
500 | i += 7; /* skip garbage */ | |
501 | i -= 4; | |
502 | ||
503 | /* oh boy is this terrible... this comes from a specific of the spec */ | |
504 | while(1) | |
505 | { | |
506 | /* | |
507 | * We used to look for four zeros; I've reduced this to three | |
508 | * as it seems AOL changed it with Mac AIM 3.0 clients. | |
509 | */ | |
510 | if ( ( (command->data[i] == 0x00) && | |
511 | (command->data[i+1] == 0x00) && | |
512 | (command->data[i+2] == 0x00) ) && | |
513 | (i+2 < command->commandlen) ) /* prevent infinity */ | |
514 | break; | |
515 | else | |
516 | i++; | |
517 | } | |
518 | ||
519 | i -= 2; | |
520 | ||
521 | if (aimutil_get16(&command->data[i]) == 0x0000) | |
522 | i += 2; | |
523 | ||
524 | msglen = aimutil_get16(&command->data[i]); | |
525 | i += 2; | |
526 | ||
527 | msglen -= 4; /* skip four 0x00s */ | |
528 | i += 4; | |
529 | ||
530 | msg = malloc(msglen +1); | |
531 | ||
532 | memcpy(msg, &(command->data[i]), msglen); | |
533 | msg[msglen] = '\0'; | |
534 | ||
535 | userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); | |
536 | ||
537 | if (userfunc) | |
538 | i = userfunc(command, &userinfo, msg, isautoreply); | |
539 | else | |
540 | i = 0; | |
541 | ||
542 | free(msg); | |
543 | ||
544 | return i; | |
545 | } | |
546 | #endif |