4 * The functions here are responsible for requesting and parsing information-
12 struct aim_priv_inforeq {
14 unsigned short infotype;
17 u_long aim_getinfo(struct aim_session_t *sess,
18 struct aim_conn_t *conn,
20 unsigned short infotype)
22 struct command_tx_struct *newpacket;
25 if (!sess || !conn || !sn)
28 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12+1+strlen(sn))))
33 i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid);
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));
40 aim_tx_enqueue(sess, newpacket);
43 struct aim_snac_t snac;
45 snac.id = sess->snac_nextid;
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;
54 aim_newsnac(sess, &snac);
57 return (sess->snac_nextid++);
64 u_char aim_caps[6][16] = {
67 {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1,
68 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
71 {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
72 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
75 {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
76 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
79 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
80 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
83 {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
84 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
87 {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1,
88 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
91 u_short aim_getcap(unsigned char *capblock, int buflen)
97 while (offset < buflen) {
98 for(y=0; y < (sizeof(aim_caps)/0x10); y++) {
99 if (memcmp(&aim_caps[y], capblock+offset, 0x10) == 0) {
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;
116 int aim_putcap(unsigned char *capblock, int buflen, u_short caps)
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]);
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]);
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]);
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]);
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]);
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]);
152 * AIM is fairly regular about providing user info. This
153 * is a generic routine to extract it in its standard form.
155 int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
165 if (!buf || !outinfo)
168 /* Clear out old data first */
169 memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
172 * Screen name. Stored as an unterminated string prepended
173 * with an unsigned byte containing its length.
175 if (buf[i] < MAXSNLEN) {
176 memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
177 outinfo->sn[(int)buf[i]] = '\0';
179 memcpy(outinfo->sn, &(buf[i+1]), MAXSNLEN-1);
180 outinfo->sn[MAXSNLEN] = '\0';
185 * Warning Level. Stored as an unsigned short.
187 outinfo->warnlevel = aimutil_get16(&buf[i]);
191 * TLV Count. Unsigned short representing the number of
192 * Type-Length-Value triples that follow.
194 tlvcnt = aimutil_get16(&buf[i]);
198 * Parse out the Type-Length-Value triples as they're found.
200 while (curtlv < tlvcnt) {
202 curtype = aimutil_get16(&buf[i]);
205 * Type = 0x0000: Invalid
207 * AOL has been trying to throw these in just to break us.
208 * They're real nice guys over there at AOL.
210 * Just skip the two zero bytes and continue on. (This doesn't
211 * count towards tlvcnt!)
219 * Type = 0x0001: Member Class.
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
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.
235 if (tlv1) /* use only the first */
237 outinfo->class = aimutil_get16(&buf[i+4]);
242 * Type = 0x0002: Member-Since date.
244 * The time/date that the user originally
245 * registered for the service, stored in
249 outinfo->membersince = aimutil_get32(&buf[i+4]);
253 * Type = 0x0003: On-Since date.
255 * The time/date that the user started
256 * their current session, stored in time_t
260 outinfo->onlinesince = aimutil_get32(&buf[i+4]);
264 * Type = 0x0004: Idle time.
266 * Number of seconds since the user
267 * actively used the service.
270 outinfo->idletime = aimutil_get16(&buf[i+4]);
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.
284 len = aimutil_get16(buf+i+2);
288 outinfo->capabilities = aim_getcap(buf+i+4, len);
295 * Unknown. Always of zero length, and always only
305 * Type = 0x000f: Session Length. (AIM)
306 * Type = 0x0010: Session Length. (AOL)
308 * The duration, in seconds, of the user's
311 * Which TLV type this comes in depends
312 * on the service the user is using (AIM or AOL).
317 outinfo->sessionlen = aimutil_get32(&buf[i+4]);
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.
325 * Either way, inform the owner and attempt
331 int len,z = 0, y = 0, x = 0;
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");
341 x = sprintf(tmpstr, "faim: userinfo: ");
342 for (y = 0; y < 8; y++)
346 sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
353 printf("%s\n", tmpstr);
359 * No matter what, TLV triplets should always look like this:
363 * u_char data[length];
367 i += (2 + 2 + aimutil_get16(&buf[i+2]));
376 * Oncoming Buddy notifications contain a subset of the
377 * user information structure. Its close enough to run
378 * through aim_extractuserinfo() however.
381 int aim_parse_oncoming_middle(struct aim_session_t *sess,
382 struct command_rx_struct *command)
384 struct aim_userinfo_s userinfo;
386 rxcallback_t userfunc=NULL;
389 i += aim_extractuserinfo(command->data+i, &userinfo);
391 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
393 i = userfunc(sess, command, &userinfo);
399 * Offgoing Buddy notifications contain no useful
400 * information other than the name it applies to.
403 int aim_parse_offgoing_middle(struct aim_session_t *sess,
404 struct command_rx_struct *command)
408 rxcallback_t userfunc=NULL;
410 strncpy(sn, command->data+11, (int)command->data[10]);
411 sn[(int)command->data[10]] = '\0';
413 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
415 i = userfunc(sess, command, sn);
421 * This parses the user info stuff out all nice and pretty then calls
422 * the higher-level callback (in the user app).
425 int aim_parse_userinfo_middle(struct aim_session_t *sess,
426 struct command_rx_struct *command)
428 struct aim_userinfo_s userinfo;
429 char *text_encoding = NULL;
432 rxcallback_t userfunc=NULL;
433 struct aim_tlvlist_t *tlvlist;
434 struct aim_snac_t *origsnac = NULL;
436 struct aim_priv_inforeq *inforeq;
438 snacid = aimutil_get32(&command->data[6]);
439 origsnac = aim_remsnac(sess, snacid);
441 if (!origsnac || !origsnac->data) {
442 printf("faim: parse_userinfo_middle: major problem: no snac stored!\n");
446 inforeq = (struct aim_priv_inforeq *)origsnac->data;
448 switch (inforeq->infotype) {
449 case AIM_GETINFO_GENERALINFO:
450 case AIM_GETINFO_AWAYMESSAGE:
454 * extractuserinfo will give us the basic metaTLV information
456 i += aim_extractuserinfo(command->data+i, &userinfo);
459 * However, in this command, there's usually more TLVs following...
461 tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
464 * Depending on what informational text was requested, different
465 * TLVs will appear here.
467 * Profile will be 1 and 2, away message will be 3 and 4.
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);
477 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
489 aim_freetlvchain(&tlvlist);
492 printf("faim: parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype);
498 free(origsnac->data);
506 * Inverse of aim_extractuserinfo()
508 int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info)
511 struct aim_tlvlist_t *tlvlist = NULL;
516 i += aimutil_put8(buf+i, strlen(info->sn));
517 i += aimutil_putstr(buf+i, info->sn, strlen(info->sn));
519 i += aimutil_put16(buf+i, info->warnlevel);
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);
530 i += aim_writetlvchain(buf+i, buflen-i, &tlvlist);
531 aim_freetlvchain(&tlvlist);
536 int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
538 struct command_tx_struct *tx;
541 if (!sess || !conn || !info)
544 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
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);
555 i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
559 aim_tx_enqueue(sess, tx);
564 int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
566 struct command_tx_struct *tx;
569 if (!sess || !conn || !sn)
572 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
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);
583 i += aimutil_put8(tx->data+i, strlen(sn));
584 i += aimutil_putstr(tx->data+i, sn, strlen(sn));
587 aim_tx_enqueue(sess, tx);