]> andersk Git - libfaim.git/blob - aim_im.c
ab070485eb9be5419b4e18919233841326761e6d
[libfaim.git] / aim_im.c
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
This page took 0.252603 seconds and 3 git commands to generate.