]> andersk Git - libfaim.git/blob - aim_info.c
Hopefully fix msgbot's issue.
[libfaim.git] / aim_info.c
1 /*
2  * aim_info.c
3  *
4  * The functions here are responsible for requesting and parsing information-
5  * gathering SNACs.  
6  *
7  */
8
9
10 #include <faim/aim.h>
11
12 struct aim_priv_inforeq {
13   char sn[MAXSNLEN];
14   unsigned short infotype;
15 };
16
17 u_long aim_getinfo(struct aim_session_t *sess,
18                    struct aim_conn_t *conn, 
19                    const char *sn,
20                    unsigned short infotype)
21 {
22   struct command_tx_struct *newpacket;
23   int i = 0;
24
25   if (!sess || !conn || !sn)
26     return 0;
27
28   if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn))))
29     return -1;
30
31   newpacket->lock = 1;
32
33   i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid);
34
35   i += aimutil_put16(newpacket->data+i, infotype);
36   i += aimutil_put8(newpacket->data+i, strlen(sn));
37   i += aimutil_putstr(newpacket->data+i, sn, strlen(sn));
38
39   newpacket->lock = 0;
40   aim_tx_enqueue(sess, newpacket);
41
42   {
43     struct aim_snac_t snac;
44     
45     snac.id = sess->snac_nextid;
46     snac.family = 0x0002;
47     snac.type = 0x0005;
48     snac.flags = 0x0000;
49
50     snac.data = malloc(sizeof(struct aim_priv_inforeq));
51     strcpy(((struct aim_priv_inforeq *)snac.data)->sn, sn);
52     ((struct aim_priv_inforeq *)snac.data)->infotype = infotype;
53
54     aim_newsnac(sess, &snac);
55   }
56
57   return (sess->snac_nextid++);
58 }
59
60
61 /*
62  * Capability blocks.  
63  */
64 u_char aim_caps[6][16] = {
65   
66   /* Buddy icon */
67   {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, 
68    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
69   
70   /* Voice */
71   {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, 
72    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
73   
74   /* IM image */
75   {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, 
76    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
77   
78   /* Chat */
79   {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 
80    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
81   
82   /* Get file */
83   {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
84    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
85   
86   /* Send file */
87   {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, 
88    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
89 };
90
91 /*
92  * AIM is fairly regular about providing user info.  This
93  * is a generic routine to extract it in its standard form.
94  */
95 int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
96 {
97   int i = 0;
98   int tlvcnt = 0;
99   int curtlv = 0;
100   int tlv1 = 0;
101   u_short curtype;
102
103
104   if (!buf || !outinfo)
105     return -1;
106
107   /* Clear out old data first */
108   memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
109
110   /*
111    * Screen name.    Stored as an unterminated string prepended
112    *                 with an unsigned byte containing its length.
113    */
114   memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
115   outinfo->sn[(int)buf[i]] = '\0';
116   i = 1 + (int)buf[i];
117
118   /*
119    * Warning Level.  Stored as an unsigned short.
120    */
121   outinfo->warnlevel = aimutil_get16(&buf[i]);
122   i += 2;
123
124   /*
125    * TLV Count.      Unsigned short representing the number of 
126    *                 Type-Length-Value triples that follow.
127    */
128   tlvcnt = aimutil_get16(&buf[i]);
129   i += 2;
130
131   /* 
132    * Parse out the Type-Length-Value triples as they're found.
133    */
134   while (curtlv < tlvcnt)
135     {
136       curtype = aimutil_get16(&buf[i]);
137       switch (curtype)
138         {
139           /*
140            * Type = 0x0001: Member Class.   
141            * 
142            * Specified as any of the following bitwise ORed together:
143            *      0x0001  Trial (user less than 60days)
144            *      0x0002  Unknown bit 2
145            *      0x0004  AOL Main Service user
146            *      0x0008  Unknown bit 4
147            *      0x0010  Free (AIM) user 
148            *      0x0020  Away
149            *
150            * In some odd cases, we can end up with more
151            * than one of these.  We only want the first,
152            * as the others may not be something we want.
153            *
154            */
155         case 0x0001:
156           if (tlv1) /* use only the first */
157             break;
158           outinfo->class = aimutil_get16(&buf[i+4]);
159           tlv1++;
160           break;
161           
162           /*
163            * Type = 0x0002: Member-Since date. 
164            *
165            * The time/date that the user originally
166            * registered for the service, stored in 
167            * time_t format
168            */
169         case 0x0002: 
170           outinfo->membersince = aimutil_get32(&buf[i+4]);
171           break;
172           
173           /*
174            * Type = 0x0003: On-Since date.
175            *
176            * The time/date that the user started 
177            * their current session, stored in time_t
178            * format.
179            */
180         case 0x0003:
181           outinfo->onlinesince = aimutil_get32(&buf[i+4]);
182           break;
183
184           /*
185            * Type = 0x0004: Idle time.
186            *
187            * Number of seconds since the user
188            * actively used the service.
189            */
190         case 0x0004:
191           outinfo->idletime = aimutil_get16(&buf[i+4]);
192           break;
193
194           /*
195            * Type = 0x000d
196            *
197            * Capability information.  Not real sure of
198            * actual decoding.  See comment on aim_bos_setprofile()
199            * in aim_misc.c about the capability block, its the same.
200            *
201            * Ignore.
202            *
203            */
204         case 0x000d:
205           {
206             int z,y; 
207             int len;
208             len = aimutil_get16(buf+i+2);
209             if (!len)
210               break;
211
212             for (z = 0; z < len; z+=0x10) {
213               for(y=0; y < 6; y++) {
214                 if (memcmp(&aim_caps[y], buf+i+4+z, 0x10) == 0) {
215                   switch(y) {
216                   case 0: outinfo->capabilities |= AIM_CAPS_BUDDYICON; break;
217                   case 1: outinfo->capabilities |= AIM_CAPS_VOICE; break;
218                   case 2: outinfo->capabilities |= AIM_CAPS_IMIMAGE; break;
219                   case 3: outinfo->capabilities |= AIM_CAPS_CHAT; break;
220                   case 4: outinfo->capabilities |= AIM_CAPS_GETFILE; break;
221                   case 5: outinfo->capabilities |= AIM_CAPS_SENDFILE; break;
222                   default: outinfo->capabilities |= 0xff00; break;
223                   }
224                 }
225               }
226             }
227           }
228           break;
229
230           /*
231            * Type = 0x000e
232            *
233            * Unknown.  Always of zero length, and always only
234            * on AOL users.
235            *
236            * Ignore.
237            *
238            */
239         case 0x000e:
240           break;
241           
242           /*
243            * Type = 0x000f: Session Length. (AIM)
244            * Type = 0x0010: Session Length. (AOL)
245            *
246            * The duration, in seconds, of the user's
247            * current session.
248            *
249            * Which TLV type this comes in depends
250            * on the service the user is using (AIM or AOL).
251            *
252            */
253         case 0x000f:
254         case 0x0010:
255           outinfo->sessionlen = aimutil_get32(&buf[i+4]);
256           break;
257
258           /*
259            * Reaching here indicates that either AOL has
260            * added yet another TLV for us to deal with, 
261            * or the parsing has gone Terribly Wrong.
262            *
263            * Either way, inform the owner and attempt
264            * recovery.
265            *
266            */
267         default:
268           {
269             int len,z = 0, y = 0, x = 0;
270             char tmpstr[80];
271             printf("faim: userinfo: **warning: unexpected TLV:\n");
272             printf("faim: userinfo:   sn    =%s\n", outinfo->sn);
273             printf("faim: userinfo:   curtlv=0x%04x\n", curtlv);
274             printf("faim: userinfo:   type  =0x%04x\n",aimutil_get16(&buf[i]));
275             printf("faim: userinfo:   length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
276             printf("faim: userinfo:   data: \n");
277             while (z<len)
278               {
279                 x = sprintf(tmpstr, "faim: userinfo:      ");
280                 for (y = 0; y < 8; y++)
281                   {
282                     if (z<len)
283                       {
284                         sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
285                         z++;
286                         x += 3;
287                       }
288                     else
289                       break;
290                   }
291                 printf("%s\n", tmpstr);
292               }
293           }
294           break;
295         }  
296       /*
297        * No matter what, TLV triplets should always look like this:
298        *
299        *   u_short type;
300        *   u_short length;
301        *   u_char  data[length];
302        *
303        */
304       i += (2 + 2 + aimutil_get16(&buf[i+2]));
305       
306       curtlv++;
307     }
308   
309   return i;
310 }
311
312 /*
313  * Oncoming Buddy notifications contain a subset of the
314  * user information structure.  Its close enough to run
315  * through aim_extractuserinfo() however.
316  *
317  */
318 int aim_parse_oncoming_middle(struct aim_session_t *sess,
319                               struct command_rx_struct *command)
320 {
321   struct aim_userinfo_s userinfo;
322   u_int i = 0;
323   rxcallback_t userfunc=NULL;
324
325   i = 10;
326   i += aim_extractuserinfo(command->data+i, &userinfo);
327
328   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
329   if (userfunc)
330     i = userfunc(sess, command, &userinfo);
331
332   return 1;
333 }
334
335 /*
336  * Offgoing Buddy notifications contain no useful
337  * information other than the name it applies to.
338  *
339  */
340 int aim_parse_offgoing_middle(struct aim_session_t *sess,
341                               struct command_rx_struct *command)
342 {
343   char sn[MAXSNLEN+1];
344   u_int i = 0;
345   rxcallback_t userfunc=NULL;
346
347   strncpy(sn, command->data+11, (int)command->data[10]);
348   sn[(int)command->data[10]] = '\0';
349
350   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
351   if (userfunc)
352     i = userfunc(sess, command, sn);
353
354   return 1;
355 }
356
357 /*
358  * This parses the user info stuff out all nice and pretty then calls 
359  * the higher-level callback (in the user app).
360  *
361  */
362 int aim_parse_userinfo_middle(struct aim_session_t *sess,
363                               struct command_rx_struct *command)
364 {
365   struct aim_userinfo_s userinfo;
366   char *text_encoding = NULL;
367   char *text = NULL;
368   u_int i = 0;
369   rxcallback_t userfunc=NULL;
370   struct aim_tlvlist_t *tlvlist;
371   struct aim_snac_t *origsnac = NULL;
372   u_long snacid;
373   struct aim_priv_inforeq *inforeq;
374   
375   snacid = aimutil_get32(&command->data[6]);
376   origsnac = aim_remsnac(sess, snacid);
377
378   if (!origsnac || !origsnac->data) {
379     printf("faim: parse_userinfo_middle: major problem: no snac stored!\n");
380     return 1;
381   }
382
383   inforeq = (struct aim_priv_inforeq *)origsnac->data;
384
385   switch (inforeq->infotype) {
386   case AIM_GETINFO_GENERALINFO:
387   case AIM_GETINFO_AWAYMESSAGE:
388     i = 10;
389
390     /*
391      * extractuserinfo will give us the basic metaTLV information
392      */
393     i += aim_extractuserinfo(command->data+i, &userinfo);
394   
395     /*
396      * However, in this command, there's usually more TLVs following...
397      */ 
398     tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
399
400     /* 
401      * Depending on what informational text was requested, different
402      * TLVs will appear here.
403      *
404      * Profile will be 1 and 2, away message will be 3 and 4.
405      */
406     if (aim_gettlv(tlvlist, 0x0001, 1)) {
407       text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
408       text = aim_gettlv_str(tlvlist, 0x0002, 1);
409     } else if (aim_gettlv(tlvlist, 0x0003, 1)) {
410       text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
411       text = aim_gettlv_str(tlvlist, 0x0004, 1);
412     }
413
414     userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
415     if (userfunc) {
416       i = userfunc(sess,
417                    command, 
418                    &userinfo, 
419                    text_encoding, 
420                    text,
421                    inforeq->infotype); 
422     }
423   
424     free(text_encoding);
425     free(text);
426     aim_freetlvchain(&tlvlist);
427     break;
428   default:
429     printf("faim: parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype);
430     break;
431   }
432
433   if (origsnac) {
434     if (origsnac->data)
435       free(origsnac->data);
436     free(origsnac);
437   }
438
439   return 1;
440 }
441
442 /*
443  * Inverse of aim_extractuserinfo()
444  */
445 int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info)
446 {
447   int i = 0;
448   struct aim_tlvlist_t *tlvlist = NULL;
449
450   if (!buf || !info)
451     return 0;
452
453   i += aimutil_put8(buf+i, strlen(info->sn));
454   i += aimutil_putstr(buf+i, info->sn, strlen(info->sn));
455
456   i += aimutil_put16(buf+i, info->warnlevel);
457
458   /* XXX: we only put down five */
459   i += aimutil_put16(buf+i, 5);
460   aim_addtlvtochain16(&tlvlist, 0x0001, info->class);
461   aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
462   aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
463   aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
464   /* XXX: should put caps here */
465   aim_addtlvtochain32(&tlvlist, (info->class)&AIM_CLASS_AOL?0x0010:0x000f, info->sessionlen);
466   
467   i += aim_writetlvchain(buf+i, buflen-i, &tlvlist);
468   aim_freetlvchain(&tlvlist);
469   
470   return i;
471 }
472
473 int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
474 {
475   struct command_tx_struct *tx;
476   int i = 0;
477
478   if (!sess || !conn || !info)
479     return 0;
480
481   if (!(tx = aim_tx_new(0x0002, conn, 1152)))
482     return -1;
483
484   tx->lock = 1;
485
486   i += aimutil_put16(tx->data+i, 0x0003);
487   i += aimutil_put16(tx->data+i, 0x000b);
488   i += aimutil_put16(tx->data+i, 0x0000);
489   i += aimutil_put16(tx->data+i, 0x0000);
490   i += aimutil_put16(tx->data+i, 0x0000);
491
492   i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
493
494   tx->commandlen = i;
495   tx->lock = 0;
496   aim_tx_enqueue(sess, tx);
497
498   return 0;
499 }
500
501 int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
502 {
503   struct command_tx_struct *tx;
504   int i = 0;
505
506   if (!sess || !conn || !sn)
507     return 0;
508
509   if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
510     return -1;
511
512   tx->lock = 1;
513
514   i += aimutil_put16(tx->data+i, 0x0003);
515   i += aimutil_put16(tx->data+i, 0x000c);
516   i += aimutil_put16(tx->data+i, 0x0000);
517   i += aimutil_put16(tx->data+i, 0x0000);
518   i += aimutil_put16(tx->data+i, 0x0000);
519
520   i += aimutil_put8(tx->data+i, strlen(sn));
521   i += aimutil_putstr(tx->data+i, sn, strlen(sn));
522   
523   tx->lock = 0;
524   aim_tx_enqueue(sess, tx);
525
526   return 0;
527 }
528
This page took 0.09513 seconds and 5 git commands to generate.