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)
164 if (!buf || !outinfo)
167 /* Clear out old data first */
168 memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
171 * Screen name. Stored as an unterminated string prepended
172 * with an unsigned byte containing its length.
174 memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
175 outinfo->sn[(int)buf[i]] = '\0';
179 * Warning Level. Stored as an unsigned short.
181 outinfo->warnlevel = aimutil_get16(&buf[i]);
185 * TLV Count. Unsigned short representing the number of
186 * Type-Length-Value triples that follow.
188 tlvcnt = aimutil_get16(&buf[i]);
192 * Parse out the Type-Length-Value triples as they're found.
194 while (curtlv < tlvcnt)
196 curtype = aimutil_get16(&buf[i]);
200 * Type = 0x0001: Member Class.
202 * Specified as any of the following bitwise ORed together:
203 * 0x0001 Trial (user less than 60days)
204 * 0x0002 Unknown bit 2
205 * 0x0004 AOL Main Service user
206 * 0x0008 Unknown bit 4
207 * 0x0010 Free (AIM) user
210 * In some odd cases, we can end up with more
211 * than one of these. We only want the first,
212 * as the others may not be something we want.
216 if (tlv1) /* use only the first */
218 outinfo->class = aimutil_get16(&buf[i+4]);
223 * Type = 0x0002: Member-Since date.
225 * The time/date that the user originally
226 * registered for the service, stored in
230 outinfo->membersince = aimutil_get32(&buf[i+4]);
234 * Type = 0x0003: On-Since date.
236 * The time/date that the user started
237 * their current session, stored in time_t
241 outinfo->onlinesince = aimutil_get32(&buf[i+4]);
245 * Type = 0x0004: Idle time.
247 * Number of seconds since the user
248 * actively used the service.
251 outinfo->idletime = aimutil_get16(&buf[i+4]);
257 * Capability information. Not real sure of
258 * actual decoding. See comment on aim_bos_setprofile()
259 * in aim_misc.c about the capability block, its the same.
265 len = aimutil_get16(buf+i+2);
269 outinfo->capabilities = aim_getcap(buf+i+4, len);
276 * Unknown. Always of zero length, and always only
286 * Type = 0x000f: Session Length. (AIM)
287 * Type = 0x0010: Session Length. (AOL)
289 * The duration, in seconds, of the user's
292 * Which TLV type this comes in depends
293 * on the service the user is using (AIM or AOL).
298 outinfo->sessionlen = aimutil_get32(&buf[i+4]);
302 * Reaching here indicates that either AOL has
303 * added yet another TLV for us to deal with,
304 * or the parsing has gone Terribly Wrong.
306 * Either way, inform the owner and attempt
312 int len,z = 0, y = 0, x = 0;
314 printf("faim: userinfo: **warning: unexpected TLV:\n");
315 printf("faim: userinfo: sn =%s\n", outinfo->sn);
316 printf("faim: userinfo: curtlv=0x%04x\n", curtlv);
317 printf("faim: userinfo: type =0x%04x\n",aimutil_get16(&buf[i]));
318 printf("faim: userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
319 printf("faim: userinfo: data: \n");
322 x = sprintf(tmpstr, "faim: userinfo: ");
323 for (y = 0; y < 8; y++)
327 sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
334 printf("%s\n", tmpstr);
340 * No matter what, TLV triplets should always look like this:
344 * u_char data[length];
347 i += (2 + 2 + aimutil_get16(&buf[i+2]));
356 * Oncoming Buddy notifications contain a subset of the
357 * user information structure. Its close enough to run
358 * through aim_extractuserinfo() however.
361 int aim_parse_oncoming_middle(struct aim_session_t *sess,
362 struct command_rx_struct *command)
364 struct aim_userinfo_s userinfo;
366 rxcallback_t userfunc=NULL;
369 i += aim_extractuserinfo(command->data+i, &userinfo);
371 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
373 i = userfunc(sess, command, &userinfo);
379 * Offgoing Buddy notifications contain no useful
380 * information other than the name it applies to.
383 int aim_parse_offgoing_middle(struct aim_session_t *sess,
384 struct command_rx_struct *command)
388 rxcallback_t userfunc=NULL;
390 strncpy(sn, command->data+11, (int)command->data[10]);
391 sn[(int)command->data[10]] = '\0';
393 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
395 i = userfunc(sess, command, sn);
401 * This parses the user info stuff out all nice and pretty then calls
402 * the higher-level callback (in the user app).
405 int aim_parse_userinfo_middle(struct aim_session_t *sess,
406 struct command_rx_struct *command)
408 struct aim_userinfo_s userinfo;
409 char *text_encoding = NULL;
412 rxcallback_t userfunc=NULL;
413 struct aim_tlvlist_t *tlvlist;
414 struct aim_snac_t *origsnac = NULL;
416 struct aim_priv_inforeq *inforeq;
418 snacid = aimutil_get32(&command->data[6]);
419 origsnac = aim_remsnac(sess, snacid);
421 if (!origsnac || !origsnac->data) {
422 printf("faim: parse_userinfo_middle: major problem: no snac stored!\n");
426 inforeq = (struct aim_priv_inforeq *)origsnac->data;
428 switch (inforeq->infotype) {
429 case AIM_GETINFO_GENERALINFO:
430 case AIM_GETINFO_AWAYMESSAGE:
434 * extractuserinfo will give us the basic metaTLV information
436 i += aim_extractuserinfo(command->data+i, &userinfo);
439 * However, in this command, there's usually more TLVs following...
441 tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
444 * Depending on what informational text was requested, different
445 * TLVs will appear here.
447 * Profile will be 1 and 2, away message will be 3 and 4.
449 if (aim_gettlv(tlvlist, 0x0001, 1)) {
450 text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
451 text = aim_gettlv_str(tlvlist, 0x0002, 1);
452 } else if (aim_gettlv(tlvlist, 0x0003, 1)) {
453 text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
454 text = aim_gettlv_str(tlvlist, 0x0004, 1);
457 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
469 aim_freetlvchain(&tlvlist);
472 printf("faim: parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype);
478 free(origsnac->data);
486 * Inverse of aim_extractuserinfo()
488 int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info)
491 struct aim_tlvlist_t *tlvlist = NULL;
496 i += aimutil_put8(buf+i, strlen(info->sn));
497 i += aimutil_putstr(buf+i, info->sn, strlen(info->sn));
499 i += aimutil_put16(buf+i, info->warnlevel);
501 /* XXX: we only put down five */
502 i += aimutil_put16(buf+i, 5);
503 aim_addtlvtochain16(&tlvlist, 0x0001, info->class);
504 aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
505 aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
506 aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
507 /* XXX: should put caps here */
508 aim_addtlvtochain32(&tlvlist, (info->class)&AIM_CLASS_AOL?0x0010:0x000f, info->sessionlen);
510 i += aim_writetlvchain(buf+i, buflen-i, &tlvlist);
511 aim_freetlvchain(&tlvlist);
516 int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
518 struct command_tx_struct *tx;
521 if (!sess || !conn || !info)
524 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
529 i += aimutil_put16(tx->data+i, 0x0003);
530 i += aimutil_put16(tx->data+i, 0x000b);
531 i += aimutil_put16(tx->data+i, 0x0000);
532 i += aimutil_put16(tx->data+i, 0x0000);
533 i += aimutil_put16(tx->data+i, 0x0000);
535 i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
539 aim_tx_enqueue(sess, tx);
544 int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
546 struct command_tx_struct *tx;
549 if (!sess || !conn || !sn)
552 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
557 i += aimutil_put16(tx->data+i, 0x0003);
558 i += aimutil_put16(tx->data+i, 0x000c);
559 i += aimutil_put16(tx->data+i, 0x0000);
560 i += aimutil_put16(tx->data+i, 0x0000);
561 i += aimutil_put16(tx->data+i, 0x0000);
563 i += aimutil_put8(tx->data+i, strlen(sn));
564 i += aimutil_putstr(tx->data+i, sn, strlen(sn));
567 aim_tx_enqueue(sess, tx);