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) {
310 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
311 dprintf("connection error (rend out)\n");
312 aim_conn_kill(&aimsess, &waitingconn);
316 if (aim_get_command(&aimsess, waitingconn) >= 0) {
317 aim_rxdispatch(&aimsess);
319 dvprintf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype);
320 /* we should have callbacks for all these, else the library will do the conn_kill for us. */
321 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
322 dprintf("connection error: rendezvous connection. you forgot register a disconnect callback, right?\n");
323 aim_conn_kill(&aimsess, &waitingconn);
325 aim_conn_kill(&aimsess, &waitingconn);
326 if (!aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)) {
327 dprintf("major connection error\n");
328 if (faimtest_mode == 2)
337 /* close up all connections, dead or no */
338 aim_session_kill(&aimsess);
340 if (faimtest_mode < 2) {
345 free(priv.buddyicon);
351 int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...)
358 famcount = va_arg(ap, int);
359 families = va_arg(ap, fu16_t *);
362 dvprintf("faimtest: SNAC families supported by this host (type %d): ", fr->conn->type);
363 for (i = 0; i < famcount; i++)
364 dvinlineprintf("0x%04x ", families[i]);
367 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
369 aim_auth_setversions(sess, fr->conn);
370 aim_bos_reqrate(sess, fr->conn); /* request rate info */
372 dprintf("done with auth server ready\n");
374 } else if (fr->conn->type == AIM_CONN_TYPE_BOS) {
376 aim_setversions(sess, fr->conn);
377 aim_bos_reqrate(sess, fr->conn); /* request rate info */
379 dprintf("done with BOS server ready\n");
385 int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
387 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
393 code = va_arg(ap, int);
394 msg = va_arg(ap, char *);
397 dvprintf("connerr: Code 0x%04x: %s\n", code, msg);
398 aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
406 static int faimtest_rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...)
409 aim_bos_ackrateresp(sess, fr->conn);
410 aim_auth_clientready(sess, fr->conn);
412 dprintf("faimtest: connected to authorization/admin service\n");
417 int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
423 status = va_arg(ap, int); /* status code of confirmation request */
426 dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
436 * This kind of function is really not legal in the new bstream way...
437 * In fact, clients should never access the aim_frame_t directly in handlers,
438 * since that may leave it in a bizare state for the lower layers. In fact,
439 * clients should probably not even get passed a pointer like this.
442 int faimtest_parse_unknown(aim_session_t *sess, aim_frame_t *fr, ...)
446 aim_bstream_rewind(&fr->data); /* boo! */
448 dprintf("\nReceived unknown packet:");
449 for (i = 0; aim_bstream_empty(&fr->data); i++) {
451 dinlineprintf("\n\t");
452 dvinlineprintf("0x%2x ", aimbs_get8(&fr->data));
454 dinlineprintf("\n\n");
460 int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
468 serviceid = va_arg(ap, int);
469 ip = va_arg(ap, char *);
470 cookie = va_arg(ap, fu8_t *);
472 if (serviceid == 0x0005) { /* Adverts */
476 tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, ip);
477 if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
478 dprintf("faimtest: unable to reconnect with authorizer\n");
480 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
481 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
482 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
483 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
484 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
485 aim_auth_sendcookie(sess, tstconn, cookie);
486 dprintf("sent cookie to adverts host\n");
489 } else if (serviceid == 0x0007) { /* Authorizer */
493 tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
494 if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
495 dprintf("faimtest: unable to reconnect with authorizer\n");
497 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
498 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
499 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
500 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
501 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
502 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
503 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
504 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
505 /* Send the cookie to the Auth */
506 aim_auth_sendcookie(sess, tstconn, cookie);
507 dprintf("sent cookie to authorizer host\n");
510 } else if (serviceid == 0x000d) { /* ChatNav */
512 chatnav_redirect(sess, ip, cookie);
514 } else if (serviceid == 0x000e) { /* Chat */
515 char *roomname = NULL;
518 roomname = va_arg(ap, char *);
519 exchange = va_arg(ap, int);
521 chat_redirect(sess, ip, cookie, roomname, exchange);
524 dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
532 static int faimtest_rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...)
534 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
535 char buddies[128]; /* this is the new buddy list */
536 char profile[256]; /* this is the new profile */
537 char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
539 /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
540 snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah");
541 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);
543 aim_bos_ackrateresp(sess, fr->conn); /* ack rate info response */
544 aim_bos_reqpersonalinfo(sess, fr->conn);
545 aim_bos_reqlocaterights(sess, fr->conn);
546 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*/);
547 aim_bos_reqbuddyrights(sess, fr->conn);
549 /* send the buddy list and profile (required, even if empty) */
550 aim_bos_setbuddylist(sess, fr->conn, buddies);
552 aim_reqicbmparams(sess, fr->conn);
554 aim_bos_reqrights(sess, fr->conn);
555 /* set group permissions -- all user classes */
556 aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
557 aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE);
562 static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
564 struct aim_icbmparameters *params;
568 params = va_arg(ap, struct aim_icbmparameters *);
571 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);
574 * Set these to your taste, or client medium. Setting minmsginterval
575 * higher is good for keeping yourself from getting flooded (esp
576 * if you're on a slow connection or something where that would be
579 params->maxmsglen = 8000;
580 params->minmsginterval = 0; /* in milliseconds */
582 aim_seticbmparam(sess, fr->conn, params);
587 static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...)
594 vercount = va_arg(ap, int); /* number of family/version pairs */
595 versions = va_arg(ap, fu8_t *);
598 dprintf("faimtest: SNAC versions supported by this host: ");
599 for (i = 0; i < vercount*4; i += 4) {
600 dvinlineprintf("0x%04x:0x%04x ",
601 aimutil_get16(versions+i), /* SNAC family */
602 aimutil_get16(versions+i+2) /* Version number */);
609 static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
612 fu16_t maxbuddies, maxwatchers;
615 maxbuddies = va_arg(ap, int);
616 maxwatchers = va_arg(ap, int);
619 dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
624 static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
627 fu16_t maxpermits, maxdenies;
630 maxpermits = va_arg(ap, int);
631 maxdenies = va_arg(ap, int);
634 dvprintf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
636 aim_bos_clientready(sess, fr->conn);
638 dprintf("officially connected to BOS.\n");
643 static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
649 maxsiglen = va_arg(ap, int);
652 dvprintf("locate rights: max signature length = %d\n", maxsiglen);
657 static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
659 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
664 interval = va_arg(ap, int);
667 dvprintf("minimum report interval: %d (seconds?)\n", interval);
669 if (!priv->connected)
673 aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */
674 aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */
676 /* Don't know what this does... */
677 /* XXX sess->sn should be normalized by the 0001/000f handler */
678 aim_0002_000b(sess, fr->conn, sess->sn);
681 aim_reqicbmparams(sess, fr->conn);
686 static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
688 static char *codes[] = {
695 static int codeslen = 5;
701 id = va_arg(ap, int);
702 msg = va_arg(ap, char *);
705 dvprintf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown");
711 * This is a little more complicated than it looks. The module
712 * name (proto, boscore, etc) may or may not be given. If it is
713 * not given, then use aim.exe. If it is given, put ".ocm" on the
716 * Now, if the offset or length requested would cause a read past
717 * the end of the file, then the request is considered invalid. Invalid
718 * requests are processed specially. The value hashed is the
719 * the request, put into little-endian (eight bytes: offset followed
722 * Additionally, if the request is valid, the length is mod 4096. It is
723 * important that the length is checked for validity first before doing
726 * Note to Bosco's Brigade: if you'd like to break this, put the
727 * module name on an invalid request.
730 static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
732 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
734 static const char defaultmod[] = "aim.exe";
735 char *filename = NULL;
740 if (!bufret || !buflenret)
745 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
746 dperror("memrequest: malloc");
750 sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
754 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
755 dperror("memrequest: malloc");
759 sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
763 if (stat(filename, &st) == -1) {
765 dperror("memrequest: stat");
773 if ((offset > st.st_size) || (len > st.st_size))
775 else if ((st.st_size - offset) < len)
776 len = st.st_size - offset;
777 else if ((st.st_size - len) < len)
778 len = st.st_size - len;
787 free(filename); /* not needed */
789 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
793 i += strlen(modname);
795 if (!(buf = malloc(i)))
801 memcpy(buf, modname, strlen(modname));
802 i += strlen(modname);
805 /* Damn endianness. This must be little (LSB first) endian. */
806 buf[i++] = offset & 0xff;
807 buf[i++] = (offset >> 8) & 0xff;
808 buf[i++] = (offset >> 16) & 0xff;
809 buf[i++] = (offset >> 24) & 0xff;
810 buf[i++] = len & 0xff;
811 buf[i++] = (len >> 8) & 0xff;
812 buf[i++] = (len >> 16) & 0xff;
813 buf[i++] = (len >> 24) & 0xff;
820 if (!(buf = malloc(len))) {
825 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
827 if (!(f = fopen(filename, "r"))) {
828 dperror("memrequest: fopen");
836 if (fseek(f, offset, SEEK_SET) == -1) {
837 dperror("memrequest: fseek");
843 if (fread(buf, len, 1, f) != 1) {
844 dperror("memrequest: fread");
857 return 0; /* success! */
861 * This will get an offset and a length. The client should read this
862 * data out of whatever AIM.EXE binary the user has provided (hopefully
863 * it matches the client information thats sent at login) and pass a
864 * buffer back to libfaim so it can hash the data and send it to AOL for
865 * inspection by the client police.
867 static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
869 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
877 offset = va_arg(ap, fu32_t);
878 len = va_arg(ap, fu32_t);
879 modname = va_arg(ap, char *);
882 if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
884 aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
890 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
892 aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
899 static void printuserflags(fu16_t flags)
901 if (flags & AIM_FLAG_UNCONFIRMED)
902 dinlineprintf("UNCONFIRMED ");
903 if (flags & AIM_FLAG_ADMINISTRATOR)
904 dinlineprintf("ADMINISTRATOR ");
905 if (flags & AIM_FLAG_AOL)
906 dinlineprintf("AOL ");
907 if (flags & AIM_FLAG_OSCAR_PAY)
908 dinlineprintf("OSCAR_PAY ");
909 if (flags & AIM_FLAG_FREE)
910 dinlineprintf("FREE ");
911 if (flags & AIM_FLAG_AWAY)
912 dinlineprintf("AWAY ");
913 if (flags & AIM_FLAG_UNKNOWN40)
914 dinlineprintf("ICQ? ");
915 if (flags & AIM_FLAG_UNKNOWN80)
916 dinlineprintf("UNKNOWN80 ");
920 static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
922 struct aim_userinfo_s *userinfo;
923 char *prof_encoding = NULL;
929 userinfo = va_arg(ap, struct aim_userinfo_s *);
930 prof_encoding = va_arg(ap, char *);
931 prof = va_arg(ap, char *);
932 inforeq = va_arg(ap, fu16_t);
935 dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn);
936 dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
937 dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
938 printuserflags(userinfo->flags);
941 dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
942 dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
943 dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
945 if (inforeq == AIM_GETINFO_GENERALINFO) {
946 dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
947 dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
948 } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
949 dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
950 dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
952 dprintf("faimtest: userinfo: unknown info request\n");
957 static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr)
959 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
961 if (!strncmp(tmpstr, "disconnect", 10)) {
965 } else if (strstr(tmpstr, "goodday")) {
967 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
969 } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
970 struct aim_sendimext_args args;
971 static const char iconmsg[] = {"I have an icon"};
973 args.destsn = userinfo->sn;
974 args.flags = AIM_IMFLAGS_HASICON;
976 args.msglen = strlen(iconmsg);
977 args.iconlen = priv->buddyiconlen;
978 args.iconstamp = priv->buddyiconstamp;
979 args.iconsum = priv->buddyiconsum;
981 aim_send_im_ext(sess, conn, &args);
983 } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
985 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
987 } else if (strstr(tmpstr, "warnme")) {
989 dprintf("faimtest: icbm: sending non-anon warning\n");
990 aim_send_warning(sess, conn, userinfo->sn, 0);
992 } else if (strstr(tmpstr, "anonwarn")) {
994 dprintf("faimtest: icbm: sending anon warning\n");
995 aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
997 } else if (strstr(tmpstr, "setdirectoryinfo")) {
999 dprintf("faimtest: icbm: sending backwards profile data\n");
1000 aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1002 } else if (strstr(tmpstr, "setinterests")) {
1004 dprintf("faimtest: icbm: setting fun interests\n");
1005 aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1007 } else if (!strncmp(tmpstr, "getfile", 7)) {
1009 if (!priv->ohcaptainmycaptain) {
1011 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1014 getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1016 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1018 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1020 } else if (!strncmp(tmpstr, "create", 6)) {
1022 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1024 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1025 aim_conn_t *chatnavconn;
1027 if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1028 aim_conn_kill(sess, &chatnavconn);
1030 } else if (!strncmp(tmpstr, "join", 4)) {
1032 aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1034 } else if (!strncmp(tmpstr, "leave", 5)) {
1036 aim_chat_leaveroom(sess, "worlddomination");
1038 } else if (!strncmp(tmpstr, "getinfo", 7)) {
1040 aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO);
1041 aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1042 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1043 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1045 } else if (!strncmp(tmpstr, "open directim", 13)) {
1047 directim_start(sess, conn, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1049 } else if(!(strncmp(tmpstr, "lookup", 6))) {
1051 aim_usersearch_address(sess, conn, tmpstr+7);
1053 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1055 aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1057 } else if (!strncmp(tmpstr, "reqauth", 7)) {
1059 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1061 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1063 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1065 } else if (!strncmp(tmpstr, "reqemail", 8)) {
1067 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1069 } else if (!strncmp(tmpstr, "changepass", 8)) {
1071 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1073 } else if (!strncmp(tmpstr, "setemail", 8)) {
1075 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1077 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1085 newbuf = malloc(i+1);
1086 for (z = 0; z < i; z++)
1087 newbuf[z] = (z % 10)+0x30;
1089 aim_send_im(sess, conn, userinfo->sn, 0, newbuf);
1095 dprintf("unknown command.\n");
1096 aim_add_buddy(sess, conn, userinfo->sn);
1104 * Channel 1: Standard Message
1106 static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1109 struct aim_incomingim_ch1_args *args;
1110 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1111 char realmsg[8192+1] = {""};
1113 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1116 clienttype = aim_fingerprintclient(args->fingerprint, args->finlen);
1118 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1119 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1120 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1121 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1122 printuserflags(userinfo->flags);
1123 dinlineprintf("\n");
1125 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1126 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1127 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1128 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1130 dprintf("faimtest: icbm: icbmflags = ");
1131 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1132 dinlineprintf("away ");
1133 if (args->icbmflags & AIM_IMFLAGS_ACK)
1134 dinlineprintf("ackrequest ");
1135 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1136 dinlineprintf("buddyreq ");
1137 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1138 dinlineprintf("hasicon ");
1139 dinlineprintf("\n");
1141 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
1144 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1145 * characters with their equivelent HTML entity.
1147 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1150 for (i = 0; i < args->msglen; i += 2) {
1153 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1155 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1157 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1159 } else { /* something else, do UNICODE entity */
1161 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1170 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1171 * no need to do anything special here. Most
1172 * terminals/whatever will be able to display such characters
1175 * Beware that PC-ASCII 128 through 159 are _not_ actually
1176 * defined in ASCII or ISO 8859-1, and you should send them as
1177 * UNICODE. WinAIM will send these characters in a UNICODE
1178 * message, so you need to do so as well.
1180 * You may not think it necessary to handle UNICODE messages.
1181 * You're probably wrong. For one thing, Microsoft "Smart
1182 * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1183 * but real UNICODE). If you don't parse UNICODE at all, your
1184 * users will get a blank message instead of the message
1185 * containing Smart Quotes.
1188 strncpy(realmsg, args->msg, sizeof(realmsg));
1191 dvprintf("faimtest: icbm: message: %s\n", realmsg);
1193 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1194 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1199 while (realmsg[i] == '<') {
1200 if (realmsg[i] == '<') {
1201 while (realmsg[i] != '>')
1208 faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1216 * Channel 2: Rendevous Request
1218 static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1220 struct aim_incomingim_ch2_args *args;
1222 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1225 if (args->reqclass == AIM_CAPS_VOICE) {
1227 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1228 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1229 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1230 printuserflags(userinfo->flags);
1231 dinlineprintf("\n");
1233 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1234 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1236 } else if (args->reqclass == AIM_CAPS_GETFILE) {
1238 getfile_requested(sess, conn, userinfo, args);
1240 } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1242 dprintf("faimtest: send file!\n");
1244 } else if (args->reqclass == AIM_CAPS_CHAT) {
1246 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1247 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1248 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1249 printuserflags(userinfo->flags);
1250 dinlineprintf("\n");
1252 /* we dont get membersince on chat invites! */
1253 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1254 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1256 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1257 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1258 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1259 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1260 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1261 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1262 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
1264 /* Automatically join room... */
1265 aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
1267 } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1269 dprintf("faimtest: icbm: rendezvous imimage\n");
1271 directim_requested(sess, conn, userinfo, args);
1273 } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1275 dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, args->info.icon.length);
1279 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1285 static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1288 struct aim_userinfo_s *userinfo;
1293 channel = va_arg(ap, fu16_t);
1294 userinfo = va_arg(ap, struct aim_userinfo_s *);
1297 ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, ap);
1298 else if (channel == 2)
1299 ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap);
1301 dvprintf("unsupported channel 0x%04x\n", channel);
1303 dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret);
1308 #ifdef MID_REWROTE_ALL_THE_CRAP
1309 static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
1311 fu16_t change = 0, perms, type;
1317 perms = va_arg(ap, fu16_t);
1318 type = va_arg(ap, fu16_t);
1319 length = va_arg(ap, int);
1320 val = va_arg(ap, char *);
1321 str = va_arg(ap, int);
1324 if (aimutil_get16(command->data+2) == 0x0005)
1327 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1333 static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1335 struct aim_userinfo_s *userinfo;
1339 userinfo = va_arg(ap, struct aim_userinfo_s *);
1342 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1344 userinfo->sn, userinfo->flags,
1345 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1346 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1347 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1348 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1349 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1350 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1351 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1352 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1353 userinfo->capabilities);
1357 static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1359 struct aim_userinfo_s *userinfo;
1363 userinfo = va_arg(ap, struct aim_userinfo_s *);
1366 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1368 userinfo->sn, userinfo->flags,
1369 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1370 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1371 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1372 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1373 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1374 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1375 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1376 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1377 userinfo->capabilities);
1382 static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1388 reason = va_arg(ap, fu16_t);
1391 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1396 static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1403 reason = va_arg(ap, fu16_t);
1404 destsn = va_arg(ap, char *);
1407 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1412 static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1419 reason = va_arg(ap, fu16_t);
1420 destsn = va_arg(ap, char *);
1423 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1428 static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1430 static char *missedreasons[] = {
1432 "Message too large",
1437 static int missedreasonslen = 5;
1440 fu16_t chan, nummissed, reason;
1441 struct aim_userinfo_s *userinfo;
1444 chan = va_arg(ap, fu16_t);
1445 userinfo = va_arg(ap, struct aim_userinfo_s *);
1446 nummissed = va_arg(ap, fu16_t);
1447 reason = va_arg(ap, fu16_t);
1450 dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1456 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1458 static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1465 type = va_arg(ap, fu16_t);
1466 sn = va_arg(ap, char *);
1469 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1474 static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1476 static char *codes[5] = {
1484 fu16_t code, rateclass;
1485 fu32_t windowsize, clear, alert, limit, disconnect;
1486 fu32_t currentavg, maxavg;
1490 /* See code explanations below */
1491 code = va_arg(ap, fu16_t);
1494 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1496 rateclass = va_arg(ap, fu16_t);
1499 * Not sure what this is exactly. I think its the temporal
1500 * relation factor (ie, how to make the rest of the numbers
1501 * make sense in the real world).
1503 windowsize = va_arg(ap, fu32_t);
1505 /* Explained below */
1506 clear = va_arg(ap, fu32_t);
1507 alert = va_arg(ap, fu32_t);
1508 limit = va_arg(ap, fu32_t);
1509 disconnect = va_arg(ap, fu32_t);
1510 currentavg = va_arg(ap, fu32_t);
1511 maxavg = va_arg(ap, fu32_t);
1516 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",
1517 (code < 5)?codes[code]:"invalid",
1524 if (code == AIM_RATE_CODE_CHANGE) {
1526 * Not real sure when these get sent.
1528 if (currentavg >= clear)
1529 aim_conn_setlatency(fr->conn, 0);
1531 } else if (code == AIM_RATE_CODE_WARNING) {
1533 * We start getting WARNINGs the first time we go below the
1534 * 'alert' limit (currentavg < alert) and they stop when
1535 * either we pause long enough for currentavg to go above
1536 * 'clear', or until we flood it bad enough to go below
1537 * 'limit' (and start getting LIMITs instead) or even further
1538 * and go below 'disconnect' and get disconnected completely
1539 * (and won't be able to login right away either).
1541 aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */
1543 } else if (code == AIM_RATE_CODE_LIMIT) {
1545 * When we hit LIMIT, messages will start getting dropped.
1547 aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */
1549 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1551 * The limit is cleared when curavg goes above 'clear'.
1553 aim_conn_setlatency(fr->conn, 0);
1559 static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1563 struct aim_userinfo_s *userinfo;
1566 newevil = va_arg(ap, fu16_t);
1567 userinfo = va_arg(ap, struct aim_userinfo_s *);
1571 * Evil Notifications that are lacking userinfo->sn are anon-warns
1572 * if they are an evil increases, but are not warnings at all if its
1573 * a decrease (its the natural backoff happening).
1575 * newevil is passed as an int representing the new evil value times
1578 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1583 static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1586 char *address, *SNs;
1590 address = va_arg(ap, char *);
1591 num = va_arg(ap, int);
1592 SNs = va_arg(ap, char *);
1595 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
1597 for(i = 0; i < num; i++)
1598 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1599 dinlineprintf("\n");
1604 static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1610 address = va_arg(ap, char *);
1613 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1618 void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
1621 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1623 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1624 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */
1625 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
1626 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1627 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1628 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1629 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1630 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1631 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
1632 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1633 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
1634 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
1635 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
1636 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1637 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1638 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1639 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1640 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1641 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1642 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
1643 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1644 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
1645 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1646 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
1647 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1649 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1650 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1651 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
1653 #ifdef MID_REWROTE_ALL_THE_CRAP
1654 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);