5 * TODO: Seperate a lot of this into an aim_bos.c.
19 * Should set your current idle time in seconds. Idealy, OSCAR should
20 * do this for us. But, it doesn't. The client must call this to set idle
24 u_long aim_bos_setidle(struct aim_session_t *sess,
25 struct aim_conn_t *conn,
28 return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime);
33 * aim_bos_changevisibility(conn, changtype, namelist)
35 * Changes your visibility depending on changetype:
37 * AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you
38 * AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list
39 * AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
40 * AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
42 * list should be a list of
43 * screen names in the form "Screen Name One&ScreenNameTwo&" etc.
45 * Equivelents to options in WinAIM:
46 * - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD
47 * with only your name on it.
48 * - Allow only users on my Buddy List: Send an
49 * AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your
51 * - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD
52 * with everyone listed that you want to see you.
53 * - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only
54 * yourself in the list
55 * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with
56 * the list of users to be blocked
60 u_long aim_bos_changevisibility(struct aim_session_t *sess,
61 struct aim_conn_t *conn,
62 int changetype, char *denylist)
64 struct command_tx_struct *newpacket;
68 char *localcpy = NULL;
76 localcpy = (char *) malloc(strlen(denylist)+1);
77 memcpy(localcpy, denylist, strlen(denylist)+1);
79 listcount = aimutil_itemcnt(localcpy, '&');
80 packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
82 if (!(newpacket = aim_tx_new(0x0002, conn, packlen)))
89 case AIM_VISIBILITYCHANGE_PERMITADD: subtype = 0x05; break;
90 case AIM_VISIBILITYCHANGE_PERMITREMOVE: subtype = 0x06; break;
91 case AIM_VISIBILITYCHANGE_DENYADD: subtype = 0x07; break;
92 case AIM_VISIBILITYCHANGE_DENYREMOVE: subtype = 0x08; break;
94 free(newpacket->data);
99 /* We actually DO NOT send a SNAC ID with this one! */
100 aim_putsnac(newpacket->data, 0x0009, subtype, 0x00, 0);
102 j = 10; /* the next byte */
104 for (i=0; (i < (listcount - 1)) && (i < 99); i++)
106 tmpptr = aimutil_itemidx(localcpy, i, '&');
108 newpacket->data[j] = strlen(tmpptr);
109 memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr));
110 j += strlen(tmpptr)+1;
117 aim_tx_enqueue(sess, newpacket);
119 return (sess->snac_nextid); /* dont increment */
126 * aim_bos_setbuddylist(buddylist)
128 * This just builds the "set buddy list" command then queues it.
130 * buddy_list = "Screen Name One&ScreenNameTwo&";
132 * TODO: Clean this up.
134 * XXX: I can't stress the TODO enough.
137 u_long aim_bos_setbuddylist(struct aim_session_t *sess,
138 struct aim_conn_t *conn,
143 struct command_tx_struct *newpacket;
145 int packet_login_phase3c_hi_b_len = 0;
147 char *localcpy = NULL;
150 packet_login_phase3c_hi_b_len = 16; /* 16b for FLAP and SNAC headers */
152 /* bail out if we can't make the packet */
157 localcpy = (char *) malloc(strlen(buddy_list)+1);
158 memcpy(localcpy, buddy_list, strlen(buddy_list)+1);
161 tmpptr = strtok(localcpy, "&");
162 while ((tmpptr != NULL) && (i < 100))
165 printf("---adding %s (%d)\n", tmpptr, strlen(tmpptr));
167 packet_login_phase3c_hi_b_len += strlen(tmpptr)+1;
169 tmpptr = strtok(NULL, "&");
172 printf("*** send buddy list len: %d (%x)\n", packet_login_phase3c_hi_b_len, packet_login_phase3c_hi_b_len);
176 if (!(newpacket = aim_tx_new(0x0002, conn, packet_login_phase3c_hi_b_len - 6)))
181 aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, sess->snac_nextid);
183 j = 10; /* the next byte */
186 tmpptr = strtok(buddy_list, "&");
187 while ((tmpptr != NULL) & (i < 100))
190 printf("---adding %s (%d)\n", tmpptr, strlen(tmpptr));
192 newpacket->data[j] = strlen(tmpptr);
193 memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr));
194 j += strlen(tmpptr)+1;
196 tmpptr = strtok(NULL, "&");
201 aim_tx_enqueue(sess, newpacket);
203 return (sess->snac_nextid++);
207 * aim_bos_setprofile(profile)
209 * Gives BOS your profile.
212 * The large data chunk given here is of unknown decoding.
213 * What I do know is that each 0x20 byte repetition
214 * represents a capability. People with only the
215 * first two reptitions can support normal messaging
216 * and chat (client version 2.0 or 3.0). People with
217 * the third as well can also support voice chat (client
218 * version 3.5 or higher). IOW, if we don't send this,
219 * we won't get chat invitations (get "software doesn't
220 * support chat" error).
222 * This data is broadcast along with your oncoming
223 * buddy command to everyone who has you on their
224 * buddy list, as a type 0x0002 TLV.
227 u_long aim_bos_setprofile(struct aim_session_t *sess,
228 struct aim_conn_t *conn,
233 struct command_tx_struct *newpacket;
236 if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0))))
239 i += aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid);
240 i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\"");
241 i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(profile), profile);
242 /* why do we send this twice? */
243 i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\"");
245 /* Away message -- we send this no matter what, even if its blank */
247 i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(awaymsg), awaymsg);
249 i += aim_puttlv_str(newpacket->data+i, 0x0004, 0x0000, NULL);
251 /* Capability information. */
254 i += aimutil_put16(newpacket->data+i, 0x0005);
256 i += aimutil_put16(newpacket->data+i, 0);
257 if (caps & AIM_CAPS_BUDDYICON)
258 i += aimutil_putstr(newpacket->data+i, aim_caps[0], 0x10);
259 if (caps & AIM_CAPS_VOICE)
260 i += aimutil_putstr(newpacket->data+i, aim_caps[1], 0x10);
261 if (caps & AIM_CAPS_IMIMAGE)
262 i += aimutil_putstr(newpacket->data+i, aim_caps[2], 0x10);
263 if (caps & AIM_CAPS_CHAT)
264 i += aimutil_putstr(newpacket->data+i, aim_caps[3], 0x10);
265 if (caps & AIM_CAPS_GETFILE)
266 i += aimutil_putstr(newpacket->data+i, aim_caps[4], 0x10);
267 if (caps & AIM_CAPS_SENDFILE)
268 i += aimutil_putstr(newpacket->data+i, aim_caps[5], 0x10);
269 aimutil_put16(newpacket->data+isave, i-isave-2);
271 newpacket->commandlen = i;
272 aim_tx_enqueue(sess, newpacket);
274 return (sess->snac_nextid++);
278 * aim_bos_setgroupperm(mask)
280 * Set group permisson mask. Normally 0x1f.
283 u_long aim_bos_setgroupperm(struct aim_session_t *sess,
284 struct aim_conn_t *conn,
287 return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask);
291 * aim_bos_clientready()
298 u_long aim_bos_clientready(struct aim_session_t *sess,
299 struct aim_conn_t *conn)
301 u_char command_2[] = {
302 /* placeholders for dynamic data */
303 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
347 int command_2_len = 0x52;
348 struct command_tx_struct *newpacket;
350 if (!(newpacket = aim_tx_new(0x0002, conn, command_2_len)))
355 memcpy(newpacket->data, command_2, command_2_len);
357 /* This write over the dynamic parts of the byte block */
358 aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid);
360 aim_tx_enqueue(sess, newpacket);
362 return (sess->snac_nextid++);
366 * send_login_phase3(int socket)
368 * Request Rate Information.
370 * TODO: Move to aim_conn.
371 * TODO: Move to SNAC interface.
373 u_long aim_bos_reqrate(struct aim_session_t *sess,
374 struct aim_conn_t *conn)
376 return aim_genericreq_n(sess, conn, 0x0001, 0x0006);
380 * send_login_phase3b(int socket)
382 * Rate Information Response Acknowledge.
385 u_long aim_bos_ackrateresp(struct aim_session_t *sess,
386 struct aim_conn_t *conn)
388 struct command_tx_struct *newpacket;
389 int packlen = 18, i=0;
391 if (conn->type != AIM_CONN_TYPE_BOS)
394 if(!(newpacket = aim_tx_new(0x0002, conn, packlen)));
398 i = aim_putsnac(newpacket->data, 0x0001, 0x0008, 0x0000, sess->snac_nextid);
399 i += aimutil_put16(newpacket->data+i, 0x0001);
400 i += aimutil_put16(newpacket->data+i, 0x0002);
401 i += aimutil_put16(newpacket->data+i, 0x0003);
402 i += aimutil_put16(newpacket->data+i, 0x0004);
404 if (conn->type != AIM_CONN_TYPE_BOS) {
405 i += aimutil_put16(newpacket->data+i, 0x0005);
408 aim_tx_enqueue(sess, newpacket);
410 return (sess->snac_nextid++);
414 * aim_bos_setprivacyflags()
416 * Sets privacy flags. Normally 0x03.
418 * Bit 1: Allows other AIM users to see how long you've been idle.
422 u_long aim_bos_setprivacyflags(struct aim_session_t *sess,
423 struct aim_conn_t *conn,
426 return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags);
430 * aim_bos_reqpersonalinfo()
432 * Requests the current user's information. Can't go generic on this one
433 * because aparently it uses SNAC flags.
436 u_long aim_bos_reqpersonalinfo(struct aim_session_t *sess,
437 struct aim_conn_t *conn)
439 struct command_tx_struct *newpacket;
441 if (!(newpacket = aim_tx_new(0x0002, conn, 12)))
446 aim_putsnac(newpacket->data, 0x000a, 0x0001, 0x000e /* huh? */, sess->snac_nextid);
448 newpacket->data[10] = 0x0d;
449 newpacket->data[11] = 0xda;
452 aim_tx_enqueue(sess, newpacket);
454 return (sess->snac_nextid++);
457 u_long aim_setversions(struct aim_session_t *sess,
458 struct aim_conn_t *conn)
460 struct command_tx_struct *newpacket;
463 if (!(newpacket = aim_tx_new(0x0002, conn, 10 + (4*11))))
468 i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid);
470 i += aimutil_put16(newpacket->data+i, 0x0001);
471 i += aimutil_put16(newpacket->data+i, 0x0003);
473 i += aimutil_put16(newpacket->data+i, 0x0002);
474 i += aimutil_put16(newpacket->data+i, 0x0001);
476 i += aimutil_put16(newpacket->data+i, 0x0003);
477 i += aimutil_put16(newpacket->data+i, 0x0001);
479 i += aimutil_put16(newpacket->data+i, 0x0004);
480 i += aimutil_put16(newpacket->data+i, 0x0001);
482 i += aimutil_put16(newpacket->data+i, 0x0006);
483 i += aimutil_put16(newpacket->data+i, 0x0001);
485 i += aimutil_put16(newpacket->data+i, 0x0008);
486 i += aimutil_put16(newpacket->data+i, 0x0001);
488 i += aimutil_put16(newpacket->data+i, 0x0009);
489 i += aimutil_put16(newpacket->data+i, 0x0001);
491 i += aimutil_put16(newpacket->data+i, 0x000a);
492 i += aimutil_put16(newpacket->data+i, 0x0001);
494 i += aimutil_put16(newpacket->data+i, 0x000b);
495 i += aimutil_put16(newpacket->data+i, 0x0002);
497 i += aimutil_put16(newpacket->data+i, 0x000c);
498 i += aimutil_put16(newpacket->data+i, 0x0001);
500 i += aimutil_put16(newpacket->data+i, 0x0015);
501 i += aimutil_put16(newpacket->data+i, 0x0001);
504 for (j = 0; j < 0x10; j++) {
505 i += aimutil_put16(newpacket->data+i, j); /* family */
506 i += aimutil_put16(newpacket->data+i, 0x0003); /* version */
510 aim_tx_enqueue(sess, newpacket);
512 return (sess->snac_nextid++);
517 * aim_bos_reqservice(serviceid)
522 u_long aim_bos_reqservice(struct aim_session_t *sess,
523 struct aim_conn_t *conn,
526 return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid);
530 * aim_bos_reqrights()
532 * Request BOS rights.
535 u_long aim_bos_reqrights(struct aim_session_t *sess,
536 struct aim_conn_t *conn)
538 return aim_genericreq_n(sess, conn, 0x0009, 0x0002);
542 * aim_bos_reqbuddyrights()
544 * Request Buddy List rights.
547 u_long aim_bos_reqbuddyrights(struct aim_session_t *sess,
548 struct aim_conn_t *conn)
550 return aim_genericreq_n(sess, conn, 0x0003, 0x0002);
554 * Generic routine for sending commands.
557 * I know I can do this in a smarter way...but I'm not thinking straight
560 * I had one big function that handled all three cases, but then it broke
561 * and I split it up into three. But then I fixed it. I just never went
562 * back to the single. I don't see any advantage to doing it either way.
565 u_long aim_genericreq_n(struct aim_session_t *sess,
566 struct aim_conn_t *conn,
567 u_short family, u_short subtype)
569 struct command_tx_struct *newpacket;
571 if (!(newpacket = aim_tx_new(0x0002, conn, 10)))
576 aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid);
578 aim_tx_enqueue(sess, newpacket);
579 return (sess->snac_nextid++);
586 u_long aim_genericreq_l(struct aim_session_t *sess,
587 struct aim_conn_t *conn,
588 u_short family, u_short subtype, u_long *longdata)
590 struct command_tx_struct *newpacket;
593 /* If we don't have data, there's no reason to use this function */
595 return aim_genericreq_n(sess, conn, family, subtype);
597 if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_long))))
602 aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid);
605 newlong = htonl(*longdata);
606 memcpy(&(newpacket->data[10]), &newlong, sizeof(u_long));
608 aim_tx_enqueue(sess, newpacket);
609 return (sess->snac_nextid++);
612 u_long aim_genericreq_s(struct aim_session_t *sess,
613 struct aim_conn_t *conn,
614 u_short family, u_short subtype, u_short *shortdata)
616 struct command_tx_struct *newpacket;
619 /* If we don't have data, there's no reason to use this function */
621 return aim_genericreq_n(sess, conn, family, subtype);
623 if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_short))))
628 aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid);
631 newshort = htons(*shortdata);
632 memcpy(&(newpacket->data[10]), &newshort, sizeof(u_short));
634 aim_tx_enqueue(sess, newpacket);
635 return (sess->snac_nextid++);
639 * aim_bos_reqlocaterights()
641 * Request Location services rights.
644 u_long aim_bos_reqlocaterights(struct aim_session_t *sess,
645 struct aim_conn_t *conn)
647 return aim_genericreq_n(sess, conn, 0x0002, 0x0002);
651 * aim_bos_reqicbmparaminfo()
653 * Request ICBM parameter information.
656 u_long aim_bos_reqicbmparaminfo(struct aim_session_t *sess,
657 struct aim_conn_t *conn)
659 return aim_genericreq_n(sess, conn, 0x0004, 0x0004);