]> andersk Git - libfaim.git/blame - aim_im.c
Initial Checkin. For real.
[libfaim.git] / aim_im.c
CommitLineData
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 */
27u_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
106u_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 */
202int 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 */
462int 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
This page took 0.209248 seconds and 5 git commands to generate.