]> andersk Git - libfaim.git/blame - utils/faimtest/faimtest.c
- Fri Sep 7 21:18:51 PDT 2001
[libfaim.git] / utils / faimtest / faimtest.c
CommitLineData
9de3ca7e 1/*
d410cf58 2 * faimtest.
9de3ca7e 3 *
d410cf58 4 * The point of faimtest is twofold:
5 * - Test the functionality of libfaim.
6 * - Demonstrate the functionality of libfaim and how to use it.
9de3ca7e 7 *
d410cf58 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?)
9de3ca7e 15 *
d410cf58 16 * The faimtest code is very ugly. Probably always will be.
9de3ca7e 17 *
d410cf58 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.
9de3ca7e 21 *
22 */
23
b562f484 24#include "faimtest.h"
83ae98f8 25#include <sys/stat.h>
397055b1 26
d410cf58 27char *dprintf_ctime(void)
37ee990e 28{
d410cf58 29 static char retbuf[64];
30 struct tm *lt;
31 struct timeval tv;
32 struct timezone tz;
37ee990e 33
d410cf58 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);
37
38 return retbuf;
37ee990e 39}
96f8b1ed 40
41static char *msgerrreasons[] = {
d410cf58 42 "Invalid error",
43 "Invalid SNAC",
44 "Rate to host",
45 "Rate to client",
46 "Not logged on",
47 "Service unavailable",
48 "Service not defined",
49 "Obsolete SNAC",
50 "Not supported by host",
51 "Not supported by client",
52 "Refused by client",
53 "Reply too big",
54 "Responses lost",
55 "Request denied",
56 "Busted SNAC payload",
57 "Insufficient rights",
58 "In local permit/deny",
59 "Too evil (sender)",
60 "Too evil (receiver)",
61 "User temporarily unavailable",
62 "No match",
63 "List overflow",
64 "Request ambiguous",
65 "Queue full",
66 "Not while on AOL",
67};
96f8b1ed 68static int msgerrreasonslen = 25;
7392c79f 69
d410cf58 70aim_session_t aimsess;
b562f484 71int keepgoing = 1;
72
d410cf58 73/*
74 * This is used to intercept debugging/diagnostic messages from libfaim.
75 *
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.
78 *
79 */
80static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
646c6b52 81{
82
355229fe 83 vfprintf(stderr, format, va);
646c6b52 84
355229fe 85 return;
646c6b52 86}
37ee990e 87
d410cf58 88int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
22517493 89{
90
d410cf58 91 /* XXX fix libfaim to support this */
92 dvprintf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
22517493 93
94#if 0
355229fe 95 /*
96 * This is an alternate location for starting the login process.
97 */
98 /* XXX should do more checking to make sure its really the right AUTH conn */
d410cf58 99 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
355229fe 100 /* do NOT send a flapversion, request_login will send it if needed */
d410cf58 101 aim_request_login(sess, fr->conn, priv->screenname);
355229fe 102 dprintf("faimtest: login request sent\n");
103 }
22517493 104#endif
105
355229fe 106 return 1;
22517493 107}
108
109/*
110 * This is a frivilous callback. You don't need it. I only used it for
111 * debugging non-blocking connects.
112 *
113 * If packets are sent to a conn before its fully connected, they
114 * will be queued and then transmitted when the connection completes.
115 *
116 */
d410cf58 117int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
22517493 118{
355229fe 119 va_list ap;
d410cf58 120 aim_conn_t *conn;
22517493 121
d410cf58 122 va_start(ap, fr);
123 conn = va_arg(ap, aim_conn_t *);
355229fe 124 va_end(ap);
22517493 125
355229fe 126 if (conn)
127 dvprintf("faimtest: connection on %d completed\n", conn->fd);
128
129 return 1;
22517493 130}
131
999b6d5f 132#ifdef _WIN32
133/*
134 * This is really all thats needed to link against libfaim on win32.
135 *
136 * Note that this particular version of faimtest has never been tested
d410cf58 137 * on win32, but I'm fairly sure it should work.
999b6d5f 138 */
d410cf58 139static int initwsa(void)
999b6d5f 140{
355229fe 141 WORD wVersionRequested;
142 WSADATA wsaData;
999b6d5f 143
355229fe 144 wVersionRequested = MAKEWORD(2,2);
145 return WSAStartup(wVersionRequested, &wsaData);
999b6d5f 146}
147#endif /* _WIN32 */
148
d410cf58 149/*
150 * This is unrealistic. Most clients will not be able to do this.
151 */
b562f484 152int faimtest_init(void)
153{
d410cf58 154 aim_conn_t *stdinconn = NULL;
b562f484 155
355229fe 156 if (!(stdinconn = aim_newconn(&aimsess, 0, NULL))) {
157 dprintf("unable to create connection for stdin!\n");
158 return -1;
159 }
b562f484 160
355229fe 161 stdinconn->fd = STDIN_FILENO;
b562f484 162
355229fe 163 return 0;
b562f484 164}
165
37ee990e 166int main(int argc, char **argv)
9de3ca7e 167{
d410cf58 168 aim_conn_t *waitingconn = NULL;
355229fe 169 int i;
170 int selstat = 0;
171 static int faimtest_mode = 0;
172 struct timeval tv;
173 time_t lastnop = 0;
174 const char *buddyiconpath = NULL;
d410cf58 175 struct faimtest_priv priv = {
176 NULL, NULL, NULL, NULL,
177 NULL, NULL, NULL, NULL,
178 0,
179 NULL, NULL,
180 NULL, 0, 0, 0
181 };
355229fe 182
d410cf58 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");
355229fe 189
d410cf58 190 priv.listingpath = getenv("LISTINGPATH");
355229fe 191
192 while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:i:")) != EOF) {
193 switch (i) {
d410cf58 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;
355229fe 202 case 'o': faimtest_mode = 1; break; /* half old interface */
203 case 'O': faimtest_mode = 2; break; /* full old interface */
d410cf58 204 case 'b': priv.aimbinarypath = optarg; break;
355229fe 205 case 'i': buddyiconpath = optarg; break;
206 case 'h':
207 default:
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");
222 exit(0);
223 }
224 }
37ee990e 225
999b6d5f 226#ifdef _WIN32
355229fe 227 if (initwsa() != 0) {
228 dprintf("faimtest: could not initialize windows sockets\n");
229 return -1;
230 }
999b6d5f 231#endif /* _WIN32 */
232
355229fe 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 ! */
d410cf58 236 aimsess.aux_data = &priv;
7b91722d 237
d410cf58 238 if (priv.listingpath) {
355229fe 239 char *listingname;
240
d410cf58 241 listingname = (char *)calloc(1, strlen(priv.listingpath)+strlen("/listing.txt"));
242 sprintf(listingname, "%s/listing.txt", priv.listingpath);
355229fe 243
d410cf58 244 if ((priv.listingfile = fopen(listingname, "r")) == NULL)
355229fe 245 dvprintf("Couldn't open %s... disabling that shit.\n", listingname);
7b91722d 246
355229fe 247 free(listingname);
248 }
50038c74 249
355229fe 250 if (buddyiconpath) {
251 struct stat st;
252 FILE *f;
7b91722d 253
355229fe 254 if ((stat(buddyiconpath, &st) != -1) && (st.st_size <= MAXICONLEN) && (f = fopen(buddyiconpath, "r"))) {
7b91722d 255
d410cf58 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);
7b91722d 260
d410cf58 261 priv.buddyiconsum = aim_iconsum(priv.buddyicon, priv.buddyiconlen);
7b91722d 262
d410cf58 263 dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", priv.buddyiconlen, buddyiconpath, priv.buddyiconsum);
bb0dc593 264
355229fe 265 fclose(f);
9bf14d44 266
355229fe 267 } else
268 dvprintf("could not open buddy icon %s\n", buddyiconpath);
9de3ca7e 269
355229fe 270 }
d32954e7 271
355229fe 272 faimtest_init();
d32954e7 273
355229fe 274 if (faimtest_mode < 2)
275 cmd_init();
d32954e7 276
355229fe 277 if (faimtest_mode >= 1) {
d410cf58 278 if (login(&aimsess, priv.screenname, priv.password) == -1) {
355229fe 279 if (faimtest_mode < 2)
280 cmd_uninit();
281 exit(-1);
282 }
283 }
b8d0da45 284
355229fe 285 while (keepgoing) {
286
d410cf58 287 /* XXX uh. */
355229fe 288 tv.tv_sec = 5;
289 tv.tv_usec = 0;
290
291 waitingconn = aim_select(&aimsess, &tv, &selstat);
292
d410cf58 293 if (priv.connected && ((time(NULL) - lastnop) > 30)) {
355229fe 294 lastnop = time(NULL);
295 aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS));
296 }
297
298 if (selstat == -1) { /* error */
299 keepgoing = 0; /* fall through */
300 } else if (selstat == 0) { /* no events pending */
301 ;
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)) {
306 cmd_gotkey();
307 } else {
308 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
d410cf58 309#if 0
355229fe 310 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
311 dprintf("connection error (rend out)\n");
312 aim_conn_kill(&aimsess, &waitingconn);
313 }
d410cf58 314#endif
355229fe 315 } else {
316 if (aim_get_command(&aimsess, waitingconn) >= 0) {
317 aim_rxdispatch(&aimsess);
318 } else {
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);
324 } else
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)
329 break;
330 }
331 }
332 }
333 }
334 }
7392c79f 335 }
9de3ca7e 336
355229fe 337 /* close up all connections, dead or no */
338 aim_session_kill(&aimsess);
9de3ca7e 339
355229fe 340 if (faimtest_mode < 2) {
341 printf("\n");
342 cmd_uninit();
343 }
b562f484 344
d410cf58 345 free(priv.buddyicon);
7b91722d 346
355229fe 347 /* Get out */
348 exit(0);
9de3ca7e 349}
350
d410cf58 351int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...)
c78446b5 352{
d410cf58 353 int famcount, i;
354 fu16_t *families;
355 va_list ap;
c78446b5 356
d410cf58 357 va_start(ap, fr);
358 famcount = va_arg(ap, int);
359 families = va_arg(ap, fu16_t *);
360 va_end(ap);
361
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]);
365 dinlineprintf("\n");
c78446b5 366
d410cf58 367 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
c78446b5 368
d410cf58 369 aim_auth_setversions(sess, fr->conn);
370 aim_bos_reqrate(sess, fr->conn); /* request rate info */
c78446b5 371
d410cf58 372 dprintf("done with auth server ready\n");
355229fe 373
d410cf58 374 } else if (fr->conn->type == AIM_CONN_TYPE_BOS) {
355229fe 375
d410cf58 376 aim_setversions(sess, fr->conn);
377 aim_bos_reqrate(sess, fr->conn); /* request rate info */
355229fe 378
d410cf58 379 dprintf("done with BOS server ready\n");
355229fe 380 }
d410cf58 381
382 return 1;
383}
384
385int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
386{
387 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
388 va_list ap;
389 fu16_t code;
390 char *msg;
391
392 va_start(ap, fr);
393 code = va_arg(ap, int);
394 msg = va_arg(ap, char *);
395 va_end(ap);
396
397 dvprintf("connerr: Code 0x%04x: %s\n", code, msg);
398 aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
399
400 priv->connected = 0;
401
402 return 1;
403}
404
405#if 0
406static int faimtest_rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...)
407{
408
409 aim_bos_ackrateresp(sess, fr->conn);
410 aim_auth_clientready(sess, fr->conn);
411
412 dprintf("faimtest: connected to authorization/admin service\n");
413
414 return 1;
415}
416
417int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
418{
419 int status;
420 va_list ap;
421
422 va_start(ap, fr);
423 status = va_arg(ap, int); /* status code of confirmation request */
424 va_end(ap);
425
426 dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
427
428 return 1;
429}
430
431
432#endif
433
434#if 0
435/*
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.
440 *
441 */
442int faimtest_parse_unknown(aim_session_t *sess, aim_frame_t *fr, ...)
443{
444 int i;
445
446 aim_bstream_rewind(&fr->data); /* boo! */
447
448 dprintf("\nReceived unknown packet:");
449 for (i = 0; aim_bstream_empty(&fr->data); i++) {
450 if ((i % 8) == 0)
451 dinlineprintf("\n\t");
452 dvinlineprintf("0x%2x ", aimbs_get8(&fr->data));
355229fe 453 }
d410cf58 454 dinlineprintf("\n\n");
355229fe 455
456 return 1;
c78446b5 457}
d410cf58 458#endif
c78446b5 459
d410cf58 460int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
461{
462 va_list ap;
463 int serviceid;
464 char *ip;
465 fu8_t *cookie;
466
467 va_start(ap, fr);
468 serviceid = va_arg(ap, int);
469 ip = va_arg(ap, char *);
470 cookie = va_arg(ap, fu8_t *);
471
472 if (serviceid == 0x0005) { /* Adverts */
473#if 0
474 aim_conn_t *tstconn;
475
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");
479 } else {
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");
487 }
488#endif
489 } else if (serviceid == 0x0007) { /* Authorizer */
490#if 0
491 aim_conn_t *tstconn;
492
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");
496 } else {
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");
508 }
509#endif
510 } else if (serviceid == 0x000d) { /* ChatNav */
511
512 chatnav_redirect(sess, ip, cookie);
513
514 } else if (serviceid == 0x000e) { /* Chat */
515 char *roomname = NULL;
516 int exchange;
517
518 roomname = va_arg(ap, char *);
519 exchange = va_arg(ap, int);
520
521 chat_redirect(sess, ip, cookie, roomname, exchange);
522
523 } else {
524 dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
525 }
526
527 va_end(ap);
528
529 return 1;
530}
531
532static int faimtest_rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...)
533{
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"};
538
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);
542
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);
548
549 /* send the buddy list and profile (required, even if empty) */
550 aim_bos_setbuddylist(sess, fr->conn, buddies);
551
552 aim_reqicbmparams(sess, fr->conn);
553
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);
558
559 return 1;
560}
561
562static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
00ef5271 563{
355229fe 564 struct aim_icbmparameters *params;
565 va_list ap;
00ef5271 566
d410cf58 567 va_start(ap, fr);
355229fe 568 params = va_arg(ap, struct aim_icbmparameters *);
569 va_end(ap);
00ef5271 570
355229fe 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);
00ef5271 572
36a61e0d 573 /*
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
577 * useful).
578 */
355229fe 579 params->maxmsglen = 8000;
36a61e0d 580 params->minmsginterval = 0; /* in milliseconds */
355229fe 581
d410cf58 582 aim_seticbmparam(sess, fr->conn, params);
355229fe 583
584 return 1;
00ef5271 585}
586
d410cf58 587static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...)
ee49b735 588{
355229fe 589 int vercount, i;
d410cf58 590 fu8_t *versions;
355229fe 591 va_list ap;
592
d410cf58 593 va_start(ap, fr);
355229fe 594 vercount = va_arg(ap, int); /* number of family/version pairs */
d410cf58 595 versions = va_arg(ap, fu8_t *);
355229fe 596 va_end(ap);
597
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 */);
603 }
604 dinlineprintf("\n");
ee49b735 605
355229fe 606 return 1;
ee49b735 607}
608
d410cf58 609static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
64c78745 610{
355229fe 611 va_list ap;
d410cf58 612 fu16_t maxbuddies, maxwatchers;
64c78745 613
d410cf58 614 va_start(ap, fr);
615 maxbuddies = va_arg(ap, int);
616 maxwatchers = va_arg(ap, int);
355229fe 617 va_end(ap);
64c78745 618
d410cf58 619 dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
64c78745 620
355229fe 621 return 1;
64c78745 622}
623
d410cf58 624static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 625{
d410cf58 626 va_list ap;
627 fu16_t maxpermits, maxdenies;
9de3ca7e 628
d410cf58 629 va_start(ap, fr);
630 maxpermits = va_arg(ap, int);
631 maxdenies = va_arg(ap, int);
632 va_end(ap);
633
634 dvprintf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
96f8b1ed 635
d410cf58 636 aim_bos_clientready(sess, fr->conn);
96f8b1ed 637
d410cf58 638 dprintf("officially connected to BOS.\n");
96f8b1ed 639
d410cf58 640 return 1;
96f8b1ed 641}
642
d410cf58 643static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
c78446b5 644{
d410cf58 645 va_list ap;
646 fu16_t maxsiglen;
96f8b1ed 647
d410cf58 648 va_start(ap, fr);
649 maxsiglen = va_arg(ap, int);
650 va_end(ap);
c78446b5 651
d410cf58 652 dvprintf("locate rights: max signature length = %d\n", maxsiglen);
37ee990e 653
d410cf58 654 return 1;
37ee990e 655}
656
d410cf58 657static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
b39e0a91 658{
d410cf58 659 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
660 va_list ap;
661 fu16_t interval;
b39e0a91 662
d410cf58 663 va_start(ap, fr);
664 interval = va_arg(ap, int);
665 va_end(ap);
b39e0a91 666
d410cf58 667 dvprintf("minimum report interval: %d (seconds?)\n", interval);
b39e0a91 668
d410cf58 669 if (!priv->connected)
670 priv->connected++;
b39e0a91 671
d410cf58 672#if 0
673 aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */
674 aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */
37ee990e 675
d410cf58 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);
679#endif
37ee990e 680
d410cf58 681 aim_reqicbmparams(sess, fr->conn);
c78446b5 682
d410cf58 683 return 1;
c78446b5 684}
685
d410cf58 686static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 687{
d410cf58 688 static char *codes[] = {
689 "Unknown",
690 "Mandatory upgrade",
691 "Advisory upgrade",
692 "System bulletin",
693 "Top o' the world!"
694 };
695 static int codeslen = 5;
696 char *msg;
697 fu16_t id;
698 va_list ap;
699
700 va_start(ap, fr);
701 id = va_arg(ap, int);
702 msg = va_arg(ap, char *);
703 va_end(ap);
704
705 dvprintf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown");
706
707 return 1;
9de3ca7e 708}
709
83ae98f8 710/*
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
714 * end of it.
715 *
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
720 * by length).
721 *
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
724 * the mod.
725 *
726 * Note to Bosco's Brigade: if you'd like to break this, put the
727 * module name on an invalid request.
728 *
729 */
d410cf58 730static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
b1eac25a 731{
d410cf58 732 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
733 FILE *f;
734 static const char defaultmod[] = "aim.exe";
735 char *filename = NULL;
736 struct stat st;
737 unsigned char *buf;
738 int invalid = 0;
739
740 if (!bufret || !buflenret)
741 return -1;
b1eac25a 742
d410cf58 743 if (modname) {
001c9b80 744
d410cf58 745 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
746 dperror("memrequest: malloc");
747 return -1;
748 }
5ac961d5 749
d410cf58 750 sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
5ac961d5 751
d410cf58 752 } else {
328837f7 753
d410cf58 754 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
755 dperror("memrequest: malloc");
756 return -1;
757 }
328837f7 758
d410cf58 759 sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
b1eac25a 760
d410cf58 761 }
83ae98f8 762
d410cf58 763 if (stat(filename, &st) == -1) {
764 if (!modname) {
765 dperror("memrequest: stat");
766 free(filename);
767 return -1;
768 }
769 invalid = 1;
770 }
83ae98f8 771
d410cf58 772 if (!invalid) {
773 if ((offset > st.st_size) || (len > st.st_size))
774 invalid = 1;
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;
779 }
83ae98f8 780
d410cf58 781 if (!invalid && len)
782 len %= 4096;
83ae98f8 783
d410cf58 784 if (invalid) {
785 int i;
f6a4f6b7 786
d410cf58 787 free(filename); /* not needed */
f6a4f6b7 788
d410cf58 789 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
83ae98f8 790
d410cf58 791 i = 8;
792 if (modname)
793 i += strlen(modname);
f6a4f6b7 794
d410cf58 795 if (!(buf = malloc(i)))
796 return -1;
83ae98f8 797
d410cf58 798 i = 0;
83ae98f8 799
d410cf58 800 if (modname) {
801 memcpy(buf, modname, strlen(modname));
802 i += strlen(modname);
803 }
83ae98f8 804
d410cf58 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;
83ae98f8 814
d410cf58 815 *bufret = buf;
816 *buflenret = i;
83ae98f8 817
d410cf58 818 } else {
83ae98f8 819
d410cf58 820 if (!(buf = malloc(len))) {
821 free(filename);
822 return -1;
823 }
83ae98f8 824
d410cf58 825 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
5ac961d5 826
d410cf58 827 if (!(f = fopen(filename, "r"))) {
828 dperror("memrequest: fopen");
829 free(filename);
830 free(buf);
831 return -1;
832 }
b1eac25a 833
d410cf58 834 free(filename);
b1eac25a 835
d410cf58 836 if (fseek(f, offset, SEEK_SET) == -1) {
837 dperror("memrequest: fseek");
838 fclose(f);
839 free(buf);
840 return -1;
841 }
83ae98f8 842
d410cf58 843 if (fread(buf, len, 1, f) != 1) {
844 dperror("memrequest: fread");
845 fclose(f);
846 free(buf);
847 return -1;
848 }
b1eac25a 849
d410cf58 850 fclose(f);
851
852 *bufret = buf;
853 *buflenret = len;
854
855 }
856
857 return 0; /* success! */
b1eac25a 858}
859
860/*
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.
866 */
d410cf58 867static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
b1eac25a 868{
d410cf58 869 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
870 va_list ap;
871 fu32_t offset, len;
872 char *modname;
873 unsigned char *buf;
874 int buflen;
875
876 va_start(ap, fr);
877 offset = va_arg(ap, fu32_t);
878 len = va_arg(ap, fu32_t);
879 modname = va_arg(ap, char *);
880 va_end(ap);
b1eac25a 881
d410cf58 882 if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
b1eac25a 883
d410cf58 884 aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 885
d410cf58 886 free(buf);
b1eac25a 887
d410cf58 888 } else {
b1eac25a 889
d410cf58 890 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
b1eac25a 891
d410cf58 892 aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 893
d410cf58 894 }
b1eac25a 895
d410cf58 896 return 1;
b1eac25a 897}
898
d410cf58 899static void printuserflags(fu16_t flags)
9de3ca7e 900{
d410cf58 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 ");
917 return;
9de3ca7e 918}
919
d410cf58 920static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
a15d82b1 921{
d410cf58 922 struct aim_userinfo_s *userinfo;
923 char *prof_encoding = NULL;
924 char *prof = NULL;
925 fu16_t inforeq = 0;
a15d82b1 926
d410cf58 927 va_list ap;
928 va_start(ap, fr);
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);
933 va_end(ap);
934
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);
939 dinlineprintf("\n");
940
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);
944
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]");
951 } else
952 dprintf("faimtest: userinfo: unknown info request\n");
953
954 return 1;
9de3ca7e 955}
956
d410cf58 957static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr)
d2587300 958{
d410cf58 959 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
d2587300 960
d410cf58 961 if (!strncmp(tmpstr, "disconnect", 10)) {
d2587300 962
d410cf58 963 logout(sess);
d2587300 964
d410cf58 965 } else if (strstr(tmpstr, "goodday")) {
7b91722d 966
d410cf58 967 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
7b91722d 968
d410cf58 969 } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
970 struct aim_sendimext_args args;
971 static const char iconmsg[] = {"I have an icon"};
7b91722d 972
d410cf58 973 args.destsn = userinfo->sn;
974 args.flags = AIM_IMFLAGS_HASICON;
975 args.msg = iconmsg;
976 args.msglen = strlen(iconmsg);
977 args.iconlen = priv->buddyiconlen;
978 args.iconstamp = priv->buddyiconstamp;
979 args.iconsum = priv->buddyiconsum;
7b91722d 980
d410cf58 981 aim_send_im_ext(sess, conn, &args);
7b91722d 982
84e0ca17 983 } else if (strstr(tmpstr, "havefeat")) {
984 struct aim_sendimext_args args;
985 static const char featmsg[] = {"I have nifty features."};
986 fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
987
988 args.destsn = userinfo->sn;
989 args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
990 args.msg = featmsg;
991 args.msglen = strlen(featmsg);
992 args.features = features;
993 args.featureslen = sizeof(features);
994
995 aim_send_im_ext(sess, conn, &args);
996
d410cf58 997 } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
d2587300 998
d410cf58 999 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
d2587300 1000
d410cf58 1001 } else if (strstr(tmpstr, "warnme")) {
d2587300 1002
d410cf58 1003 dprintf("faimtest: icbm: sending non-anon warning\n");
1004 aim_send_warning(sess, conn, userinfo->sn, 0);
d2587300 1005
d410cf58 1006 } else if (strstr(tmpstr, "anonwarn")) {
d2587300 1007
d410cf58 1008 dprintf("faimtest: icbm: sending anon warning\n");
1009 aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
d2587300 1010
d410cf58 1011 } else if (strstr(tmpstr, "setdirectoryinfo")) {
d2587300 1012
d410cf58 1013 dprintf("faimtest: icbm: sending backwards profile data\n");
1014 aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
d2587300 1015
d410cf58 1016 } else if (strstr(tmpstr, "setinterests")) {
d2587300 1017
d410cf58 1018 dprintf("faimtest: icbm: setting fun interests\n");
1019 aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
d2587300 1020
d410cf58 1021 } else if (!strncmp(tmpstr, "getfile", 7)) {
d2587300 1022
d410cf58 1023 if (!priv->ohcaptainmycaptain) {
d2587300 1024
d410cf58 1025 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
d2587300 1026
d410cf58 1027 } else
1028 getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1029
1030 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
d2587300 1031
d410cf58 1032 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
d2587300 1033
d410cf58 1034 } else if (!strncmp(tmpstr, "create", 6)) {
d2587300 1035
d410cf58 1036 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
d2587300 1037
d410cf58 1038 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1039 aim_conn_t *chatnavconn;
d2587300 1040
d410cf58 1041 if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1042 aim_conn_kill(sess, &chatnavconn);
d2587300 1043
d410cf58 1044 } else if (!strncmp(tmpstr, "join", 4)) {
d2587300 1045
d410cf58 1046 aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
d2587300 1047
d410cf58 1048 } else if (!strncmp(tmpstr, "leave", 5)) {
d2587300 1049
d410cf58 1050 aim_chat_leaveroom(sess, "worlddomination");
d2587300 1051
d410cf58 1052 } else if (!strncmp(tmpstr, "getinfo", 7)) {
d2587300 1053
d410cf58 1054 aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO);
1055 aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1056 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1057 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
d2587300 1058
d410cf58 1059 } else if (!strncmp(tmpstr, "open directim", 13)) {
d2587300 1060
d410cf58 1061 directim_start(sess, conn, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
d2587300 1062
d410cf58 1063 } else if(!(strncmp(tmpstr, "lookup", 6))) {
d2587300 1064
d410cf58 1065 aim_usersearch_address(sess, conn, tmpstr+7);
d2587300 1066
d410cf58 1067 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
d2587300 1068
d410cf58 1069 aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
d2587300 1070
d410cf58 1071 } else if (!strncmp(tmpstr, "reqauth", 7)) {
d2587300 1072
d410cf58 1073 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
d2587300 1074
d410cf58 1075 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
d2587300 1076
d410cf58 1077 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
d2587300 1078
d410cf58 1079 } else if (!strncmp(tmpstr, "reqemail", 8)) {
d2587300 1080
d410cf58 1081 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
d2587300 1082
d410cf58 1083 } else if (!strncmp(tmpstr, "changepass", 8)) {
d2587300 1084
d410cf58 1085 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
d2587300 1086
d410cf58 1087 } else if (!strncmp(tmpstr, "setemail", 8)) {
d2587300 1088
d410cf58 1089 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
d2587300 1090
d410cf58 1091 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1092 int i;
d2587300 1093
d410cf58 1094 i = atoi(tmpstr+8);
1095 if (i < 10000) {
1096 char *newbuf;
1097 int z;
d2587300 1098
d410cf58 1099 newbuf = malloc(i+1);
1100 for (z = 0; z < i; z++)
1101 newbuf[z] = (z % 10)+0x30;
1102 newbuf[i] = '\0';
1103 aim_send_im(sess, conn, userinfo->sn, 0, newbuf);
1104 free(newbuf);
1105 }
d2587300 1106
d410cf58 1107 } else {
d2587300 1108
d410cf58 1109 dprintf("unknown command.\n");
1110 aim_add_buddy(sess, conn, userinfo->sn);
d2587300 1111
d410cf58 1112 }
d2587300 1113
d410cf58 1114 return 0;
d2587300 1115}
1116
9de3ca7e 1117/*
d410cf58 1118 * Channel 1: Standard Message
9de3ca7e 1119 */
d410cf58 1120static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
9de3ca7e 1121{
e1b8c575 1122 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
d410cf58 1123 char *tmpstr;
1124 struct aim_incomingim_ch1_args *args;
1125 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1126 char realmsg[8192+1] = {""};
7a449b5d 1127
d410cf58 1128 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1129 va_end(ap);
7a449b5d 1130
84e0ca17 1131 clienttype = aim_fingerprintclient(args->features, args->featureslen);
9de3ca7e 1132
d410cf58 1133 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1134 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1135 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1136 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1137 printuserflags(userinfo->flags);
1138 dinlineprintf("\n");
7392c79f 1139
d410cf58 1140 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1141 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1142 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1143 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1144
1145 dprintf("faimtest: icbm: icbmflags = ");
1146 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1147 dinlineprintf("away ");
1148 if (args->icbmflags & AIM_IMFLAGS_ACK)
1149 dinlineprintf("ackrequest ");
1150 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1151 dinlineprintf("buddyreq ");
1152 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1153 dinlineprintf("hasicon ");
1154 dinlineprintf("\n");
7392c79f 1155
d410cf58 1156 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
646c6b52 1157
d410cf58 1158 /*
1159 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1160 * characters with their equivelent HTML entity.
1161 */
1162 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1163 int i;
7392c79f 1164
d410cf58 1165 for (i = 0; i < args->msglen; i += 2) {
1166 fu16_t uni;
7392c79f 1167
d410cf58 1168 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
7392c79f 1169
d410cf58 1170 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
7392c79f 1171
d410cf58 1172 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
7392c79f 1173
d410cf58 1174 } else { /* something else, do UNICODE entity */
7392c79f 1175
d410cf58 1176 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
7392c79f 1177
d410cf58 1178 }
871e2fd0 1179
d410cf58 1180 }
871e2fd0 1181
d410cf58 1182 } else {
1183
1184 /*
1185 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1186 * no need to do anything special here. Most
1187 * terminals/whatever will be able to display such characters
1188 * unmodified.
1189 *
1190 * Beware that PC-ASCII 128 through 159 are _not_ actually
1191 * defined in ASCII or ISO 8859-1, and you should send them as
1192 * UNICODE. WinAIM will send these characters in a UNICODE
1193 * message, so you need to do so as well.
1194 *
1195 * You may not think it necessary to handle UNICODE messages.
1196 * You're probably wrong. For one thing, Microsoft "Smart
1197 * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1198 * but real UNICODE). If you don't parse UNICODE at all, your
1199 * users will get a blank message instead of the message
1200 * containing Smart Quotes.
1201 *
1202 */
1203 strncpy(realmsg, args->msg, sizeof(realmsg));
1204 }
3b101546 1205
d410cf58 1206 dvprintf("faimtest: icbm: message: %s\n", realmsg);
7392c79f 1207
d410cf58 1208 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1209 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
7392c79f 1210
d410cf58 1211 if (realmsg) {
1212 int i = 0;
9de3ca7e 1213
d410cf58 1214 while (realmsg[i] == '<') {
1215 if (realmsg[i] == '<') {
1216 while (realmsg[i] != '>')
1217 i++;
1218 i++;
1219 }
1220 }
1221 tmpstr = realmsg+i;
9de3ca7e 1222
d410cf58 1223 faimtest_handlecmd(sess, conn, userinfo, tmpstr);
64c78745 1224
d410cf58 1225 }
9de3ca7e 1226
e1b8c575 1227 if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ))
1228 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1229
d410cf58 1230 return 1;
9de3ca7e 1231}
1232
d410cf58 1233/*
1234 * Channel 2: Rendevous Request
1235 */
1236static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
9de3ca7e 1237{
d410cf58 1238 struct aim_incomingim_ch2_args *args;
9de3ca7e 1239
d410cf58 1240 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1241 va_end(ap);
9de3ca7e 1242
d410cf58 1243 if (args->reqclass == AIM_CAPS_VOICE) {
96f8b1ed 1244
d410cf58 1245 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1246 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1247 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1248 printuserflags(userinfo->flags);
1249 dinlineprintf("\n");
ee49b735 1250
d410cf58 1251 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1252 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
e80a0fa9 1253
d410cf58 1254 } else if (args->reqclass == AIM_CAPS_GETFILE) {
1255
1256 getfile_requested(sess, conn, userinfo, args);
1257
1258 } else if (args->reqclass == AIM_CAPS_SENDFILE) {
96f8b1ed 1259
d410cf58 1260 dprintf("faimtest: send file!\n");
1449ad2b 1261
d410cf58 1262 } else if (args->reqclass == AIM_CAPS_CHAT) {
1449ad2b 1263
d410cf58 1264 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1265 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1266 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1267 printuserflags(userinfo->flags);
1268 dinlineprintf("\n");
355229fe 1269
d410cf58 1270 /* we dont get membersince on chat invites! */
1271 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1272 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1449ad2b 1273
d410cf58 1274 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1275 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1276 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1277 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1278 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1279 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1280 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
96f8b1ed 1281
d410cf58 1282 /* Automatically join room... */
1283 aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
96f8b1ed 1284
d410cf58 1285 } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
355229fe 1286
d410cf58 1287 dprintf("faimtest: icbm: rendezvous imimage\n");
96f8b1ed 1288
d410cf58 1289 directim_requested(sess, conn, userinfo, args);
96f8b1ed 1290
d410cf58 1291 } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
01b59e1e 1292
e1b8c575 1293 dvprintf("faimtest: Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length);
d410cf58 1294
1295 } else {
1296
1297 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1298 }
355229fe 1299
1300 return 1;
01b59e1e 1301}
9de3ca7e 1302
d410cf58 1303static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 1304{
d410cf58 1305 fu16_t channel;
355229fe 1306 struct aim_userinfo_s *userinfo;
d410cf58 1307 va_list ap;
1308 int ret = 0;
9de3ca7e 1309
d410cf58 1310 va_start(ap, fr);
1311 channel = va_arg(ap, fu16_t);
355229fe 1312 userinfo = va_arg(ap, struct aim_userinfo_s *);
355229fe 1313
d410cf58 1314 if (channel == 1)
1315 ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, ap);
1316 else if (channel == 2)
1317 ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap);
1318 else
1319 dvprintf("unsupported channel 0x%04x\n", channel);
1320
1321 dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret);
355229fe 1322
1323 return 1;
9de3ca7e 1324}
1325
d410cf58 1326#ifdef MID_REWROTE_ALL_THE_CRAP
1327static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
01b59e1e 1328{
d410cf58 1329 fu16_t change = 0, perms, type;
1330 int length, str;
1331 char *val;
355229fe 1332 va_list ap;
9de3ca7e 1333
d410cf58 1334 va_start(ap, fr);
1335 perms = va_arg(ap, fu16_t);
1336 type = va_arg(ap, fu16_t);
1337 length = va_arg(ap, int);
1338 val = va_arg(ap, char *);
1339 str = va_arg(ap, int);
355229fe 1340 va_end(ap);
1341
d410cf58 1342 if (aimutil_get16(command->data+2) == 0x0005)
1343 change = 1;
1344
1345 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
355229fe 1346
1347 return 1;
01b59e1e 1348}
d410cf58 1349#endif
0c20631f 1350
d410cf58 1351static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1352{
355229fe 1353 struct aim_userinfo_s *userinfo;
0c20631f 1354
d410cf58 1355 va_list ap;
1356 va_start(ap, fr);
355229fe 1357 userinfo = va_arg(ap, struct aim_userinfo_s *);
1358 va_end(ap);
0c20631f 1359
d410cf58 1360 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1361 time(NULL),
1362 userinfo->sn, userinfo->flags,
1363 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1364 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1365 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1366 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1367 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1368 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1369 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1370 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1371 userinfo->capabilities);
355229fe 1372 return 1;
0c20631f 1373}
1374
d410cf58 1375static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1376{
355229fe 1377 struct aim_userinfo_s *userinfo;
d410cf58 1378 va_list ap;
1379
1380 va_start(ap, fr);
355229fe 1381 userinfo = va_arg(ap, struct aim_userinfo_s *);
1382 va_end(ap);
37ee990e 1383
d410cf58 1384 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1385 time(NULL),
1386 userinfo->sn, userinfo->flags,
1387 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1388 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1389 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1390 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1391 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1392 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1393 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1394 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1395 userinfo->capabilities);
355229fe 1396
1397 return 1;
0c20631f 1398}
1399
d410cf58 1400static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1401{
355229fe 1402 va_list ap;
d410cf58 1403 fu16_t reason;
355229fe 1404
d410cf58 1405 va_start(ap, fr);
1406 reason = va_arg(ap, fu16_t);
1407 va_end(ap);
355229fe 1408
d410cf58 1409 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
355229fe 1410
1411 return 1;
0c20631f 1412}
1413
d410cf58 1414static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1415{
355229fe 1416 va_list ap;
d410cf58 1417 char *destsn;
1418 fu16_t reason;
355229fe 1419
d410cf58 1420 va_start(ap, fr);
1421 reason = va_arg(ap, fu16_t);
1422 destsn = va_arg(ap, char *);
355229fe 1423 va_end(ap);
1424
d410cf58 1425 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
0c20631f 1426
355229fe 1427 return 1;
0c20631f 1428}
1429
d410cf58 1430static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
5e02cf44 1431{
355229fe 1432 va_list ap;
d410cf58 1433 char *destsn;
1434 fu16_t reason;
5e02cf44 1435
d410cf58 1436 va_start(ap, fr);
1437 reason = va_arg(ap, fu16_t);
1438 destsn = va_arg(ap, char *);
355229fe 1439 va_end(ap);
5e02cf44 1440
d410cf58 1441 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
d32954e7 1442
355229fe 1443 return 1;
5e02cf44 1444}
e5012450 1445
d410cf58 1446static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1447{
1448 static char *missedreasons[] = {
1449 "Invalid (0)",
1450 "Message too large",
1451 "Rate exceeded",
1452 "Evil Sender",
1453 "Evil Receiver"
1454 };
1455 static int missedreasonslen = 5;
e5012450 1456
d410cf58 1457 va_list ap;
1458 fu16_t chan, nummissed, reason;
1459 struct aim_userinfo_s *userinfo;
e5012450 1460
d410cf58 1461 va_start(ap, fr);
1462 chan = va_arg(ap, fu16_t);
1463 userinfo = va_arg(ap, struct aim_userinfo_s *);
1464 nummissed = va_arg(ap, fu16_t);
1465 reason = va_arg(ap, fu16_t);
1466 va_end(ap);
e5012450 1467
d410cf58 1468 dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
e5012450 1469
355229fe 1470 return 1;
e5012450 1471}
1a8c261b 1472
1473/*
646c6b52 1474 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1a8c261b 1475 */
d410cf58 1476static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1a8c261b 1477{
355229fe 1478 va_list ap;
d410cf58 1479 fu16_t type;
355229fe 1480 char *sn = NULL;
1a8c261b 1481
d410cf58 1482 va_start(ap, fr);
1483 type = va_arg(ap, fu16_t);
355229fe 1484 sn = va_arg(ap, char *);
1485 va_end(ap);
1a8c261b 1486
355229fe 1487 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1a8c261b 1488
355229fe 1489 return 1;
1a8c261b 1490}
1491
d410cf58 1492static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
871e2fd0 1493{
d410cf58 1494 static char *codes[5] = {
1495 "invalid",
1496 "change",
1497 "warning",
1498 "limit",
1499 "limit cleared"
1500 };
355229fe 1501 va_list ap;
d410cf58 1502 fu16_t code, rateclass;
1503 fu32_t windowsize, clear, alert, limit, disconnect;
1504 fu32_t currentavg, maxavg;
37ee990e 1505
d410cf58 1506 va_start(ap, fr);
37ee990e 1507
d410cf58 1508 /* See code explanations below */
1509 code = va_arg(ap, fu16_t);
37ee990e 1510
d410cf58 1511 /*
1512 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1513 */
1514 rateclass = va_arg(ap, fu16_t);
37ee990e 1515
d410cf58 1516 /*
1517 * Not sure what this is exactly. I think its the temporal
1518 * relation factor (ie, how to make the rest of the numbers
1519 * make sense in the real world).
1520 */
1521 windowsize = va_arg(ap, fu32_t);
646c6b52 1522
d410cf58 1523 /* Explained below */
1524 clear = va_arg(ap, fu32_t);
1525 alert = va_arg(ap, fu32_t);
1526 limit = va_arg(ap, fu32_t);
1527 disconnect = va_arg(ap, fu32_t);
1528 currentavg = va_arg(ap, fu32_t);
1529 maxavg = va_arg(ap, fu32_t);
646c6b52 1530
d410cf58 1531 va_end(ap);
646c6b52 1532
646c6b52 1533
d410cf58 1534 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",
1535 (code < 5)?codes[code]:"invalid",
1536 rateclass,
1537 currentavg, maxavg,
1538 alert, clear,
1539 limit, disconnect,
1540 windowsize);
1541
1542 if (code == AIM_RATE_CODE_CHANGE) {
1543 /*
1544 * Not real sure when these get sent.
1545 */
1546 if (currentavg >= clear)
1547 aim_conn_setlatency(fr->conn, 0);
1548
1549 } else if (code == AIM_RATE_CODE_WARNING) {
1550 /*
1551 * We start getting WARNINGs the first time we go below the
1552 * 'alert' limit (currentavg < alert) and they stop when
1553 * either we pause long enough for currentavg to go above
1554 * 'clear', or until we flood it bad enough to go below
1555 * 'limit' (and start getting LIMITs instead) or even further
1556 * and go below 'disconnect' and get disconnected completely
1557 * (and won't be able to login right away either).
1558 */
1559 aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */
1560
1561 } else if (code == AIM_RATE_CODE_LIMIT) {
1562 /*
1563 * When we hit LIMIT, messages will start getting dropped.
1564 */
1565 aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */
1566
1567 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1568 /*
1569 * The limit is cleared when curavg goes above 'clear'.
1570 */
1571 aim_conn_setlatency(fr->conn, 0);
1572 }
646c6b52 1573
d410cf58 1574 return 1;
78b3fb13 1575}
98c88242 1576
d410cf58 1577static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
98c88242 1578{
355229fe 1579 va_list ap;
d410cf58 1580 fu16_t newevil;
355229fe 1581 struct aim_userinfo_s *userinfo;
98c88242 1582
d410cf58 1583 va_start(ap, fr);
1584 newevil = va_arg(ap, fu16_t);
355229fe 1585 userinfo = va_arg(ap, struct aim_userinfo_s *);
1586 va_end(ap);
98c88242 1587
355229fe 1588 /*
1589 * Evil Notifications that are lacking userinfo->sn are anon-warns
1590 * if they are an evil increases, but are not warnings at all if its
1591 * a decrease (its the natural backoff happening).
1592 *
1593 * newevil is passed as an int representing the new evil value times
1594 * ten.
1595 */
1596 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
37ee990e 1597
355229fe 1598 return 1;
37ee990e 1599}
1600
d410cf58 1601static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
37ee990e 1602{
355229fe 1603 va_list ap;
1604 char *address, *SNs;
1605 int i, num;
37ee990e 1606
d410cf58 1607 va_start(ap, fr);
355229fe 1608 address = va_arg(ap, char *);
1609 num = va_arg(ap, int);
1610 SNs = va_arg(ap, char *);
1611 va_end(ap);
37ee990e 1612
355229fe 1613 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
37ee990e 1614
355229fe 1615 for(i = 0; i < num; i++)
1616 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1617 dinlineprintf("\n");
1618
1619 return 1;
37ee990e 1620}
1621
d410cf58 1622static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
37ee990e 1623{
355229fe 1624 va_list ap;
1625 char *address;
37ee990e 1626
d410cf58 1627 va_start(ap, fr);
355229fe 1628 address = va_arg(ap, char *);
1629 va_end(ap);
98c88242 1630
355229fe 1631 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1632
1633 return 1;
78b3fb13 1634}
d410cf58 1635
1636void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
1637{
1638
1639 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1640
1641 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1642 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */
1643 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
1644 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1645 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1646 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1647 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1648 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1649 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
1650 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1651 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
1652 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
1653 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
1654 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1655 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1656 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1657 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1658 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1659 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1660 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
1661 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1662 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
1663 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1664 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
1665 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1666
1667 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1668 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1669 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
1670
1671#ifdef MID_REWROTE_ALL_THE_CRAP
1672 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
1673#endif
1674
1675 return;
1676}
1677
This page took 1.592899 seconds and 5 git commands to generate.