4 * The functions here are responsible for requesting and parsing information-
12 u_long aim_getinfo(struct aim_session_t *sess,
13 struct aim_conn_t *conn,
16 struct command_tx_struct *newpacket;
19 if (!sess || !conn || !sn)
22 if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn))))
27 i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid);
29 i += aimutil_put16(newpacket->data+i, 0x0001);
30 i += aimutil_put8(newpacket->data+i, strlen(sn));
31 i += aimutil_putstr(newpacket->data+i, sn, strlen(sn));
34 aim_tx_enqueue(sess, newpacket);
37 struct aim_snac_t snac;
39 snac.id = sess->snac_nextid;
44 snac.data = malloc(strlen(sn)+1);
45 strcpy(snac.data, sn);
47 aim_newsnac(sess, &snac);
50 return (sess->snac_nextid++);
57 u_char aim_caps[6][16] = {
60 {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1,
61 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
64 {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
65 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
68 {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
69 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
72 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
73 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
76 {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
77 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
80 {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1,
81 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
85 * AIM is fairly regular about providing user info. This
86 * is a generic routine to extract it in its standard form.
88 int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
100 /* Clear out old data first */
101 memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
104 * Screen name. Stored as an unterminated string prepended
105 * with an unsigned byte containing its length.
107 memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
108 outinfo->sn[(int)buf[i]] = '\0';
112 * Warning Level. Stored as an unsigned short.
114 outinfo->warnlevel = aimutil_get16(&buf[i]);
118 * TLV Count. Unsigned short representing the number of
119 * Type-Length-Value triples that follow.
121 tlvcnt = aimutil_get16(&buf[i]);
125 * Parse out the Type-Length-Value triples as they're found.
127 while (curtlv < tlvcnt)
129 curtype = aimutil_get16(&buf[i]);
133 * Type = 0x0001: Member Class.
135 * Specified as any of the following bitwise ORed together:
136 * 0x0001 Trial (user less than 60days)
137 * 0x0002 Unknown bit 2
138 * 0x0004 AOL Main Service user
139 * 0x0008 Unknown bit 4
140 * 0x0010 Free (AIM) user
143 * In some odd cases, we can end up with more
144 * than one of these. We only want the first,
145 * as the others may not be something we want.
149 if (tlv1) /* use only the first */
151 outinfo->class = aimutil_get16(&buf[i+4]);
156 * Type = 0x0002: Member-Since date.
158 * The time/date that the user originally
159 * registered for the service, stored in
163 outinfo->membersince = aimutil_get32(&buf[i+4]);
167 * Type = 0x0003: On-Since date.
169 * The time/date that the user started
170 * their current session, stored in time_t
174 outinfo->onlinesince = aimutil_get32(&buf[i+4]);
178 * Type = 0x0004: Idle time.
180 * Number of seconds since the user
181 * actively used the service.
184 outinfo->idletime = aimutil_get16(&buf[i+4]);
190 * Capability information. Not real sure of
191 * actual decoding. See comment on aim_bos_setprofile()
192 * in aim_misc.c about the capability block, its the same.
201 len = aimutil_get16(buf+i+2);
205 for (z = 0; z < len; z+=0x10) {
206 for(y=0; y < 6; y++) {
207 if (memcmp(&aim_caps[y], buf+i+4+z, 0x10) == 0) {
209 case 0: outinfo->capabilities |= AIM_CAPS_BUDDYICON; break;
210 case 1: outinfo->capabilities |= AIM_CAPS_VOICE; break;
211 case 2: outinfo->capabilities |= AIM_CAPS_IMIMAGE; break;
212 case 3: outinfo->capabilities |= AIM_CAPS_CHAT; break;
213 case 4: outinfo->capabilities |= AIM_CAPS_GETFILE; break;
214 case 5: outinfo->capabilities |= AIM_CAPS_SENDFILE; break;
215 default: outinfo->capabilities |= 0xff00; break;
226 * Unknown. Always of zero length, and always only
236 * Type = 0x000f: Session Length. (AIM)
237 * Type = 0x0010: Session Length. (AOL)
239 * The duration, in seconds, of the user's
242 * Which TLV type this comes in depends
243 * on the service the user is using (AIM or AOL).
248 outinfo->sessionlen = aimutil_get32(&buf[i+4]);
252 * Reaching here indicates that either AOL has
253 * added yet another TLV for us to deal with,
254 * or the parsing has gone Terribly Wrong.
256 * Either way, inform the owner and attempt
262 int len,z = 0, y = 0, x = 0;
264 printf("faim: userinfo: **warning: unexpected TLV:\n");
265 printf("faim: userinfo: sn =%s\n", outinfo->sn);
266 printf("faim: userinfo: curtlv=0x%04x\n", curtlv);
267 printf("faim: userinfo: type =0x%04x\n",aimutil_get16(&buf[i]));
268 printf("faim: userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
269 printf("faim: userinfo: data: \n");
272 x = sprintf(tmpstr, "faim: userinfo: ");
273 for (y = 0; y < 8; y++)
277 sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
284 printf("%s\n", tmpstr);
290 * No matter what, TLV triplets should always look like this:
294 * u_char data[length];
297 i += (2 + 2 + aimutil_get16(&buf[i+2]));
306 * Oncoming Buddy notifications contain a subset of the
307 * user information structure. Its close enough to run
308 * through aim_extractuserinfo() however.
311 int aim_parse_oncoming_middle(struct aim_session_t *sess,
312 struct command_rx_struct *command)
314 struct aim_userinfo_s userinfo;
316 rxcallback_t userfunc=NULL;
319 i += aim_extractuserinfo(command->data+i, &userinfo);
321 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
323 i = userfunc(sess, command, &userinfo);
329 * Offgoing Buddy notifications contain no useful
330 * information other than the name it applies to.
333 int aim_parse_offgoing_middle(struct aim_session_t *sess,
334 struct command_rx_struct *command)
338 rxcallback_t userfunc=NULL;
340 strncpy(sn, command->data+11, (int)command->data[10]);
341 sn[(int)command->data[10]] = '\0';
343 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING);
345 i = userfunc(sess, command, sn);
351 * This parses the user info stuff out all nice and pretty then calls
352 * the higher-level callback (in the user app).
355 int aim_parse_userinfo_middle(struct aim_session_t *sess,
356 struct command_rx_struct *command)
358 struct aim_userinfo_s userinfo;
359 char *prof_encoding = NULL;
362 rxcallback_t userfunc=NULL;
363 struct aim_tlvlist_t *tlvlist;
366 u_long snacid = 0x000000000;
367 struct aim_snac_t *snac = NULL;
369 snacid = aimutil_get32(&command->data[6]);
370 snac = aim_remsnac(sess, snacid);
377 printf("faim: parse_userinfo_middle: warning: no ->data in cached SNAC\n");
381 printf("faim: parseuserinfo_middle: warning: no SNAC cached with for this response (%08lx)\n", snacid);
388 * extractuserinfo will give us the basic metaTLV information
390 i += aim_extractuserinfo(command->data+i, &userinfo);
393 * However, in this command, there's usually more TLVs following...
395 tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
396 prof_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
397 prof = aim_gettlv_str(tlvlist, 0x0002, 1);
399 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
411 aim_freetlvchain(&tlvlist);
417 * Inverse of aim_extractuserinfo()
419 int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info)
422 struct aim_tlvlist_t *tlvlist = NULL;
427 i += aimutil_put8(buf+i, strlen(info->sn));
428 i += aimutil_putstr(buf+i, info->sn, strlen(info->sn));
430 i += aimutil_put16(buf+i, info->warnlevel);
432 /* XXX: we only put down five */
433 i += aimutil_put16(buf+i, 5);
434 aim_addtlvtochain16(&tlvlist, 0x0001, info->class);
435 aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
436 aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
437 aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
438 /* XXX: should put caps here */
439 aim_addtlvtochain32(&tlvlist, (info->class)&AIM_CLASS_AOL?0x0010:0x000f, info->sessionlen);
441 i += aim_writetlvchain(buf+i, buflen-i, &tlvlist);
442 aim_freetlvchain(&tlvlist);
447 int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info)
449 struct command_tx_struct *tx;
452 if (!sess || !conn || !info)
455 if (!(tx = aim_tx_new(0x0002, conn, 1152)))
460 i += aimutil_put16(tx->data+i, 0x0003);
461 i += aimutil_put16(tx->data+i, 0x000b);
462 i += aimutil_put16(tx->data+i, 0x0000);
463 i += aimutil_put16(tx->data+i, 0x0000);
464 i += aimutil_put16(tx->data+i, 0x0000);
466 i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info);
470 aim_tx_enqueue(sess, tx);
475 int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn)
477 struct command_tx_struct *tx;
480 if (!sess || !conn || !sn)
483 if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
488 i += aimutil_put16(tx->data+i, 0x0003);
489 i += aimutil_put16(tx->data+i, 0x000c);
490 i += aimutil_put16(tx->data+i, 0x0000);
491 i += aimutil_put16(tx->data+i, 0x0000);
492 i += aimutil_put16(tx->data+i, 0x0000);
494 i += aimutil_put8(tx->data+i, strlen(sn));
495 i += aimutil_putstr(tx->data+i, sn, strlen(sn));
498 aim_tx_enqueue(sess, tx);