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