]> andersk Git - libfaim.git/blame - aim_info.c
Locking around tx seqnum.
[libfaim.git] / aim_info.c
CommitLineData
9de3ca7e 1/*
2 * aim_info.c
3 *
4 * The functions here are responsible for requesting and parsing information-
5 * gathering SNACs.
6 *
7 */
8
9
a25832e6 10#include <faim/aim.h>
9de3ca7e 11
262272cc 12struct aim_priv_inforeq {
13 char sn[MAXSNLEN];
14 unsigned short infotype;
15};
16
a25832e6 17u_long aim_getinfo(struct aim_session_t *sess,
18 struct aim_conn_t *conn,
262272cc 19 const char *sn,
20 unsigned short infotype)
9de3ca7e 21{
5b79dc93 22 struct command_tx_struct *newpacket;
276495a3 23 int i = 0;
24
25 if (!sess || !conn || !sn)
26 return 0;
9de3ca7e 27
5b79dc93 28 if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn))))
29 return -1;
9de3ca7e 30
5b79dc93 31 newpacket->lock = 1;
9de3ca7e 32
5b79dc93 33 i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid);
9de3ca7e 34
262272cc 35 i += aimutil_put16(newpacket->data+i, infotype);
5b79dc93 36 i += aimutil_put8(newpacket->data+i, strlen(sn));
37 i += aimutil_putstr(newpacket->data+i, sn, strlen(sn));
9de3ca7e 38
5b79dc93 39 newpacket->lock = 0;
40 aim_tx_enqueue(sess, newpacket);
9de3ca7e 41
42 {
43 struct aim_snac_t snac;
44
a25832e6 45 snac.id = sess->snac_nextid;
9de3ca7e 46 snac.family = 0x0002;
47 snac.type = 0x0005;
48 snac.flags = 0x0000;
49
262272cc 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;
9de3ca7e 53
a25832e6 54 aim_newsnac(sess, &snac);
9de3ca7e 55 }
56
a25832e6 57 return (sess->snac_nextid++);
9de3ca7e 58}
59
5b79dc93 60
61/*
62 * Capability blocks.
63 */
64u_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
9de3ca7e 91/*
92 * AIM is fairly regular about providing user info. This
93 * is a generic routine to extract it in its standard form.
94 */
95int 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
0c20631f 148 * 0x0020 Away
9de3ca7e 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;
0b4acf97 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:
5b79dc93 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 }
0b4acf97 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;
9de3ca7e 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 */
a25832e6 318int aim_parse_oncoming_middle(struct aim_session_t *sess,
319 struct command_rx_struct *command)
9de3ca7e 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)
a25832e6 330 i = userfunc(sess, command, &userinfo);
9de3ca7e 331
332 return 1;
333}
334
a25832e6 335/*
336 * Offgoing Buddy notifications contain no useful
337 * information other than the name it applies to.
338 *
339 */
340int 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
1a7c2214 347 strncpy(sn, command->data+11, (int)command->data[10]);
348 sn[(int)command->data[10]] = '\0';
a25832e6 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}
9de3ca7e 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 */
a25832e6 362int aim_parse_userinfo_middle(struct aim_session_t *sess,
363 struct command_rx_struct *command)
9de3ca7e 364{
365 struct aim_userinfo_s userinfo;
262272cc 366 char *text_encoding = NULL;
367 char *text = NULL;
9de3ca7e 368 u_int i = 0;
369 rxcallback_t userfunc=NULL;
0c20631f 370 struct aim_tlvlist_t *tlvlist;
262272cc 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);
9de3ca7e 377
262272cc 378 if (!origsnac || !origsnac->data) {
379 printf("faim: parse_userinfo_middle: major problem: no snac stored!\n");
380 return 1;
9de3ca7e 381 }
9de3ca7e 382
262272cc 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);
0c20631f 394
262272cc 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 }
9de3ca7e 413
262272cc 414 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
415 if (userfunc) {
a25832e6 416 i = userfunc(sess,
417 command,
9de3ca7e 418 &userinfo,
262272cc 419 text_encoding,
420 text,
421 inforeq->infotype);
9de3ca7e 422 }
0c20631f 423
262272cc 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 }
9de3ca7e 438
439 return 1;
440}
50443ea0 441
442/*
443 * Inverse of aim_extractuserinfo()
444 */
445int 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
473int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
474{
5b79dc93 475 struct command_tx_struct *tx;
50443ea0 476 int i = 0;
477
478 if (!sess || !conn || !info)
479 return 0;
480
5b79dc93 481 if (!(tx = aim_tx_new(0x0002, conn, 1152)))
482 return -1;
50443ea0 483
5b79dc93 484 tx->lock = 1;
50443ea0 485
5b79dc93 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);
50443ea0 491
5b79dc93 492 i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
50443ea0 493
5b79dc93 494 tx->commandlen = i;
495 tx->lock = 0;
496 aim_tx_enqueue(sess, tx);
50443ea0 497
498 return 0;
499}
500
501int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
502{
5b79dc93 503 struct command_tx_struct *tx;
50443ea0 504 int i = 0;
505
506 if (!sess || !conn || !sn)
507 return 0;
508
5b79dc93 509 if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
510 return -1;
50443ea0 511
5b79dc93 512 tx->lock = 1;
50443ea0 513
5b79dc93 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);
50443ea0 519
5b79dc93 520 i += aimutil_put8(tx->data+i, strlen(sn));
521 i += aimutil_putstr(tx->data+i, sn, strlen(sn));
50443ea0 522
5b79dc93 523 tx->lock = 0;
524 aim_tx_enqueue(sess, tx);
50443ea0 525
526 return 0;
527}
262272cc 528
This page took 0.124531 seconds and 5 git commands to generate.