]> andersk Git - libfaim.git/blob - aim_info.c
Stupid bug.
[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
18   if (conn)
19     newpacket.conn = conn;
20   else
21     newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
22
23   newpacket.lock = 1;
24   newpacket.type = 0x0002;
25
26   newpacket.commandlen = 12 + 1 + strlen(sn);
27   newpacket.data = (char *) malloc(newpacket.commandlen);
28
29   aim_putsnac(newpacket.data, 0x0002, 0x0005, 0x0000, sess->snac_nextid);
30
31   aimutil_put16(newpacket.data+10, 0x0001);
32   aimutil_put8(newpacket.data+12, strlen(sn));
33   aimutil_putstr(newpacket.data+13, sn, strlen(sn));
34
35   aim_tx_enqueue(sess, &newpacket);
36
37   {
38     struct aim_snac_t snac;
39     
40     snac.id = sess->snac_nextid;
41     snac.family = 0x0002;
42     snac.type = 0x0005;
43     snac.flags = 0x0000;
44
45     snac.data = malloc(strlen(sn)+1);
46     memcpy(snac.data, sn, strlen(sn)+1);
47
48     aim_newsnac(sess, &snac);
49   }
50
51   return (sess->snac_nextid++);
52 }
53
54 /*
55  * AIM is fairly regular about providing user info.  This
56  * is a generic routine to extract it in its standard form.
57  */
58 int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
59 {
60   int i = 0;
61   int tlvcnt = 0;
62   int curtlv = 0;
63   int tlv1 = 0;
64   u_short curtype;
65
66
67   if (!buf || !outinfo)
68     return -1;
69
70   /* Clear out old data first */
71   memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
72
73   /*
74    * Screen name.    Stored as an unterminated string prepended
75    *                 with an unsigned byte containing its length.
76    */
77   memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
78   outinfo->sn[(int)buf[i]] = '\0';
79   i = 1 + (int)buf[i];
80
81   /*
82    * Warning Level.  Stored as an unsigned short.
83    */
84   outinfo->warnlevel = aimutil_get16(&buf[i]);
85   i += 2;
86
87   /*
88    * TLV Count.      Unsigned short representing the number of 
89    *                 Type-Length-Value triples that follow.
90    */
91   tlvcnt = aimutil_get16(&buf[i]);
92   i += 2;
93
94   /* 
95    * Parse out the Type-Length-Value triples as they're found.
96    */
97   while (curtlv < tlvcnt)
98     {
99       curtype = aimutil_get16(&buf[i]);
100       switch (curtype)
101         {
102           /*
103            * Type = 0x0001: Member Class.   
104            * 
105            * Specified as any of the following bitwise ORed together:
106            *      0x0001  Trial (user less than 60days)
107            *      0x0002  Unknown bit 2
108            *      0x0004  AOL Main Service user
109            *      0x0008  Unknown bit 4
110            *      0x0010  Free (AIM) user 
111            *
112            * In some odd cases, we can end up with more
113            * than one of these.  We only want the first,
114            * as the others may not be something we want.
115            *
116            */
117         case 0x0001:
118           if (tlv1) /* use only the first */
119             break;
120           outinfo->class = aimutil_get16(&buf[i+4]);
121           tlv1++;
122           break;
123           
124           /*
125            * Type = 0x0002: Member-Since date. 
126            *
127            * The time/date that the user originally
128            * registered for the service, stored in 
129            * time_t format
130            */
131         case 0x0002: 
132           outinfo->membersince = aimutil_get32(&buf[i+4]);
133           break;
134           
135           /*
136            * Type = 0x0003: On-Since date.
137            *
138            * The time/date that the user started 
139            * their current session, stored in time_t
140            * format.
141            */
142         case 0x0003:
143           outinfo->onlinesince = aimutil_get32(&buf[i+4]);
144           break;
145
146           /*
147            * Type = 0x0004: Idle time.
148            *
149            * Number of seconds since the user
150            * actively used the service.
151            */
152         case 0x0004:
153           outinfo->idletime = aimutil_get16(&buf[i+4]);
154           break;
155           
156           /*
157            * Type = 0x000f: Session Length. (AIM)
158            * Type = 0x0010: Session Length. (AOL)
159            *
160            * The duration, in seconds, of the user's
161            * current session.
162            *
163            * Which TLV type this comes in depends
164            * on the service the user is using (AIM or AOL).
165            *
166            */
167         case 0x000f:
168         case 0x0010:
169           outinfo->sessionlen = aimutil_get32(&buf[i+4]);
170           break;
171
172           /*
173            * Reaching here indicates that either AOL has
174            * added yet another TLV for us to deal with, 
175            * or the parsing has gone Terribly Wrong.
176            *
177            * Either way, inform the owner and attempt
178            * recovery.
179            *
180            */
181         default:
182           {
183             int len,z = 0, y = 0, x = 0;
184             char tmpstr[80];
185             printf("faim: userinfo: **warning: unexpected TLV:\n");
186             printf("faim: userinfo:   sn    =%s\n", outinfo->sn);
187             printf("faim: userinfo:   curtlv=0x%04x\n", curtlv);
188             printf("faim: userinfo:   type  =0x%04x\n",aimutil_get16(&buf[i]));
189             printf("faim: userinfo:   length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
190             printf("faim: userinfo:   data: \n");
191             while (z<len)
192               {
193                 x = sprintf(tmpstr, "faim: userinfo:      ");
194                 for (y = 0; y < 8; y++)
195                   {
196                     if (z<len)
197                       {
198                         sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
199                         z++;
200                         x += 3;
201                       }
202                     else
203                       break;
204                   }
205                 printf("%s\n", tmpstr);
206               }
207           }
208           break;
209         }  
210       /*
211        * No matter what, TLV triplets should always look like this:
212        *
213        *   u_short type;
214        *   u_short length;
215        *   u_char  data[length];
216        *
217        */
218       i += (2 + 2 + aimutil_get16(&buf[i+2]));
219       
220       curtlv++;
221     }
222   
223   return i;
224 }
225
226 /*
227  * Oncoming Buddy notifications contain a subset of the
228  * user information structure.  Its close enough to run
229  * through aim_extractuserinfo() however.
230  *
231  */
232 int aim_parse_oncoming_middle(struct aim_session_t *sess,
233                               struct command_rx_struct *command)
234 {
235   struct aim_userinfo_s userinfo;
236   u_int i = 0;
237   rxcallback_t userfunc=NULL;
238
239   i = 10;
240   i += aim_extractuserinfo(command->data+i, &userinfo);
241
242   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
243   if (userfunc)
244     i = userfunc(sess, command, &userinfo);
245
246   return 1;
247 }
248
249 /*
250  * Offgoing Buddy notifications contain no useful
251  * information other than the name it applies to.
252  *
253  */
254 int aim_parse_offgoing_middle(struct aim_session_t *sess,
255                               struct command_rx_struct *command)
256 {
257   char sn[MAXSNLEN+1];
258   u_int i = 0;
259   rxcallback_t userfunc=NULL;
260
261   /* Protect against future SN length extensions */
262   strncpy(sn, command->data+11, (((int)(command->data+10))<=MAXSNLEN)?(int)command->data+10:MAXSNLEN);
263
264   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
265   if (userfunc)
266     i = userfunc(sess, command, sn);
267
268   return 1;
269 }
270
271 /*
272  * This parses the user info stuff out all nice and pretty then calls 
273  * the higher-level callback (in the user app).
274  *
275  */
276 int aim_parse_userinfo_middle(struct aim_session_t *sess,
277                               struct command_rx_struct *command)
278 {
279   struct aim_userinfo_s userinfo;
280   char *prof_encoding = NULL;
281   char *prof = NULL;
282   u_int i = 0;
283   rxcallback_t userfunc=NULL;
284
285   {
286     u_long snacid = 0x000000000;
287     struct aim_snac_t *snac = NULL;
288
289     snacid = aimutil_get32(&command->data[6]);
290     snac = aim_remsnac(sess, snacid);
291
292     free(snac->data);
293     free(snac);
294
295   }
296   
297   i = 10;
298   i += aim_extractuserinfo(command->data+i, &userinfo);
299
300   if (i < command->commandlen)
301     {
302       if (aimutil_get16(&command->data[i]) == 0x0001)
303         {
304           int len = 0;
305
306           len = aimutil_get16(&command->data[i+2]);
307
308           prof_encoding = (char *) malloc(len+1);
309           memcpy(prof_encoding, &(command->data[i+4]), len);
310           prof_encoding[len] = '\0';
311
312           i += (2+2+len);
313         }
314       else
315         {
316           printf("faim: userinfo: **warning: unexpected TLV after TLVblock t(%04x) l(%04x)\n", aimutil_get16(command->data+i), aimutil_get16(command->data+i+2));
317           i += 2 + 2 + command->data[i+3];
318         }
319     }
320
321   if (i < command->commandlen)
322     {
323       if (aimutil_get16(&command->data[i]) == 0x0002)
324         {
325           int len = 0;
326           len = aimutil_get16(&command->data[i+2]);
327           
328           prof = (char *) malloc(len+1);
329           memcpy(prof, &(command->data[i+4]), len);
330           prof[len] = '\0';
331         }
332       else
333         printf("faim:userinfo: **warning: profile not found, but still have data\n");
334     }
335
336   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
337   if (userfunc)
338     {
339       i = userfunc(sess,
340                    command, 
341                    &userinfo, 
342                    prof_encoding, 
343                    prof); 
344     }
345
346   free(prof_encoding);
347   free(prof);
348
349   return 1;
350 }
This page took 0.065894 seconds and 5 git commands to generate.