4 * The point of faimtest is twofold:
5 * - Test the functionality of libfaim.
6 * - Demonstrate the functionality of libfaim and how to use it.
8 * It does the latter rather badly, and the first as best it can without a
9 * more realistic UI. libfaim has a slightly different event model than
10 * many C programmers are used to, which is why I provide faimtest as
11 * documentation instead of attempting to explain how it works in English.
12 * If you're still in need of more guidance, see the source for the OSCAR
13 * "plugin" in gaim. It does it nicely, and in a realistic situation. (Did
14 * I mention faimtest is a bit idealized?)
16 * The faimtest code is very ugly. Probably always will be.
18 * Note that faimtest does not do a lot of error checking, except perhaps
19 * on some libfaim funtions. This is done for clarity, in hopes of
20 * making this crap ever so slighly more readable.
27 char *dprintf_ctime(void)
29 static char retbuf[64];
34 gettimeofday(&tv, &tz);
35 lt = localtime((time_t *)&tv.tv_sec);
36 strftime(retbuf, 64, "%a %b %e %H:%M:%S %Z %Y", lt);
41 static char *msgerrreasons[] = {
47 "Service unavailable",
48 "Service not defined",
50 "Not supported by host",
51 "Not supported by client",
56 "Busted SNAC payload",
57 "Insufficient rights",
58 "In local permit/deny",
60 "Too evil (receiver)",
61 "User temporarily unavailable",
68 static int msgerrreasonslen = 25;
70 aim_session_t aimsess;
74 * This is used to intercept debugging/diagnostic messages from libfaim.
76 * Note that you should have one of these even if you use a debuglevel of
77 * zero, as libfaim will send serious errors to stderr by default.
80 static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
83 vfprintf(stderr, format, va);
88 int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
91 /* XXX fix libfaim to support this */
92 dvprintf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
96 * This is an alternate location for starting the login process.
98 /* XXX should do more checking to make sure its really the right AUTH conn */
99 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
100 /* do NOT send a flapversion, request_login will send it if needed */
101 aim_request_login(sess, fr->conn, priv->screenname);
102 dprintf("faimtest: login request sent\n");
110 * This is a frivilous callback. You don't need it. I only used it for
111 * debugging non-blocking connects.
113 * If packets are sent to a conn before its fully connected, they
114 * will be queued and then transmitted when the connection completes.
117 int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
123 conn = va_arg(ap, aim_conn_t *);
127 dvprintf("faimtest: connection on %d completed\n", conn->fd);
134 * This is really all thats needed to link against libfaim on win32.
136 * Note that this particular version of faimtest has never been tested
137 * on win32, but I'm fairly sure it should work.
139 static int initwsa(void)
141 WORD wVersionRequested;
144 wVersionRequested = MAKEWORD(2,2);
145 return WSAStartup(wVersionRequested, &wsaData);
150 * This is unrealistic. Most clients will not be able to do this.
152 int faimtest_init(void)
154 aim_conn_t *stdinconn = NULL;
156 if (!(stdinconn = aim_newconn(&aimsess, 0, NULL))) {
157 dprintf("unable to create connection for stdin!\n");
161 stdinconn->fd = STDIN_FILENO;
166 int main(int argc, char **argv)
168 aim_conn_t *waitingconn = NULL;
171 static int faimtest_mode = 0;
174 const char *buddyiconpath = NULL;
175 struct faimtest_priv priv = {
176 NULL, NULL, NULL, NULL,
177 NULL, NULL, NULL, NULL,
183 priv.screenname = getenv("SCREENNAME");
184 priv.password = getenv("PASSWORD");
185 priv.server = getenv("AUTHSERVER");
186 priv.proxy = getenv("SOCKSPROXY");
187 priv.proxyusername = getenv("SOCKSNAME");
188 priv.proxypass = getenv("SOCKSPASS");
190 priv.listingpath = getenv("LISTINGPATH");
192 while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:i:")) != EOF) {
194 case 'u': priv.screenname = optarg; break;
195 case 'p': priv.password = optarg; break;
196 case 'a': priv.server = optarg; break;
197 case 'U': priv.proxyusername = optarg; break;
198 case 'P': priv.proxypass = optarg; break;
199 case 'A': priv.proxy = optarg; break;
200 case 'l': priv.listingpath = optarg; break;
201 case 'c': priv.ohcaptainmycaptain = optarg; break;
202 case 'o': faimtest_mode = 1; break; /* half old interface */
203 case 'O': faimtest_mode = 2; break; /* full old interface */
204 case 'b': priv.aimbinarypath = optarg; break;
205 case 'i': buddyiconpath = optarg; break;
208 printf("faimtest\n");
209 printf(" Options: \n");
210 printf(" -u name Screen name ($SCREENNAME)\n");
211 printf(" -p passwd Password ($PASSWORD)\n");
212 printf(" -a host:port Authorizer ($AUTHSERVER)\n");
213 printf(" -U name Proxy user name ($SOCKSPROXY)\n");
214 printf(" -P passwd Proxy password ($SOCKSNAME)\n");
215 printf(" -A host:port Proxy host ($SOCKSPASS)\n");
216 printf(" -l path Path to listing file ($LISTINGPATH)\n");
217 printf(" -c name Screen name of owner\n");
218 printf(" -o Login at startup, then prompt\n");
219 printf(" -O Login, never give prompt\n");
220 printf(" -b path Path to AIM 3.5.1670 binaries\n");
221 printf(" -i file Buddy Icon to send\n");
227 if (initwsa() != 0) {
228 dprintf("faimtest: could not initialize windows sockets\n");
233 /* Pass zero as flags if you want blocking connects */
234 aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 1);
235 aim_setdebuggingcb(&aimsess, faimtest_debugcb); /* still needed even if debuglevel = 0 ! */
236 aimsess.aux_data = &priv;
238 if (priv.listingpath) {
241 listingname = (char *)calloc(1, strlen(priv.listingpath)+strlen("/listing.txt"));
242 sprintf(listingname, "%s/listing.txt", priv.listingpath);
244 if ((priv.listingfile = fopen(listingname, "r")) == NULL)
245 dvprintf("Couldn't open %s... disabling that shit.\n", listingname);
254 if ((stat(buddyiconpath, &st) != -1) && (st.st_size <= MAXICONLEN) && (f = fopen(buddyiconpath, "r"))) {
256 priv.buddyiconlen = st.st_size;
257 priv.buddyiconstamp = st.st_mtime;
258 priv.buddyicon = malloc(priv.buddyiconlen);
259 fread(priv.buddyicon, 1, st.st_size, f);
261 priv.buddyiconsum = aim_iconsum(priv.buddyicon, priv.buddyiconlen);
263 dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", priv.buddyiconlen, buddyiconpath, priv.buddyiconsum);
268 dvprintf("could not open buddy icon %s\n", buddyiconpath);
274 if (faimtest_mode < 2)
277 if (faimtest_mode >= 1) {
278 if (login(&aimsess, priv.screenname, priv.password) == -1) {
279 if (faimtest_mode < 2)
291 waitingconn = aim_select(&aimsess, &tv, &selstat);
293 if (priv.connected && ((time(NULL) - lastnop) > 30)) {
294 lastnop = time(NULL);
295 aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS));
298 if (selstat == -1) { /* error */
299 keepgoing = 0; /* fall through */
300 } else if (selstat == 0) { /* no events pending */
302 } else if (selstat == 1) { /* outgoing data pending */
303 aim_tx_flushqueue(&aimsess);
304 } else if (selstat == 2) { /* incoming data pending */
305 if ((faimtest_mode < 2) && (waitingconn->fd == STDIN_FILENO)) {
308 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
309 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
310 dprintf("connection error (rend out)\n");
311 aim_conn_kill(&aimsess, &waitingconn);
314 if (aim_get_command(&aimsess, waitingconn) >= 0) {
315 aim_rxdispatch(&aimsess);
317 dvprintf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype);
318 /* we should have callbacks for all these, else the library will do the conn_kill for us. */
319 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
320 aim_conn_kill(&aimsess, &waitingconn);
322 aim_conn_kill(&aimsess, &waitingconn);
323 if (!aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)) {
324 dprintf("major connection error\n");
325 if (faimtest_mode == 2)
334 /* close up all connections, dead or no */
335 aim_session_kill(&aimsess);
337 if (faimtest_mode < 2) {
342 free(priv.buddyicon);
348 int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...)
355 famcount = va_arg(ap, int);
356 families = va_arg(ap, fu16_t *);
359 dvprintf("faimtest: SNAC families supported by this host (type %d): ", fr->conn->type);
360 for (i = 0; i < famcount; i++)
361 dvinlineprintf("0x%04x ", families[i]);
364 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
366 aim_auth_setversions(sess, fr->conn);
367 aim_bos_reqrate(sess, fr->conn); /* request rate info */
369 dprintf("done with auth server ready\n");
371 } else if (fr->conn->type == AIM_CONN_TYPE_BOS) {
373 aim_setversions(sess, fr->conn);
374 aim_bos_reqrate(sess, fr->conn); /* request rate info */
376 dprintf("done with BOS server ready\n");
382 int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
384 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
390 code = va_arg(ap, int);
391 msg = va_arg(ap, char *);
394 dvprintf("connerr: Code 0x%04x: %s\n", code, msg);
395 aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
403 static int faimtest_rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...)
406 aim_bos_ackrateresp(sess, fr->conn);
407 aim_auth_clientready(sess, fr->conn);
409 dprintf("faimtest: connected to authorization/admin service\n");
414 int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
420 status = va_arg(ap, int); /* status code of confirmation request */
423 dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
433 * This kind of function is really not legal in the new bstream way...
434 * In fact, clients should never access the aim_frame_t directly in handlers,
435 * since that may leave it in a bizare state for the lower layers. In fact,
436 * clients should probably not even get passed a pointer like this.
439 int faimtest_parse_unknown(aim_session_t *sess, aim_frame_t *fr, ...)
443 aim_bstream_rewind(&fr->data); /* boo! */
445 dprintf("\nReceived unknown packet:");
446 for (i = 0; aim_bstream_empty(&fr->data); i++) {
448 dinlineprintf("\n\t");
449 dvinlineprintf("0x%2x ", aimbs_get8(&fr->data));
451 dinlineprintf("\n\n");
457 int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
465 serviceid = va_arg(ap, int);
466 ip = va_arg(ap, char *);
467 cookie = va_arg(ap, fu8_t *);
469 if (serviceid == 0x0005) { /* Adverts */
473 tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, ip);
474 if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
475 dprintf("faimtest: unable to reconnect with authorizer\n");
477 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
478 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
479 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
480 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
481 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
482 aim_auth_sendcookie(sess, tstconn, cookie);
483 dprintf("sent cookie to adverts host\n");
486 } else if (serviceid == 0x0007) { /* Authorizer */
490 tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
491 if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
492 dprintf("faimtest: unable to reconnect with authorizer\n");
494 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
495 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
496 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
497 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
498 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
499 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
500 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
501 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
502 /* Send the cookie to the Auth */
503 aim_auth_sendcookie(sess, tstconn, cookie);
504 dprintf("sent cookie to authorizer host\n");
507 } else if (serviceid == 0x000d) { /* ChatNav */
509 chatnav_redirect(sess, ip, cookie);
511 } else if (serviceid == 0x000e) { /* Chat */
512 char *roomname = NULL;
515 roomname = va_arg(ap, char *);
516 exchange = va_arg(ap, int);
518 chat_redirect(sess, ip, cookie, roomname, exchange);
521 dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
529 static int faimtest_rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...)
531 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
532 char buddies[128]; /* this is the new buddy list */
533 char profile[256]; /* this is the new profile */
534 char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
536 /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
537 snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah");
538 snprintf(profile, sizeof(profile), "Hello.<br>My captain is %s. They were dumb enough to leave this message in their client, or they are using faimtest. Shame on them.", priv->ohcaptainmycaptain);
540 aim_bos_ackrateresp(sess, fr->conn); /* ack rate info response */
541 aim_bos_reqpersonalinfo(sess, fr->conn);
542 aim_bos_reqlocaterights(sess, fr->conn);
543 aim_bos_setprofile(sess, fr->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE /*| AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS*/);
544 aim_bos_reqbuddyrights(sess, fr->conn);
546 /* send the buddy list and profile (required, even if empty) */
547 aim_bos_setbuddylist(sess, fr->conn, buddies);
549 aim_reqicbmparams(sess, fr->conn);
551 aim_bos_reqrights(sess, fr->conn);
552 /* set group permissions -- all user classes */
553 aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
554 aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE);
559 static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
561 struct aim_icbmparameters *params;
565 params = va_arg(ap, struct aim_icbmparameters *);
568 dvprintf("ICBM Parameters: maxchannel = %d, default flags = 0x%08lx, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %ld\n", params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval);
571 * Set these to your taste, or client medium. Setting minmsginterval
572 * higher is good for keeping yourself from getting flooded (esp
573 * if you're on a slow connection or something where that would be
576 params->maxmsglen = 8000;
577 params->minmsginterval = 0; /* in milliseconds */
579 aim_seticbmparam(sess, fr->conn, params);
584 static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...)
591 vercount = va_arg(ap, int); /* number of family/version pairs */
592 versions = va_arg(ap, fu8_t *);
595 dprintf("faimtest: SNAC versions supported by this host: ");
596 for (i = 0; i < vercount*4; i += 4) {
597 dvinlineprintf("0x%04x:0x%04x ",
598 aimutil_get16(versions+i), /* SNAC family */
599 aimutil_get16(versions+i+2) /* Version number */);
606 static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
609 fu16_t maxbuddies, maxwatchers;
612 maxbuddies = va_arg(ap, int);
613 maxwatchers = va_arg(ap, int);
616 dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
621 static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
624 fu16_t maxpermits, maxdenies;
627 maxpermits = va_arg(ap, int);
628 maxdenies = va_arg(ap, int);
631 dvprintf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
633 aim_bos_clientready(sess, fr->conn);
635 dprintf("officially connected to BOS.\n");
640 static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
646 maxsiglen = va_arg(ap, int);
649 dvprintf("locate rights: max signature length = %d\n", maxsiglen);
654 static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
656 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
661 interval = va_arg(ap, int);
664 dvprintf("minimum report interval: %d (seconds?)\n", interval);
666 if (!priv->connected)
670 aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */
671 aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */
673 /* Don't know what this does... */
674 /* XXX sess->sn should be normalized by the 0001/000f handler */
675 aim_0002_000b(sess, fr->conn, sess->sn);
678 aim_reqicbmparams(sess, fr->conn);
683 static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
685 static char *codes[] = {
692 static int codeslen = 5;
698 id = va_arg(ap, int);
699 msg = va_arg(ap, char *);
702 dvprintf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown");
708 * This is a little more complicated than it looks. The module
709 * name (proto, boscore, etc) may or may not be given. If it is
710 * not given, then use aim.exe. If it is given, put ".ocm" on the
713 * Now, if the offset or length requested would cause a read past
714 * the end of the file, then the request is considered invalid. Invalid
715 * requests are processed specially. The value hashed is the
716 * the request, put into little-endian (eight bytes: offset followed
719 * Additionally, if the request is valid, the length is mod 4096. It is
720 * important that the length is checked for validity first before doing
723 * Note to Bosco's Brigade: if you'd like to break this, put the
724 * module name on an invalid request.
727 static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
729 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
731 static const char defaultmod[] = "aim.exe";
732 char *filename = NULL;
737 if (!bufret || !buflenret)
742 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
743 dperror("memrequest: malloc");
747 sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
751 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
752 dperror("memrequest: malloc");
756 sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
760 if (stat(filename, &st) == -1) {
762 dperror("memrequest: stat");
770 if ((offset > st.st_size) || (len > st.st_size))
772 else if ((st.st_size - offset) < len)
773 len = st.st_size - offset;
774 else if ((st.st_size - len) < len)
775 len = st.st_size - len;
784 free(filename); /* not needed */
786 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
790 i += strlen(modname);
792 if (!(buf = malloc(i)))
798 memcpy(buf, modname, strlen(modname));
799 i += strlen(modname);
802 /* Damn endianness. This must be little (LSB first) endian. */
803 buf[i++] = offset & 0xff;
804 buf[i++] = (offset >> 8) & 0xff;
805 buf[i++] = (offset >> 16) & 0xff;
806 buf[i++] = (offset >> 24) & 0xff;
807 buf[i++] = len & 0xff;
808 buf[i++] = (len >> 8) & 0xff;
809 buf[i++] = (len >> 16) & 0xff;
810 buf[i++] = (len >> 24) & 0xff;
817 if (!(buf = malloc(len))) {
822 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
824 if (!(f = fopen(filename, "r"))) {
825 dperror("memrequest: fopen");
833 if (fseek(f, offset, SEEK_SET) == -1) {
834 dperror("memrequest: fseek");
840 if (fread(buf, len, 1, f) != 1) {
841 dperror("memrequest: fread");
854 return 0; /* success! */
858 * This will get an offset and a length. The client should read this
859 * data out of whatever AIM.EXE binary the user has provided (hopefully
860 * it matches the client information thats sent at login) and pass a
861 * buffer back to libfaim so it can hash the data and send it to AOL for
862 * inspection by the client police.
864 static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
866 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
874 offset = va_arg(ap, fu32_t);
875 len = va_arg(ap, fu32_t);
876 modname = va_arg(ap, char *);
879 if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
881 aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
887 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
889 aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
896 static void printuserflags(fu16_t flags)
898 if (flags & AIM_FLAG_UNCONFIRMED)
899 dinlineprintf("UNCONFIRMED ");
900 if (flags & AIM_FLAG_ADMINISTRATOR)
901 dinlineprintf("ADMINISTRATOR ");
902 if (flags & AIM_FLAG_AOL)
903 dinlineprintf("AOL ");
904 if (flags & AIM_FLAG_OSCAR_PAY)
905 dinlineprintf("OSCAR_PAY ");
906 if (flags & AIM_FLAG_FREE)
907 dinlineprintf("FREE ");
908 if (flags & AIM_FLAG_AWAY)
909 dinlineprintf("AWAY ");
910 if (flags & AIM_FLAG_UNKNOWN40)
911 dinlineprintf("ICQ? ");
912 if (flags & AIM_FLAG_UNKNOWN80)
913 dinlineprintf("UNKNOWN80 ");
917 static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
919 struct aim_userinfo_s *userinfo;
920 char *prof_encoding = NULL;
926 userinfo = va_arg(ap, struct aim_userinfo_s *);
927 prof_encoding = va_arg(ap, char *);
928 prof = va_arg(ap, char *);
929 inforeq = va_arg(ap, fu16_t);
932 dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn);
933 dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
934 dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
935 printuserflags(userinfo->flags);
938 dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
939 dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
940 dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
942 if (inforeq == AIM_GETINFO_GENERALINFO) {
943 dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
944 dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
945 } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
946 dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
947 dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
949 dprintf("faimtest: userinfo: unknown info request\n");
954 static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr)
956 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
958 if (!strncmp(tmpstr, "disconnect", 10)) {
962 } else if (strstr(tmpstr, "goodday")) {
964 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
966 } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
967 struct aim_sendimext_args args;
968 static const char iconmsg[] = {"I have an icon"};
970 args.destsn = userinfo->sn;
971 args.flags = AIM_IMFLAGS_HASICON;
973 args.msglen = strlen(iconmsg);
974 args.iconlen = priv->buddyiconlen;
975 args.iconstamp = priv->buddyiconstamp;
976 args.iconsum = priv->buddyiconsum;
978 aim_send_im_ext(sess, conn, &args);
980 } else if (strstr(tmpstr, "havefeat")) {
981 struct aim_sendimext_args args;
982 static const char featmsg[] = {"I have nifty features."};
983 fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
985 args.destsn = userinfo->sn;
986 args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
988 args.msglen = strlen(featmsg);
989 args.features = features;
990 args.featureslen = sizeof(features);
992 aim_send_im_ext(sess, conn, &args);
994 } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
996 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
998 } else if (strstr(tmpstr, "warnme")) {
1000 dprintf("faimtest: icbm: sending non-anon warning\n");
1001 aim_send_warning(sess, conn, userinfo->sn, 0);
1003 } else if (strstr(tmpstr, "anonwarn")) {
1005 dprintf("faimtest: icbm: sending anon warning\n");
1006 aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
1008 } else if (strstr(tmpstr, "setdirectoryinfo")) {
1010 dprintf("faimtest: icbm: sending backwards profile data\n");
1011 aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1013 } else if (strstr(tmpstr, "setinterests")) {
1015 dprintf("faimtest: icbm: setting fun interests\n");
1016 aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1018 } else if (!strncmp(tmpstr, "getfile", 7)) {
1020 if (!priv->ohcaptainmycaptain) {
1022 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1025 getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1027 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1029 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1031 } else if (!strncmp(tmpstr, "create", 6)) {
1033 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1035 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1036 aim_conn_t *chatnavconn;
1038 if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1039 aim_conn_kill(sess, &chatnavconn);
1041 } else if (!strncmp(tmpstr, "join", 4)) {
1043 aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1045 } else if (!strncmp(tmpstr, "leave", 5)) {
1047 aim_chat_leaveroom(sess, "worlddomination");
1049 } else if (!strncmp(tmpstr, "getinfo", 7)) {
1051 aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO);
1052 aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1053 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1054 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1056 } else if (strstr(tmpstr, "open directim")) {
1058 directim_start(sess, conn, userinfo->sn);
1060 } else if(!(strncmp(tmpstr, "lookup", 6))) {
1062 aim_usersearch_address(sess, conn, tmpstr+7);
1064 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1066 aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1068 } else if (!strncmp(tmpstr, "reqauth", 7)) {
1070 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1072 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1074 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1076 } else if (!strncmp(tmpstr, "reqemail", 8)) {
1078 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1080 } else if (!strncmp(tmpstr, "changepass", 8)) {
1082 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1084 } else if (!strncmp(tmpstr, "setemail", 8)) {
1086 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1088 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1096 newbuf = malloc(i+1);
1097 for (z = 0; z < i; z++)
1098 newbuf[z] = (z % 10)+0x30;
1100 aim_send_im(sess, conn, userinfo->sn, 0, newbuf);
1106 dprintf("unknown command.\n");
1107 aim_add_buddy(sess, conn, userinfo->sn);
1115 * Channel 1: Standard Message
1117 static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1119 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
1121 struct aim_incomingim_ch1_args *args;
1122 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1123 char realmsg[8192+1] = {""};
1125 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1128 clienttype = aim_fingerprintclient(args->features, args->featureslen);
1130 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1131 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1132 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1133 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1134 printuserflags(userinfo->flags);
1135 dinlineprintf("\n");
1137 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1138 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1139 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1140 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1142 dprintf("faimtest: icbm: icbmflags = ");
1143 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1144 dinlineprintf("away ");
1145 if (args->icbmflags & AIM_IMFLAGS_ACK)
1146 dinlineprintf("ackrequest ");
1147 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1148 dinlineprintf("buddyreq ");
1149 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1150 dinlineprintf("hasicon ");
1151 dinlineprintf("\n");
1153 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
1156 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1157 * characters with their equivelent HTML entity.
1159 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1162 for (i = 0; i < args->msglen; i += 2) {
1165 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1167 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1169 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1171 } else { /* something else, do UNICODE entity */
1173 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1182 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1183 * no need to do anything special here. Most
1184 * terminals/whatever will be able to display such characters
1187 * Beware that PC-ASCII 128 through 159 are _not_ actually
1188 * defined in ASCII or ISO 8859-1, and you should send them as
1189 * UNICODE. WinAIM will send these characters in a UNICODE
1190 * message, so you need to do so as well.
1192 * You may not think it necessary to handle UNICODE messages.
1193 * You're probably wrong. For one thing, Microsoft "Smart
1194 * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1195 * but real UNICODE). If you don't parse UNICODE at all, your
1196 * users will get a blank message instead of the message
1197 * containing Smart Quotes.
1200 strncpy(realmsg, args->msg, sizeof(realmsg));
1203 dvprintf("faimtest: icbm: message: %s\n", realmsg);
1205 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1206 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1211 while (realmsg[i] == '<') {
1212 if (realmsg[i] == '<') {
1213 while (realmsg[i] != '>')
1220 faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1224 if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ))
1225 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1231 * Channel 2: Rendevous Request
1233 static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1235 struct aim_incomingim_ch2_args *args;
1237 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1240 if (args->reqclass == AIM_CAPS_VOICE) {
1242 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1243 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1244 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1245 printuserflags(userinfo->flags);
1246 dinlineprintf("\n");
1248 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1249 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1251 } else if (args->reqclass == AIM_CAPS_GETFILE) {
1253 getfile_requested(sess, conn, userinfo, args);
1255 } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1257 dprintf("faimtest: send file!\n");
1259 } else if (args->reqclass == AIM_CAPS_CHAT) {
1261 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1262 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1263 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1264 printuserflags(userinfo->flags);
1265 dinlineprintf("\n");
1267 /* we dont get membersince on chat invites! */
1268 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1269 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1271 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1272 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1273 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1274 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1275 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1276 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1277 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
1279 /* Automatically join room... */
1280 aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
1282 } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1284 dprintf("faimtest: icbm: rendezvous imimage\n");
1286 directim_requested(sess, conn, userinfo, args);
1288 } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1290 dvprintf("faimtest: Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length);
1294 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1300 static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1303 struct aim_userinfo_s *userinfo;
1308 channel = va_arg(ap, fu16_t);
1309 userinfo = va_arg(ap, struct aim_userinfo_s *);
1312 ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, ap);
1313 else if (channel == 2)
1314 ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap);
1316 dvprintf("unsupported channel 0x%04x\n", channel);
1318 dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret);
1323 #ifdef MID_REWROTE_ALL_THE_CRAP
1324 static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
1326 fu16_t change = 0, perms, type;
1332 perms = va_arg(ap, fu16_t);
1333 type = va_arg(ap, fu16_t);
1334 length = va_arg(ap, int);
1335 val = va_arg(ap, char *);
1336 str = va_arg(ap, int);
1339 if (aimutil_get16(command->data+2) == 0x0005)
1342 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1348 static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1350 struct aim_userinfo_s *userinfo;
1354 userinfo = va_arg(ap, struct aim_userinfo_s *);
1357 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1359 userinfo->sn, userinfo->flags,
1360 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1361 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1362 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1363 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1364 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1365 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1366 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1367 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1368 userinfo->capabilities);
1372 static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1374 struct aim_userinfo_s *userinfo;
1378 userinfo = va_arg(ap, struct aim_userinfo_s *);
1381 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1383 userinfo->sn, userinfo->flags,
1384 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1385 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1386 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1387 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1388 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1389 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1390 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1391 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1392 userinfo->capabilities);
1397 static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1403 reason = va_arg(ap, fu16_t);
1406 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1411 static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1418 reason = va_arg(ap, fu16_t);
1419 destsn = va_arg(ap, char *);
1422 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1427 static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1434 reason = va_arg(ap, fu16_t);
1435 destsn = va_arg(ap, char *);
1438 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1443 static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1445 static char *missedreasons[] = {
1447 "Message too large",
1452 static int missedreasonslen = 5;
1455 fu16_t chan, nummissed, reason;
1456 struct aim_userinfo_s *userinfo;
1459 chan = va_arg(ap, fu16_t);
1460 userinfo = va_arg(ap, struct aim_userinfo_s *);
1461 nummissed = va_arg(ap, fu16_t);
1462 reason = va_arg(ap, fu16_t);
1465 dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1471 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1473 static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1480 type = va_arg(ap, fu16_t);
1481 sn = va_arg(ap, char *);
1484 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1489 static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1491 static char *codes[5] = {
1499 fu16_t code, rateclass;
1500 fu32_t windowsize, clear, alert, limit, disconnect;
1501 fu32_t currentavg, maxavg;
1505 /* See code explanations below */
1506 code = va_arg(ap, fu16_t);
1509 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1511 rateclass = va_arg(ap, fu16_t);
1514 * Not sure what this is exactly. I think its the temporal
1515 * relation factor (ie, how to make the rest of the numbers
1516 * make sense in the real world).
1518 windowsize = va_arg(ap, fu32_t);
1520 /* Explained below */
1521 clear = va_arg(ap, fu32_t);
1522 alert = va_arg(ap, fu32_t);
1523 limit = va_arg(ap, fu32_t);
1524 disconnect = va_arg(ap, fu32_t);
1525 currentavg = va_arg(ap, fu32_t);
1526 maxavg = va_arg(ap, fu32_t);
1531 dvprintf("faimtest: rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1532 (code < 5)?codes[code]:"invalid",
1539 if (code == AIM_RATE_CODE_CHANGE) {
1541 * Not real sure when these get sent.
1543 if (currentavg >= clear)
1544 aim_conn_setlatency(fr->conn, 0);
1546 } else if (code == AIM_RATE_CODE_WARNING) {
1548 * We start getting WARNINGs the first time we go below the
1549 * 'alert' limit (currentavg < alert) and they stop when
1550 * either we pause long enough for currentavg to go above
1551 * 'clear', or until we flood it bad enough to go below
1552 * 'limit' (and start getting LIMITs instead) or even further
1553 * and go below 'disconnect' and get disconnected completely
1554 * (and won't be able to login right away either).
1556 aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */
1558 } else if (code == AIM_RATE_CODE_LIMIT) {
1560 * When we hit LIMIT, messages will start getting dropped.
1562 aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */
1564 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1566 * The limit is cleared when curavg goes above 'clear'.
1568 aim_conn_setlatency(fr->conn, 0);
1574 static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1578 struct aim_userinfo_s *userinfo;
1581 newevil = va_arg(ap, fu16_t);
1582 userinfo = va_arg(ap, struct aim_userinfo_s *);
1586 * Evil Notifications that are lacking userinfo->sn are anon-warns
1587 * if they are an evil increases, but are not warnings at all if its
1588 * a decrease (its the natural backoff happening).
1590 * newevil is passed as an int representing the new evil value times
1593 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1598 static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1601 char *address, *SNs;
1605 address = va_arg(ap, char *);
1606 num = va_arg(ap, int);
1607 SNs = va_arg(ap, char *);
1610 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
1612 for(i = 0; i < num; i++)
1613 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1614 dinlineprintf("\n");
1619 static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1625 address = va_arg(ap, char *);
1628 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1633 void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
1636 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1638 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1639 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */
1640 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
1641 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1642 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1643 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1644 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1645 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1646 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
1647 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1648 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
1649 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
1650 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
1651 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1652 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1653 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1654 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1655 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1656 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1657 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
1658 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1659 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
1660 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1661 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
1662 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1664 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1665 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1666 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
1668 #ifdef MID_REWROTE_ALL_THE_CRAP
1669 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);