]> andersk Git - libfaim.git/blame - aim_info.c
- Fri Sep 1 23:34:28 UTC 2000
[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
b69540e3 28 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12+1+strlen(sn))))
5b79dc93 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
b69540e3 91u_short aim_getcap(unsigned char *capblock, int buflen)
92{
93 u_short ret = 0;
94 int y;
95 int offset = 0;
96
97 while (offset < buflen) {
98 for(y=0; y < (sizeof(aim_caps)/0x10); y++) {
99 if (memcmp(&aim_caps[y], capblock+offset, 0x10) == 0) {
100 switch(y) {
101 case 0: ret |= AIM_CAPS_BUDDYICON; break;
102 case 1: ret |= AIM_CAPS_VOICE; break;
103 case 2: ret |= AIM_CAPS_IMIMAGE; break;
104 case 3: ret |= AIM_CAPS_CHAT; break;
105 case 4: ret |= AIM_CAPS_GETFILE; break;
106 case 5: ret |= AIM_CAPS_SENDFILE; break;
107 default: ret |= 0xff00; break;
108 }
109 }
110 }
111 offset += 0x10;
112 }
113 return ret;
114}
115
116int aim_putcap(unsigned char *capblock, int buflen, u_short caps)
117{
118 int offset = 0;
119
120 if (!capblock)
121 return -1;
122
123 if ((caps & AIM_CAPS_BUDDYICON) && (offset < buflen)) {
124 memcpy(capblock+offset, aim_caps[0], sizeof(aim_caps[0]));
125 offset += sizeof(aim_caps[1]);
126 }
127 if ((caps & AIM_CAPS_VOICE) && (offset < buflen)) {
128 memcpy(capblock+offset, aim_caps[1], sizeof(aim_caps[1]));
129 offset += sizeof(aim_caps[1]);
130 }
131 if ((caps & AIM_CAPS_IMIMAGE) && (offset < buflen)) {
132 memcpy(capblock+offset, aim_caps[2], sizeof(aim_caps[2]));
133 offset += sizeof(aim_caps[2]);
134 }
135 if ((caps & AIM_CAPS_CHAT) && (offset < buflen)) {
136 memcpy(capblock+offset, aim_caps[3], sizeof(aim_caps[3]));
137 offset += sizeof(aim_caps[3]);
138 }
139 if ((caps & AIM_CAPS_GETFILE) && (offset < buflen)) {
140 memcpy(capblock+offset, aim_caps[4], sizeof(aim_caps[4]));
141 offset += sizeof(aim_caps[4]);
142 }
143 if ((caps & AIM_CAPS_SENDFILE) && (offset < buflen)) {
144 memcpy(capblock+offset, aim_caps[5], sizeof(aim_caps[5]));
145 offset += sizeof(aim_caps[5]);
146 }
147
148 return offset;
149}
150
9de3ca7e 151/*
152 * AIM is fairly regular about providing user info. This
153 * is a generic routine to extract it in its standard form.
154 */
155int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
156{
157 int i = 0;
158 int tlvcnt = 0;
159 int curtlv = 0;
160 int tlv1 = 0;
161 u_short curtype;
68ac63c2 162 int lastvalid;
9de3ca7e 163
164
165 if (!buf || !outinfo)
166 return -1;
167
168 /* Clear out old data first */
169 memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
170
171 /*
172 * Screen name. Stored as an unterminated string prepended
173 * with an unsigned byte containing its length.
174 */
68ac63c2 175 if (buf[i] < MAXSNLEN) {
176 memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
177 outinfo->sn[(int)buf[i]] = '\0';
178 } else {
179 memcpy(outinfo->sn, &(buf[i+1]), MAXSNLEN-1);
180 outinfo->sn[MAXSNLEN] = '\0';
181 }
9de3ca7e 182 i = 1 + (int)buf[i];
183
184 /*
185 * Warning Level. Stored as an unsigned short.
186 */
187 outinfo->warnlevel = aimutil_get16(&buf[i]);
188 i += 2;
189
190 /*
191 * TLV Count. Unsigned short representing the number of
192 * Type-Length-Value triples that follow.
193 */
194 tlvcnt = aimutil_get16(&buf[i]);
195 i += 2;
196
197 /*
198 * Parse out the Type-Length-Value triples as they're found.
199 */
68ac63c2 200 while (curtlv < tlvcnt) {
201 lastvalid = 1;
202 curtype = aimutil_get16(&buf[i]);
203 switch (curtype) {
204 /*
205 * Type = 0x0000: Invalid
206 *
207 * AOL has been trying to throw these in just to break us.
208 * They're real nice guys over there at AOL.
209 *
210 * Just skip the two zero bytes and continue on. (This doesn't
211 * count towards tlvcnt!)
212 */
213 case 0x0000:
214 lastvalid = 0;
215 i += 2;
216 break;
0b4acf97 217
68ac63c2 218 /*
219 * Type = 0x0001: Member Class.
220 *
221 * Specified as any of the following bitwise ORed together:
222 * 0x0001 Trial (user less than 60days)
223 * 0x0002 Unknown bit 2
224 * 0x0004 AOL Main Service user
225 * 0x0008 Unknown bit 4
226 * 0x0010 Free (AIM) user
227 * 0x0020 Away
228 *
229 * In some odd cases, we can end up with more
230 * than one of these. We only want the first,
231 * as the others may not be something we want.
232 *
233 */
234 case 0x0001:
235 if (tlv1) /* use only the first */
236 break;
237 outinfo->class = aimutil_get16(&buf[i+4]);
238 tlv1++;
239 break;
240
241 /*
242 * Type = 0x0002: Member-Since date.
243 *
244 * The time/date that the user originally
245 * registered for the service, stored in
246 * time_t format
247 */
248 case 0x0002:
249 outinfo->membersince = aimutil_get32(&buf[i+4]);
250 break;
251
252 /*
253 * Type = 0x0003: On-Since date.
254 *
255 * The time/date that the user started
256 * their current session, stored in time_t
257 * format.
258 */
259 case 0x0003:
260 outinfo->onlinesince = aimutil_get32(&buf[i+4]);
261 break;
262
263 /*
264 * Type = 0x0004: Idle time.
265 *
266 * Number of seconds since the user
267 * actively used the service.
268 */
269 case 0x0004:
270 outinfo->idletime = aimutil_get16(&buf[i+4]);
271 break;
272
273 /*
274 * Type = 0x000d
275 *
276 * Capability information. Not real sure of
277 * actual decoding. See comment on aim_bos_setprofile()
278 * in aim_misc.c about the capability block, its the same.
279 *
280 */
281 case 0x000d:
282 {
283 int len;
284 len = aimutil_get16(buf+i+2);
285 if (!len)
9de3ca7e 286 break;
68ac63c2 287
288 outinfo->capabilities = aim_getcap(buf+i+4, len);
289 }
290 break;
291
292 /*
293 * Type = 0x000e
294 *
295 * Unknown. Always of zero length, and always only
296 * on AOL users.
297 *
298 * Ignore.
299 *
300 */
301 case 0x000e:
302 break;
303
304 /*
305 * Type = 0x000f: Session Length. (AIM)
306 * Type = 0x0010: Session Length. (AOL)
307 *
308 * The duration, in seconds, of the user's
309 * current session.
310 *
311 * Which TLV type this comes in depends
312 * on the service the user is using (AIM or AOL).
313 *
314 */
315 case 0x000f:
316 case 0x0010:
317 outinfo->sessionlen = aimutil_get32(&buf[i+4]);
318 break;
319
320 /*
321 * Reaching here indicates that either AOL has
322 * added yet another TLV for us to deal with,
323 * or the parsing has gone Terribly Wrong.
324 *
325 * Either way, inform the owner and attempt
326 * recovery.
327 *
328 */
329 default:
330 {
331 int len,z = 0, y = 0, x = 0;
332 char tmpstr[80];
333 printf("faim: userinfo: **warning: unexpected TLV:\n");
334 printf("faim: userinfo: sn =%s\n", outinfo->sn);
335 printf("faim: userinfo: curtlv=0x%04x\n", curtlv);
336 printf("faim: userinfo: type =0x%04x\n",aimutil_get16(&buf[i]));
337 printf("faim: userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
338 printf("faim: userinfo: data: \n");
339 while (z<len)
9de3ca7e 340 {
68ac63c2 341 x = sprintf(tmpstr, "faim: userinfo: ");
342 for (y = 0; y < 8; y++)
9de3ca7e 343 {
68ac63c2 344 if (z<len)
9de3ca7e 345 {
68ac63c2 346 sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
347 z++;
348 x += 3;
9de3ca7e 349 }
68ac63c2 350 else
351 break;
9de3ca7e 352 }
68ac63c2 353 printf("%s\n", tmpstr);
9de3ca7e 354 }
68ac63c2 355 }
356 break;
357 }
358 /*
359 * No matter what, TLV triplets should always look like this:
360 *
361 * u_short type;
362 * u_short length;
363 * u_char data[length];
364 *
365 */
366 if (lastvalid) {
367 i += (2 + 2 + aimutil_get16(&buf[i+2]));
9de3ca7e 368 curtlv++;
369 }
68ac63c2 370 }
9de3ca7e 371
372 return i;
373}
374
375/*
376 * Oncoming Buddy notifications contain a subset of the
377 * user information structure. Its close enough to run
378 * through aim_extractuserinfo() however.
379 *
380 */
a25832e6 381int aim_parse_oncoming_middle(struct aim_session_t *sess,
382 struct command_rx_struct *command)
9de3ca7e 383{
384 struct aim_userinfo_s userinfo;
385 u_int i = 0;
386 rxcallback_t userfunc=NULL;
387
388 i = 10;
389 i += aim_extractuserinfo(command->data+i, &userinfo);
390
391 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
392 if (userfunc)
a25832e6 393 i = userfunc(sess, command, &userinfo);
9de3ca7e 394
395 return 1;
396}
397
a25832e6 398/*
399 * Offgoing Buddy notifications contain no useful
400 * information other than the name it applies to.
401 *
402 */
403int aim_parse_offgoing_middle(struct aim_session_t *sess,
404 struct command_rx_struct *command)
405{
406 char sn[MAXSNLEN+1];
407 u_int i = 0;
408 rxcallback_t userfunc=NULL;
409
1a7c2214 410 strncpy(sn, command->data+11, (int)command->data[10]);
411 sn[(int)command->data[10]] = '\0';
a25832e6 412
413 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
414 if (userfunc)
415 i = userfunc(sess, command, sn);
416
417 return 1;
418}
9de3ca7e 419
420/*
421 * This parses the user info stuff out all nice and pretty then calls
422 * the higher-level callback (in the user app).
423 *
424 */
a25832e6 425int aim_parse_userinfo_middle(struct aim_session_t *sess,
426 struct command_rx_struct *command)
9de3ca7e 427{
428 struct aim_userinfo_s userinfo;
262272cc 429 char *text_encoding = NULL;
430 char *text = NULL;
9de3ca7e 431 u_int i = 0;
432 rxcallback_t userfunc=NULL;
0c20631f 433 struct aim_tlvlist_t *tlvlist;
262272cc 434 struct aim_snac_t *origsnac = NULL;
435 u_long snacid;
436 struct aim_priv_inforeq *inforeq;
437
438 snacid = aimutil_get32(&command->data[6]);
439 origsnac = aim_remsnac(sess, snacid);
9de3ca7e 440
262272cc 441 if (!origsnac || !origsnac->data) {
442 printf("faim: parse_userinfo_middle: major problem: no snac stored!\n");
443 return 1;
9de3ca7e 444 }
9de3ca7e 445
262272cc 446 inforeq = (struct aim_priv_inforeq *)origsnac->data;
447
448 switch (inforeq->infotype) {
449 case AIM_GETINFO_GENERALINFO:
450 case AIM_GETINFO_AWAYMESSAGE:
451 i = 10;
452
453 /*
454 * extractuserinfo will give us the basic metaTLV information
455 */
456 i += aim_extractuserinfo(command->data+i, &userinfo);
0c20631f 457
262272cc 458 /*
459 * However, in this command, there's usually more TLVs following...
460 */
461 tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
462
463 /*
464 * Depending on what informational text was requested, different
465 * TLVs will appear here.
466 *
467 * Profile will be 1 and 2, away message will be 3 and 4.
468 */
469 if (aim_gettlv(tlvlist, 0x0001, 1)) {
470 text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
471 text = aim_gettlv_str(tlvlist, 0x0002, 1);
472 } else if (aim_gettlv(tlvlist, 0x0003, 1)) {
473 text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
474 text = aim_gettlv_str(tlvlist, 0x0004, 1);
475 }
9de3ca7e 476
262272cc 477 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
478 if (userfunc) {
a25832e6 479 i = userfunc(sess,
480 command,
9de3ca7e 481 &userinfo,
262272cc 482 text_encoding,
483 text,
484 inforeq->infotype);
9de3ca7e 485 }
0c20631f 486
262272cc 487 free(text_encoding);
488 free(text);
489 aim_freetlvchain(&tlvlist);
490 break;
491 default:
492 printf("faim: parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype);
493 break;
494 }
495
496 if (origsnac) {
497 if (origsnac->data)
498 free(origsnac->data);
499 free(origsnac);
500 }
9de3ca7e 501
502 return 1;
503}
50443ea0 504
505/*
506 * Inverse of aim_extractuserinfo()
507 */
508int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info)
509{
510 int i = 0;
511 struct aim_tlvlist_t *tlvlist = NULL;
512
513 if (!buf || !info)
514 return 0;
515
516 i += aimutil_put8(buf+i, strlen(info->sn));
517 i += aimutil_putstr(buf+i, info->sn, strlen(info->sn));
518
519 i += aimutil_put16(buf+i, info->warnlevel);
520
521 /* XXX: we only put down five */
522 i += aimutil_put16(buf+i, 5);
523 aim_addtlvtochain16(&tlvlist, 0x0001, info->class);
524 aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
525 aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
526 aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
527 /* XXX: should put caps here */
528 aim_addtlvtochain32(&tlvlist, (info->class)&AIM_CLASS_AOL?0x0010:0x000f, info->sessionlen);
529
530 i += aim_writetlvchain(buf+i, buflen-i, &tlvlist);
531 aim_freetlvchain(&tlvlist);
532
533 return i;
534}
535
536int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
537{
5b79dc93 538 struct command_tx_struct *tx;
50443ea0 539 int i = 0;
540
541 if (!sess || !conn || !info)
542 return 0;
543
b69540e3 544 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
5b79dc93 545 return -1;
50443ea0 546
5b79dc93 547 tx->lock = 1;
50443ea0 548
5b79dc93 549 i += aimutil_put16(tx->data+i, 0x0003);
550 i += aimutil_put16(tx->data+i, 0x000b);
551 i += aimutil_put16(tx->data+i, 0x0000);
552 i += aimutil_put16(tx->data+i, 0x0000);
553 i += aimutil_put16(tx->data+i, 0x0000);
50443ea0 554
5b79dc93 555 i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
50443ea0 556
5b79dc93 557 tx->commandlen = i;
558 tx->lock = 0;
559 aim_tx_enqueue(sess, tx);
50443ea0 560
561 return 0;
562}
563
564int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
565{
5b79dc93 566 struct command_tx_struct *tx;
50443ea0 567 int i = 0;
568
569 if (!sess || !conn || !sn)
570 return 0;
571
b69540e3 572 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
5b79dc93 573 return -1;
50443ea0 574
5b79dc93 575 tx->lock = 1;
50443ea0 576
5b79dc93 577 i += aimutil_put16(tx->data+i, 0x0003);
578 i += aimutil_put16(tx->data+i, 0x000c);
579 i += aimutil_put16(tx->data+i, 0x0000);
580 i += aimutil_put16(tx->data+i, 0x0000);
581 i += aimutil_put16(tx->data+i, 0x0000);
50443ea0 582
5b79dc93 583 i += aimutil_put8(tx->data+i, strlen(sn));
584 i += aimutil_putstr(tx->data+i, sn, strlen(sn));
50443ea0 585
5b79dc93 586 tx->lock = 0;
587 aim_tx_enqueue(sess, tx);
50443ea0 588
589 return 0;
590}
262272cc 591
This page took 0.22401 seconds and 5 git commands to generate.