]> andersk Git - libfaim.git/blame - utils/faimtest/faimtest.c
- Tue Sep 11 04:42:28 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) {
309 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
310 dprintf("connection error (rend out)\n");
311 aim_conn_kill(&aimsess, &waitingconn);
312 }
313 } else {
314 if (aim_get_command(&aimsess, waitingconn) >= 0) {
315 aim_rxdispatch(&aimsess);
316 } else {
317 dvprintf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype);
318 /* we should have callbacks for all these, else the library will do the conn_kill for us. */
319 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
59e1da90 320 if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
321 dvprintf("disconnected from %s\n", aim_directim_getsn(waitingconn));
355229fe 322 aim_conn_kill(&aimsess, &waitingconn);
323 } else
324 aim_conn_kill(&aimsess, &waitingconn);
325 if (!aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)) {
326 dprintf("major connection error\n");
327 if (faimtest_mode == 2)
328 break;
329 }
330 }
331 }
332 }
333 }
7392c79f 334 }
9de3ca7e 335
355229fe 336 /* close up all connections, dead or no */
337 aim_session_kill(&aimsess);
9de3ca7e 338
355229fe 339 if (faimtest_mode < 2) {
340 printf("\n");
341 cmd_uninit();
342 }
b562f484 343
d410cf58 344 free(priv.buddyicon);
7b91722d 345
355229fe 346 /* Get out */
347 exit(0);
9de3ca7e 348}
349
d410cf58 350int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...)
c78446b5 351{
d410cf58 352 int famcount, i;
353 fu16_t *families;
354 va_list ap;
c78446b5 355
d410cf58 356 va_start(ap, fr);
357 famcount = va_arg(ap, int);
358 families = va_arg(ap, fu16_t *);
359 va_end(ap);
360
361 dvprintf("faimtest: SNAC families supported by this host (type %d): ", fr->conn->type);
362 for (i = 0; i < famcount; i++)
363 dvinlineprintf("0x%04x ", families[i]);
364 dinlineprintf("\n");
c78446b5 365
d410cf58 366 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
c78446b5 367
d410cf58 368 aim_auth_setversions(sess, fr->conn);
369 aim_bos_reqrate(sess, fr->conn); /* request rate info */
c78446b5 370
d410cf58 371 dprintf("done with auth server ready\n");
355229fe 372
d410cf58 373 } else if (fr->conn->type == AIM_CONN_TYPE_BOS) {
355229fe 374
d410cf58 375 aim_setversions(sess, fr->conn);
376 aim_bos_reqrate(sess, fr->conn); /* request rate info */
355229fe 377
d410cf58 378 dprintf("done with BOS server ready\n");
355229fe 379 }
d410cf58 380
381 return 1;
382}
383
384int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
385{
386 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
387 va_list ap;
388 fu16_t code;
389 char *msg;
390
391 va_start(ap, fr);
392 code = va_arg(ap, int);
393 msg = va_arg(ap, char *);
394 va_end(ap);
395
396 dvprintf("connerr: Code 0x%04x: %s\n", code, msg);
397 aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
398
399 priv->connected = 0;
400
401 return 1;
402}
403
d410cf58 404static int faimtest_rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...)
405{
406
407 aim_bos_ackrateresp(sess, fr->conn);
408 aim_auth_clientready(sess, fr->conn);
409
410 dprintf("faimtest: connected to authorization/admin service\n");
411
412 return 1;
413}
414
415int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
416{
417 int status;
418 va_list ap;
419
420 va_start(ap, fr);
421 status = va_arg(ap, int); /* status code of confirmation request */
422 va_end(ap);
423
424 dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
425
426 return 1;
427}
428
d410cf58 429#if 0
430/*
431 * This kind of function is really not legal in the new bstream way...
432 * In fact, clients should never access the aim_frame_t directly in handlers,
433 * since that may leave it in a bizare state for the lower layers. In fact,
434 * clients should probably not even get passed a pointer like this.
435 *
436 */
437int faimtest_parse_unknown(aim_session_t *sess, aim_frame_t *fr, ...)
438{
439 int i;
440
441 aim_bstream_rewind(&fr->data); /* boo! */
442
443 dprintf("\nReceived unknown packet:");
444 for (i = 0; aim_bstream_empty(&fr->data); i++) {
445 if ((i % 8) == 0)
446 dinlineprintf("\n\t");
447 dvinlineprintf("0x%2x ", aimbs_get8(&fr->data));
355229fe 448 }
d410cf58 449 dinlineprintf("\n\n");
355229fe 450
451 return 1;
c78446b5 452}
d410cf58 453#endif
c78446b5 454
8722e782 455static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
456{
457 fu16_t change = 0, perms, type;
458 int length, str;
459 char *val;
460 va_list ap;
461
462 va_start(ap, fr);
463 change = va_arg(ap, int);
464 perms = va_arg(ap, fu16_t);
465 type = va_arg(ap, fu16_t);
466 length = va_arg(ap, int);
467 val = va_arg(ap, char *);
468 str = va_arg(ap, int);
469 va_end(ap);
470
471 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
472
473 return 1;
474}
475
476
d410cf58 477int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
478{
479 va_list ap;
480 int serviceid;
481 char *ip;
482 fu8_t *cookie;
483
484 va_start(ap, fr);
485 serviceid = va_arg(ap, int);
486 ip = va_arg(ap, char *);
487 cookie = va_arg(ap, fu8_t *);
488
489 if (serviceid == 0x0005) { /* Adverts */
490#if 0
491 aim_conn_t *tstconn;
492
493 tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, 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_auth_sendcookie(sess, tstconn, cookie);
503 dprintf("sent cookie to adverts host\n");
504 }
505#endif
506 } else if (serviceid == 0x0007) { /* Authorizer */
d410cf58 507 aim_conn_t *tstconn;
508
509 tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
510 if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
511 dprintf("faimtest: unable to reconnect with authorizer\n");
512 } else {
513 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
514 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
515 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
8722e782 516 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp_auth, 0); /* rate info */
517 //aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
d410cf58 518 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
519 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
520 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
521 /* Send the cookie to the Auth */
522 aim_auth_sendcookie(sess, tstconn, cookie);
523 dprintf("sent cookie to authorizer host\n");
524 }
d410cf58 525 } else if (serviceid == 0x000d) { /* ChatNav */
526
527 chatnav_redirect(sess, ip, cookie);
528
529 } else if (serviceid == 0x000e) { /* Chat */
530 char *roomname = NULL;
531 int exchange;
532
533 roomname = va_arg(ap, char *);
534 exchange = va_arg(ap, int);
535
536 chat_redirect(sess, ip, cookie, roomname, exchange);
537
538 } else {
539 dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
540 }
541
542 va_end(ap);
543
544 return 1;
545}
546
547static int faimtest_rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...)
548{
549 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
550 char buddies[128]; /* this is the new buddy list */
551 char profile[256]; /* this is the new profile */
552 char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
553
554 /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
555 snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah");
556 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);
557
558 aim_bos_ackrateresp(sess, fr->conn); /* ack rate info response */
559 aim_bos_reqpersonalinfo(sess, fr->conn);
560 aim_bos_reqlocaterights(sess, fr->conn);
8722e782 561 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 | AIM_CAPS_SENDBUDDYLIST);
d410cf58 562 aim_bos_reqbuddyrights(sess, fr->conn);
563
564 /* send the buddy list and profile (required, even if empty) */
565 aim_bos_setbuddylist(sess, fr->conn, buddies);
566
567 aim_reqicbmparams(sess, fr->conn);
568
569 aim_bos_reqrights(sess, fr->conn);
570 /* set group permissions -- all user classes */
571 aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
572 aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE);
573
574 return 1;
575}
576
577static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
00ef5271 578{
355229fe 579 struct aim_icbmparameters *params;
580 va_list ap;
00ef5271 581
d410cf58 582 va_start(ap, fr);
355229fe 583 params = va_arg(ap, struct aim_icbmparameters *);
584 va_end(ap);
00ef5271 585
355229fe 586 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 587
36a61e0d 588 /*
589 * Set these to your taste, or client medium. Setting minmsginterval
590 * higher is good for keeping yourself from getting flooded (esp
591 * if you're on a slow connection or something where that would be
592 * useful).
593 */
355229fe 594 params->maxmsglen = 8000;
36a61e0d 595 params->minmsginterval = 0; /* in milliseconds */
355229fe 596
d410cf58 597 aim_seticbmparam(sess, fr->conn, params);
355229fe 598
599 return 1;
00ef5271 600}
601
d410cf58 602static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...)
ee49b735 603{
355229fe 604 int vercount, i;
d410cf58 605 fu8_t *versions;
355229fe 606 va_list ap;
607
d410cf58 608 va_start(ap, fr);
355229fe 609 vercount = va_arg(ap, int); /* number of family/version pairs */
d410cf58 610 versions = va_arg(ap, fu8_t *);
355229fe 611 va_end(ap);
612
613 dprintf("faimtest: SNAC versions supported by this host: ");
614 for (i = 0; i < vercount*4; i += 4) {
615 dvinlineprintf("0x%04x:0x%04x ",
616 aimutil_get16(versions+i), /* SNAC family */
617 aimutil_get16(versions+i+2) /* Version number */);
618 }
619 dinlineprintf("\n");
ee49b735 620
355229fe 621 return 1;
ee49b735 622}
623
d410cf58 624static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
64c78745 625{
355229fe 626 va_list ap;
d410cf58 627 fu16_t maxbuddies, maxwatchers;
64c78745 628
d410cf58 629 va_start(ap, fr);
630 maxbuddies = va_arg(ap, int);
631 maxwatchers = va_arg(ap, int);
355229fe 632 va_end(ap);
64c78745 633
d410cf58 634 dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
64c78745 635
355229fe 636 return 1;
64c78745 637}
638
d410cf58 639static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 640{
d410cf58 641 va_list ap;
642 fu16_t maxpermits, maxdenies;
9de3ca7e 643
d410cf58 644 va_start(ap, fr);
645 maxpermits = va_arg(ap, int);
646 maxdenies = va_arg(ap, int);
647 va_end(ap);
648
649 dvprintf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
96f8b1ed 650
d410cf58 651 aim_bos_clientready(sess, fr->conn);
96f8b1ed 652
d410cf58 653 dprintf("officially connected to BOS.\n");
96f8b1ed 654
d410cf58 655 return 1;
96f8b1ed 656}
657
d410cf58 658static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
c78446b5 659{
d410cf58 660 va_list ap;
661 fu16_t maxsiglen;
96f8b1ed 662
d410cf58 663 va_start(ap, fr);
664 maxsiglen = va_arg(ap, int);
665 va_end(ap);
c78446b5 666
d410cf58 667 dvprintf("locate rights: max signature length = %d\n", maxsiglen);
37ee990e 668
d410cf58 669 return 1;
37ee990e 670}
671
d410cf58 672static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
b39e0a91 673{
d410cf58 674 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
675 va_list ap;
676 fu16_t interval;
b39e0a91 677
d410cf58 678 va_start(ap, fr);
679 interval = va_arg(ap, int);
680 va_end(ap);
b39e0a91 681
d410cf58 682 dvprintf("minimum report interval: %d (seconds?)\n", interval);
b39e0a91 683
d410cf58 684 if (!priv->connected)
685 priv->connected++;
b39e0a91 686
d410cf58 687#if 0
688 aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */
689 aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */
37ee990e 690
d410cf58 691 /* Don't know what this does... */
692 /* XXX sess->sn should be normalized by the 0001/000f handler */
693 aim_0002_000b(sess, fr->conn, sess->sn);
694#endif
37ee990e 695
d410cf58 696 aim_reqicbmparams(sess, fr->conn);
c78446b5 697
d410cf58 698 return 1;
c78446b5 699}
700
d410cf58 701static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 702{
d410cf58 703 static char *codes[] = {
704 "Unknown",
705 "Mandatory upgrade",
706 "Advisory upgrade",
707 "System bulletin",
708 "Top o' the world!"
709 };
710 static int codeslen = 5;
711 char *msg;
712 fu16_t id;
713 va_list ap;
714
715 va_start(ap, fr);
716 id = va_arg(ap, int);
717 msg = va_arg(ap, char *);
718 va_end(ap);
719
720 dvprintf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown");
721
722 return 1;
9de3ca7e 723}
724
83ae98f8 725/*
726 * This is a little more complicated than it looks. The module
727 * name (proto, boscore, etc) may or may not be given. If it is
728 * not given, then use aim.exe. If it is given, put ".ocm" on the
729 * end of it.
730 *
731 * Now, if the offset or length requested would cause a read past
732 * the end of the file, then the request is considered invalid. Invalid
733 * requests are processed specially. The value hashed is the
734 * the request, put into little-endian (eight bytes: offset followed
735 * by length).
736 *
737 * Additionally, if the request is valid, the length is mod 4096. It is
738 * important that the length is checked for validity first before doing
739 * the mod.
740 *
741 * Note to Bosco's Brigade: if you'd like to break this, put the
742 * module name on an invalid request.
743 *
744 */
d410cf58 745static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
b1eac25a 746{
d410cf58 747 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
748 FILE *f;
749 static const char defaultmod[] = "aim.exe";
750 char *filename = NULL;
751 struct stat st;
752 unsigned char *buf;
753 int invalid = 0;
754
755 if (!bufret || !buflenret)
756 return -1;
b1eac25a 757
d410cf58 758 if (modname) {
001c9b80 759
d410cf58 760 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
761 dperror("memrequest: malloc");
762 return -1;
763 }
5ac961d5 764
d410cf58 765 sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
5ac961d5 766
d410cf58 767 } else {
328837f7 768
d410cf58 769 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
770 dperror("memrequest: malloc");
771 return -1;
772 }
328837f7 773
d410cf58 774 sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
b1eac25a 775
d410cf58 776 }
83ae98f8 777
d410cf58 778 if (stat(filename, &st) == -1) {
779 if (!modname) {
780 dperror("memrequest: stat");
781 free(filename);
782 return -1;
783 }
784 invalid = 1;
785 }
83ae98f8 786
d410cf58 787 if (!invalid) {
788 if ((offset > st.st_size) || (len > st.st_size))
789 invalid = 1;
790 else if ((st.st_size - offset) < len)
791 len = st.st_size - offset;
792 else if ((st.st_size - len) < len)
793 len = st.st_size - len;
794 }
83ae98f8 795
d410cf58 796 if (!invalid && len)
797 len %= 4096;
83ae98f8 798
d410cf58 799 if (invalid) {
800 int i;
f6a4f6b7 801
d410cf58 802 free(filename); /* not needed */
f6a4f6b7 803
d410cf58 804 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
83ae98f8 805
d410cf58 806 i = 8;
807 if (modname)
808 i += strlen(modname);
f6a4f6b7 809
d410cf58 810 if (!(buf = malloc(i)))
811 return -1;
83ae98f8 812
d410cf58 813 i = 0;
83ae98f8 814
d410cf58 815 if (modname) {
816 memcpy(buf, modname, strlen(modname));
817 i += strlen(modname);
818 }
83ae98f8 819
d410cf58 820 /* Damn endianness. This must be little (LSB first) endian. */
821 buf[i++] = offset & 0xff;
822 buf[i++] = (offset >> 8) & 0xff;
823 buf[i++] = (offset >> 16) & 0xff;
824 buf[i++] = (offset >> 24) & 0xff;
825 buf[i++] = len & 0xff;
826 buf[i++] = (len >> 8) & 0xff;
827 buf[i++] = (len >> 16) & 0xff;
828 buf[i++] = (len >> 24) & 0xff;
83ae98f8 829
d410cf58 830 *bufret = buf;
831 *buflenret = i;
83ae98f8 832
d410cf58 833 } else {
83ae98f8 834
d410cf58 835 if (!(buf = malloc(len))) {
836 free(filename);
837 return -1;
838 }
83ae98f8 839
d410cf58 840 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
5ac961d5 841
d410cf58 842 if (!(f = fopen(filename, "r"))) {
843 dperror("memrequest: fopen");
844 free(filename);
845 free(buf);
846 return -1;
847 }
b1eac25a 848
d410cf58 849 free(filename);
b1eac25a 850
d410cf58 851 if (fseek(f, offset, SEEK_SET) == -1) {
852 dperror("memrequest: fseek");
853 fclose(f);
854 free(buf);
855 return -1;
856 }
83ae98f8 857
d410cf58 858 if (fread(buf, len, 1, f) != 1) {
859 dperror("memrequest: fread");
860 fclose(f);
861 free(buf);
862 return -1;
863 }
b1eac25a 864
d410cf58 865 fclose(f);
866
867 *bufret = buf;
868 *buflenret = len;
869
870 }
871
872 return 0; /* success! */
b1eac25a 873}
874
875/*
876 * This will get an offset and a length. The client should read this
877 * data out of whatever AIM.EXE binary the user has provided (hopefully
878 * it matches the client information thats sent at login) and pass a
879 * buffer back to libfaim so it can hash the data and send it to AOL for
880 * inspection by the client police.
881 */
d410cf58 882static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
b1eac25a 883{
d410cf58 884 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
885 va_list ap;
886 fu32_t offset, len;
887 char *modname;
888 unsigned char *buf;
889 int buflen;
890
891 va_start(ap, fr);
892 offset = va_arg(ap, fu32_t);
893 len = va_arg(ap, fu32_t);
894 modname = va_arg(ap, char *);
895 va_end(ap);
b1eac25a 896
d410cf58 897 if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
b1eac25a 898
d410cf58 899 aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 900
d410cf58 901 free(buf);
b1eac25a 902
d410cf58 903 } else {
b1eac25a 904
d410cf58 905 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
b1eac25a 906
d410cf58 907 aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 908
d410cf58 909 }
b1eac25a 910
d410cf58 911 return 1;
b1eac25a 912}
913
d410cf58 914static void printuserflags(fu16_t flags)
9de3ca7e 915{
d410cf58 916 if (flags & AIM_FLAG_UNCONFIRMED)
917 dinlineprintf("UNCONFIRMED ");
918 if (flags & AIM_FLAG_ADMINISTRATOR)
919 dinlineprintf("ADMINISTRATOR ");
920 if (flags & AIM_FLAG_AOL)
921 dinlineprintf("AOL ");
922 if (flags & AIM_FLAG_OSCAR_PAY)
923 dinlineprintf("OSCAR_PAY ");
924 if (flags & AIM_FLAG_FREE)
925 dinlineprintf("FREE ");
926 if (flags & AIM_FLAG_AWAY)
927 dinlineprintf("AWAY ");
928 if (flags & AIM_FLAG_UNKNOWN40)
929 dinlineprintf("ICQ? ");
930 if (flags & AIM_FLAG_UNKNOWN80)
931 dinlineprintf("UNKNOWN80 ");
932 return;
9de3ca7e 933}
934
d410cf58 935static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
a15d82b1 936{
d410cf58 937 struct aim_userinfo_s *userinfo;
938 char *prof_encoding = NULL;
939 char *prof = NULL;
940 fu16_t inforeq = 0;
a15d82b1 941
d410cf58 942 va_list ap;
943 va_start(ap, fr);
944 userinfo = va_arg(ap, struct aim_userinfo_s *);
945 prof_encoding = va_arg(ap, char *);
946 prof = va_arg(ap, char *);
947 inforeq = va_arg(ap, fu16_t);
948 va_end(ap);
949
950 dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn);
951 dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
952 dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
953 printuserflags(userinfo->flags);
954 dinlineprintf("\n");
955
956 dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
957 dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
958 dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
959
960 if (inforeq == AIM_GETINFO_GENERALINFO) {
961 dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
962 dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
963 } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
964 dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
965 dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
966 } else
967 dprintf("faimtest: userinfo: unknown info request\n");
968
969 return 1;
9de3ca7e 970}
971
d410cf58 972static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr)
d2587300 973{
d410cf58 974 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
d2587300 975
d410cf58 976 if (!strncmp(tmpstr, "disconnect", 10)) {
d2587300 977
d410cf58 978 logout(sess);
d2587300 979
d410cf58 980 } else if (strstr(tmpstr, "goodday")) {
7b91722d 981
d410cf58 982 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
7b91722d 983
d410cf58 984 } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
985 struct aim_sendimext_args args;
986 static const char iconmsg[] = {"I have an icon"};
7b91722d 987
d410cf58 988 args.destsn = userinfo->sn;
989 args.flags = AIM_IMFLAGS_HASICON;
990 args.msg = iconmsg;
991 args.msglen = strlen(iconmsg);
992 args.iconlen = priv->buddyiconlen;
993 args.iconstamp = priv->buddyiconstamp;
994 args.iconsum = priv->buddyiconsum;
7b91722d 995
d410cf58 996 aim_send_im_ext(sess, conn, &args);
7b91722d 997
603fdcaa 998 } else if (strstr(tmpstr, "sendbin")) {
999 struct aim_sendimext_args args;
1000 static const unsigned char data[] = {
1001 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1002 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1003 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1004 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1005 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1006 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1007 };
1008
1009 /*
1010 * I put this here as a demonstration of how to send
1011 * arbitrary binary data via OSCAR ICBM's without the need
1012 * for escape or baseN encoding of any sort.
1013 *
1014 * Apparently if you set the charset to something WinAIM
1015 * doesn't recognize, it will completly ignore the message.
1016 * That is, it will not display anything in the conversation
1017 * window for the user that recieved it.
1018 *
1019 * HOWEVER, if they do not have a conversation window open
1020 * for you, a new one will be created, but it will not have
1021 * any messages in it. Therefore sending these things could
1022 * be a great way to seemingly subliminally convince people
1023 * to talk to you...
1024 *
1025 */
1026 args.destsn = userinfo->sn;
1027 args.flags = AIM_IMFLAGS_CUSTOMCHARSET;
1028 args.charset = args.charsubset = 0x4242;
1029 args.msg = data;
1030 args.msglen = sizeof(data);
1031
1032 aim_send_im_ext(sess, conn, &args);
1033
1034 } else if (strstr(tmpstr, "sendmulti")) {
1035 struct aim_sendimext_args args;
1036 aim_mpmsg_t mpm;
1037 static const fu16_t unidata[] = { /* "UNICODE." */
1038 0x0055, 0x004e, 0x0049, 0x0043,
1039 0x004f, 0x0044, 0x0045, 0x002e,
1040 };
1041 static const int unidatalen = 8;
1042
1043 /*
1044 * This is how multipart messages should be sent.
1045 *
1046 * This should render as:
1047 * "Part 1, ASCII. UNICODE.Part 3, ASCII. "
1048 */
1049
1050 aim_mpmsg_init(sess, &mpm);
1051
1052 aim_mpmsg_addascii(sess, &mpm, "Part 1, ASCII. ");
1053 aim_mpmsg_addunicode(sess, &mpm, unidata, unidatalen);
1054 aim_mpmsg_addascii(sess, &mpm, "Part 3, ASCII. ");
1055
1056 args.destsn = userinfo->sn;
1057 args.flags = AIM_IMFLAGS_MULTIPART;
1058 args.mpmsg = &mpm;
1059
1060 aim_send_im_ext(sess, conn, &args);
1061
1062 aim_mpmsg_free(sess, &mpm);
1063
1064 } else if (strstr(tmpstr, "sendprebin")) {
1065 static const unsigned char data[] = {
1066 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1067 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1068 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1069 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1070 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1071 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1072 };
1073 struct aim_sendimext_args args;
1074 aim_mpmsg_t mpm;
1075
1076 /*
1077 * This demonstrates sending a human-readable preamble,
1078 * and then arbitrary binary data.
1079 *
1080 * This means that you can very inconspicuously send binary
1081 * attachments to other users. In WinAIM, this appears as
1082 * though it only had the ASCII portion.
1083 *
1084 */
1085
1086 aim_mpmsg_init(sess, &mpm);
1087
1088 aim_mpmsg_addascii(sess, &mpm, "This message has binary data.");
1089 aim_mpmsg_addraw(sess, &mpm, 0x4242, 0x4242, data, sizeof(data));
1090
1091 args.destsn = userinfo->sn;
1092 args.flags = AIM_IMFLAGS_MULTIPART;
1093 args.mpmsg = &mpm;
1094
1095 aim_send_im_ext(sess, conn, &args);
1096
1097 aim_mpmsg_free(sess, &mpm);
1098
84e0ca17 1099 } else if (strstr(tmpstr, "havefeat")) {
1100 struct aim_sendimext_args args;
1101 static const char featmsg[] = {"I have nifty features."};
1102 fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
1103
1104 args.destsn = userinfo->sn;
1105 args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
1106 args.msg = featmsg;
1107 args.msglen = strlen(featmsg);
1108 args.features = features;
1109 args.featureslen = sizeof(features);
1110
1111 aim_send_im_ext(sess, conn, &args);
1112
d410cf58 1113 } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
d2587300 1114
d410cf58 1115 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
d2587300 1116
d410cf58 1117 } else if (strstr(tmpstr, "warnme")) {
d2587300 1118
d410cf58 1119 dprintf("faimtest: icbm: sending non-anon warning\n");
1120 aim_send_warning(sess, conn, userinfo->sn, 0);
d2587300 1121
d410cf58 1122 } else if (strstr(tmpstr, "anonwarn")) {
d2587300 1123
d410cf58 1124 dprintf("faimtest: icbm: sending anon warning\n");
1125 aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
d2587300 1126
d410cf58 1127 } else if (strstr(tmpstr, "setdirectoryinfo")) {
d2587300 1128
d410cf58 1129 dprintf("faimtest: icbm: sending backwards profile data\n");
1130 aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
d2587300 1131
d410cf58 1132 } else if (strstr(tmpstr, "setinterests")) {
d2587300 1133
d410cf58 1134 dprintf("faimtest: icbm: setting fun interests\n");
1135 aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
d2587300 1136
d410cf58 1137 } else if (!strncmp(tmpstr, "getfile", 7)) {
d2587300 1138
d410cf58 1139 if (!priv->ohcaptainmycaptain) {
d2587300 1140
d410cf58 1141 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
d2587300 1142
d410cf58 1143 } else
1144 getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1145
1146 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
d2587300 1147
d410cf58 1148 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
d2587300 1149
d410cf58 1150 } else if (!strncmp(tmpstr, "create", 6)) {
d2587300 1151
d410cf58 1152 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
d2587300 1153
d410cf58 1154 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1155 aim_conn_t *chatnavconn;
d2587300 1156
d410cf58 1157 if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1158 aim_conn_kill(sess, &chatnavconn);
d2587300 1159
d410cf58 1160 } else if (!strncmp(tmpstr, "join", 4)) {
d2587300 1161
d410cf58 1162 aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
d2587300 1163
d410cf58 1164 } else if (!strncmp(tmpstr, "leave", 5)) {
d2587300 1165
d410cf58 1166 aim_chat_leaveroom(sess, "worlddomination");
d2587300 1167
d410cf58 1168 } else if (!strncmp(tmpstr, "getinfo", 7)) {
d2587300 1169
d410cf58 1170 aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO);
1171 aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1172 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1173 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
d2587300 1174
c5f5b7f1 1175 } else if (strstr(tmpstr, "open directim")) {
d2587300 1176
c5f5b7f1 1177 directim_start(sess, conn, userinfo->sn);
d2587300 1178
3e9e6e14 1179 } else if(strstr(tmpstr, "lookup")) {
d2587300 1180
3e9e6e14 1181 aim_usersearch_address(sess, conn, "mid@auk.cx");
d2587300 1182
d410cf58 1183 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
d2587300 1184
d410cf58 1185 aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
d2587300 1186
d410cf58 1187 } else if (!strncmp(tmpstr, "reqauth", 7)) {
d2587300 1188
d410cf58 1189 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
d2587300 1190
d410cf58 1191 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
d2587300 1192
d410cf58 1193 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
d2587300 1194
d410cf58 1195 } else if (!strncmp(tmpstr, "reqemail", 8)) {
d2587300 1196
d410cf58 1197 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
d2587300 1198
d410cf58 1199 } else if (!strncmp(tmpstr, "changepass", 8)) {
d2587300 1200
d410cf58 1201 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
d2587300 1202
d410cf58 1203 } else if (!strncmp(tmpstr, "setemail", 8)) {
d2587300 1204
d410cf58 1205 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
d2587300 1206
d410cf58 1207 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1208 int i;
d2587300 1209
d410cf58 1210 i = atoi(tmpstr+8);
1211 if (i < 10000) {
1212 char *newbuf;
1213 int z;
d2587300 1214
d410cf58 1215 newbuf = malloc(i+1);
1216 for (z = 0; z < i; z++)
1217 newbuf[z] = (z % 10)+0x30;
1218 newbuf[i] = '\0';
1219 aim_send_im(sess, conn, userinfo->sn, 0, newbuf);
1220 free(newbuf);
1221 }
d2587300 1222
d410cf58 1223 } else {
d2587300 1224
d410cf58 1225 dprintf("unknown command.\n");
1226 aim_add_buddy(sess, conn, userinfo->sn);
d2587300 1227
d410cf58 1228 }
d2587300 1229
d410cf58 1230 return 0;
d2587300 1231}
1232
9de3ca7e 1233/*
d410cf58 1234 * Channel 1: Standard Message
9de3ca7e 1235 */
d410cf58 1236static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
9de3ca7e 1237{
e1b8c575 1238 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
d410cf58 1239 char *tmpstr;
1240 struct aim_incomingim_ch1_args *args;
1241 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1242 char realmsg[8192+1] = {""};
7a449b5d 1243
d410cf58 1244 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1245 va_end(ap);
7a449b5d 1246
84e0ca17 1247 clienttype = aim_fingerprintclient(args->features, args->featureslen);
9de3ca7e 1248
d410cf58 1249 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1250 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1251 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1252 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1253 printuserflags(userinfo->flags);
1254 dinlineprintf("\n");
7392c79f 1255
d410cf58 1256 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1257 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1258 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1259 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1260
1261 dprintf("faimtest: icbm: icbmflags = ");
1262 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1263 dinlineprintf("away ");
1264 if (args->icbmflags & AIM_IMFLAGS_ACK)
1265 dinlineprintf("ackrequest ");
1266 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1267 dinlineprintf("buddyreq ");
1268 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1269 dinlineprintf("hasicon ");
1270 dinlineprintf("\n");
7392c79f 1271
603fdcaa 1272 if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET)
1273 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset);
646c6b52 1274
d410cf58 1275 /*
1276 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1277 * characters with their equivelent HTML entity.
1278 */
1279 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1280 int i;
7392c79f 1281
d410cf58 1282 for (i = 0; i < args->msglen; i += 2) {
1283 fu16_t uni;
7392c79f 1284
d410cf58 1285 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
7392c79f 1286
d410cf58 1287 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
7392c79f 1288
d410cf58 1289 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
7392c79f 1290
d410cf58 1291 } else { /* something else, do UNICODE entity */
7392c79f 1292
d410cf58 1293 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
7392c79f 1294
d410cf58 1295 }
871e2fd0 1296
d410cf58 1297 }
871e2fd0 1298
d410cf58 1299 } else {
1300
1301 /*
1302 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1303 * no need to do anything special here. Most
1304 * terminals/whatever will be able to display such characters
1305 * unmodified.
1306 *
1307 * Beware that PC-ASCII 128 through 159 are _not_ actually
1308 * defined in ASCII or ISO 8859-1, and you should send them as
1309 * UNICODE. WinAIM will send these characters in a UNICODE
1310 * message, so you need to do so as well.
1311 *
1312 * You may not think it necessary to handle UNICODE messages.
1313 * You're probably wrong. For one thing, Microsoft "Smart
1314 * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1315 * but real UNICODE). If you don't parse UNICODE at all, your
1316 * users will get a blank message instead of the message
1317 * containing Smart Quotes.
1318 *
1319 */
1320 strncpy(realmsg, args->msg, sizeof(realmsg));
1321 }
3b101546 1322
d410cf58 1323 dvprintf("faimtest: icbm: message: %s\n", realmsg);
7392c79f 1324
603fdcaa 1325 if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1326 aim_mpmsg_section_t *sec;
1327 int z;
1328
1329 dvprintf("faimtest: icbm: multipart: this message has %d parts\n", args->mpmsg.numparts);
1330
1331 for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1332 if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1333 dvprintf("faimtest: icbm: multipart: part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data);
1334 } else {
1335 dvprintf("faimtest: icbm: multipart: part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset);
1336 }
1337 }
1338 }
1339
d410cf58 1340 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1341 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
7392c79f 1342
d410cf58 1343 if (realmsg) {
1344 int i = 0;
9de3ca7e 1345
d410cf58 1346 while (realmsg[i] == '<') {
1347 if (realmsg[i] == '<') {
1348 while (realmsg[i] != '>')
1349 i++;
1350 i++;
1351 }
1352 }
1353 tmpstr = realmsg+i;
9de3ca7e 1354
d410cf58 1355 faimtest_handlecmd(sess, conn, userinfo, tmpstr);
64c78745 1356
d410cf58 1357 }
9de3ca7e 1358
e1b8c575 1359 if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ))
1360 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1361
d410cf58 1362 return 1;
9de3ca7e 1363}
1364
d410cf58 1365/*
1366 * Channel 2: Rendevous Request
1367 */
1368static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
9de3ca7e 1369{
d410cf58 1370 struct aim_incomingim_ch2_args *args;
9de3ca7e 1371
d410cf58 1372 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1373 va_end(ap);
9de3ca7e 1374
d410cf58 1375 if (args->reqclass == AIM_CAPS_VOICE) {
96f8b1ed 1376
d410cf58 1377 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1378 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1379 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1380 printuserflags(userinfo->flags);
1381 dinlineprintf("\n");
ee49b735 1382
d410cf58 1383 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1384 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
e80a0fa9 1385
d410cf58 1386 } else if (args->reqclass == AIM_CAPS_GETFILE) {
1387
1388 getfile_requested(sess, conn, userinfo, args);
1389
1390 } else if (args->reqclass == AIM_CAPS_SENDFILE) {
96f8b1ed 1391
d410cf58 1392 dprintf("faimtest: send file!\n");
1449ad2b 1393
d410cf58 1394 } else if (args->reqclass == AIM_CAPS_CHAT) {
1449ad2b 1395
d410cf58 1396 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1397 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1398 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1399 printuserflags(userinfo->flags);
1400 dinlineprintf("\n");
355229fe 1401
d410cf58 1402 /* we dont get membersince on chat invites! */
1403 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1404 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1449ad2b 1405
d410cf58 1406 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1407 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1408 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1409 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1410 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1411 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1412 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
96f8b1ed 1413
d410cf58 1414 /* Automatically join room... */
1415 aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
96f8b1ed 1416
d410cf58 1417 } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
355229fe 1418
d410cf58 1419 dprintf("faimtest: icbm: rendezvous imimage\n");
96f8b1ed 1420
d410cf58 1421 directim_requested(sess, conn, userinfo, args);
96f8b1ed 1422
d410cf58 1423 } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
01b59e1e 1424
e1b8c575 1425 dvprintf("faimtest: Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length);
d410cf58 1426
1427 } else {
1428
1429 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1430 }
355229fe 1431
1432 return 1;
01b59e1e 1433}
9de3ca7e 1434
d410cf58 1435static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
9de3ca7e 1436{
d410cf58 1437 fu16_t channel;
355229fe 1438 struct aim_userinfo_s *userinfo;
d410cf58 1439 va_list ap;
1440 int ret = 0;
9de3ca7e 1441
d410cf58 1442 va_start(ap, fr);
1443 channel = va_arg(ap, fu16_t);
355229fe 1444 userinfo = va_arg(ap, struct aim_userinfo_s *);
355229fe 1445
d410cf58 1446 if (channel == 1)
1447 ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, ap);
1448 else if (channel == 2)
1449 ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap);
1450 else
1451 dvprintf("unsupported channel 0x%04x\n", channel);
1452
1453 dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret);
355229fe 1454
1455 return 1;
9de3ca7e 1456}
1457
d410cf58 1458static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1459{
355229fe 1460 struct aim_userinfo_s *userinfo;
0c20631f 1461
d410cf58 1462 va_list ap;
1463 va_start(ap, fr);
355229fe 1464 userinfo = va_arg(ap, struct aim_userinfo_s *);
1465 va_end(ap);
0c20631f 1466
d410cf58 1467 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1468 time(NULL),
1469 userinfo->sn, userinfo->flags,
1470 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1471 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1472 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1473 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1474 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1475 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1476 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1477 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1478 userinfo->capabilities);
355229fe 1479 return 1;
0c20631f 1480}
1481
d410cf58 1482static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1483{
355229fe 1484 struct aim_userinfo_s *userinfo;
d410cf58 1485 va_list ap;
1486
1487 va_start(ap, fr);
355229fe 1488 userinfo = va_arg(ap, struct aim_userinfo_s *);
1489 va_end(ap);
37ee990e 1490
d410cf58 1491 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1492 time(NULL),
1493 userinfo->sn, userinfo->flags,
1494 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1495 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1496 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1497 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1498 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1499 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1500 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1501 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1502 userinfo->capabilities);
355229fe 1503
1504 return 1;
0c20631f 1505}
1506
d410cf58 1507static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1508{
355229fe 1509 va_list ap;
d410cf58 1510 fu16_t reason;
355229fe 1511
d410cf58 1512 va_start(ap, fr);
1513 reason = va_arg(ap, fu16_t);
1514 va_end(ap);
355229fe 1515
d410cf58 1516 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
355229fe 1517
1518 return 1;
0c20631f 1519}
1520
d410cf58 1521static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
0c20631f 1522{
355229fe 1523 va_list ap;
d410cf58 1524 char *destsn;
1525 fu16_t reason;
355229fe 1526
d410cf58 1527 va_start(ap, fr);
1528 reason = va_arg(ap, fu16_t);
1529 destsn = va_arg(ap, char *);
355229fe 1530 va_end(ap);
1531
d410cf58 1532 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
0c20631f 1533
355229fe 1534 return 1;
0c20631f 1535}
1536
d410cf58 1537static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
5e02cf44 1538{
355229fe 1539 va_list ap;
d410cf58 1540 char *destsn;
1541 fu16_t reason;
5e02cf44 1542
d410cf58 1543 va_start(ap, fr);
1544 reason = va_arg(ap, fu16_t);
1545 destsn = va_arg(ap, char *);
355229fe 1546 va_end(ap);
5e02cf44 1547
d410cf58 1548 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
d32954e7 1549
355229fe 1550 return 1;
5e02cf44 1551}
e5012450 1552
d410cf58 1553static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1554{
1555 static char *missedreasons[] = {
1556 "Invalid (0)",
1557 "Message too large",
1558 "Rate exceeded",
1559 "Evil Sender",
1560 "Evil Receiver"
1561 };
1562 static int missedreasonslen = 5;
e5012450 1563
d410cf58 1564 va_list ap;
1565 fu16_t chan, nummissed, reason;
1566 struct aim_userinfo_s *userinfo;
e5012450 1567
d410cf58 1568 va_start(ap, fr);
1569 chan = va_arg(ap, fu16_t);
1570 userinfo = va_arg(ap, struct aim_userinfo_s *);
1571 nummissed = va_arg(ap, fu16_t);
1572 reason = va_arg(ap, fu16_t);
1573 va_end(ap);
e5012450 1574
d410cf58 1575 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 1576
355229fe 1577 return 1;
e5012450 1578}
1a8c261b 1579
1580/*
646c6b52 1581 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1a8c261b 1582 */
d410cf58 1583static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1a8c261b 1584{
355229fe 1585 va_list ap;
d410cf58 1586 fu16_t type;
355229fe 1587 char *sn = NULL;
1a8c261b 1588
d410cf58 1589 va_start(ap, fr);
1590 type = va_arg(ap, fu16_t);
355229fe 1591 sn = va_arg(ap, char *);
1592 va_end(ap);
1a8c261b 1593
355229fe 1594 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1a8c261b 1595
355229fe 1596 return 1;
1a8c261b 1597}
1598
d410cf58 1599static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
871e2fd0 1600{
d410cf58 1601 static char *codes[5] = {
1602 "invalid",
1603 "change",
1604 "warning",
1605 "limit",
1606 "limit cleared"
1607 };
355229fe 1608 va_list ap;
d410cf58 1609 fu16_t code, rateclass;
1610 fu32_t windowsize, clear, alert, limit, disconnect;
1611 fu32_t currentavg, maxavg;
37ee990e 1612
d410cf58 1613 va_start(ap, fr);
37ee990e 1614
d410cf58 1615 /* See code explanations below */
1616 code = va_arg(ap, fu16_t);
37ee990e 1617
d410cf58 1618 /*
1619 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1620 */
1621 rateclass = va_arg(ap, fu16_t);
37ee990e 1622
d410cf58 1623 /*
1624 * Not sure what this is exactly. I think its the temporal
1625 * relation factor (ie, how to make the rest of the numbers
1626 * make sense in the real world).
1627 */
1628 windowsize = va_arg(ap, fu32_t);
646c6b52 1629
d410cf58 1630 /* Explained below */
1631 clear = va_arg(ap, fu32_t);
1632 alert = va_arg(ap, fu32_t);
1633 limit = va_arg(ap, fu32_t);
1634 disconnect = va_arg(ap, fu32_t);
1635 currentavg = va_arg(ap, fu32_t);
1636 maxavg = va_arg(ap, fu32_t);
646c6b52 1637
d410cf58 1638 va_end(ap);
646c6b52 1639
646c6b52 1640
d410cf58 1641 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",
1642 (code < 5)?codes[code]:"invalid",
1643 rateclass,
1644 currentavg, maxavg,
1645 alert, clear,
1646 limit, disconnect,
1647 windowsize);
1648
1649 if (code == AIM_RATE_CODE_CHANGE) {
1650 /*
1651 * Not real sure when these get sent.
1652 */
1653 if (currentavg >= clear)
1654 aim_conn_setlatency(fr->conn, 0);
1655
1656 } else if (code == AIM_RATE_CODE_WARNING) {
1657 /*
1658 * We start getting WARNINGs the first time we go below the
1659 * 'alert' limit (currentavg < alert) and they stop when
1660 * either we pause long enough for currentavg to go above
1661 * 'clear', or until we flood it bad enough to go below
1662 * 'limit' (and start getting LIMITs instead) or even further
1663 * and go below 'disconnect' and get disconnected completely
1664 * (and won't be able to login right away either).
1665 */
1666 aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */
1667
1668 } else if (code == AIM_RATE_CODE_LIMIT) {
1669 /*
1670 * When we hit LIMIT, messages will start getting dropped.
1671 */
1672 aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */
1673
1674 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1675 /*
1676 * The limit is cleared when curavg goes above 'clear'.
1677 */
1678 aim_conn_setlatency(fr->conn, 0);
1679 }
646c6b52 1680
d410cf58 1681 return 1;
78b3fb13 1682}
98c88242 1683
d410cf58 1684static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
98c88242 1685{
355229fe 1686 va_list ap;
d410cf58 1687 fu16_t newevil;
355229fe 1688 struct aim_userinfo_s *userinfo;
98c88242 1689
d410cf58 1690 va_start(ap, fr);
1691 newevil = va_arg(ap, fu16_t);
355229fe 1692 userinfo = va_arg(ap, struct aim_userinfo_s *);
1693 va_end(ap);
98c88242 1694
355229fe 1695 /*
1696 * Evil Notifications that are lacking userinfo->sn are anon-warns
1697 * if they are an evil increases, but are not warnings at all if its
1698 * a decrease (its the natural backoff happening).
1699 *
1700 * newevil is passed as an int representing the new evil value times
1701 * ten.
1702 */
1703 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
37ee990e 1704
355229fe 1705 return 1;
37ee990e 1706}
1707
d410cf58 1708static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
37ee990e 1709{
355229fe 1710 va_list ap;
1711 char *address, *SNs;
1712 int i, num;
37ee990e 1713
d410cf58 1714 va_start(ap, fr);
355229fe 1715 address = va_arg(ap, char *);
1716 num = va_arg(ap, int);
1717 SNs = va_arg(ap, char *);
1718 va_end(ap);
37ee990e 1719
355229fe 1720 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
37ee990e 1721
355229fe 1722 for(i = 0; i < num; i++)
1723 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1724 dinlineprintf("\n");
1725
1726 return 1;
37ee990e 1727}
1728
d410cf58 1729static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
37ee990e 1730{
355229fe 1731 va_list ap;
1732 char *address;
37ee990e 1733
d410cf58 1734 va_start(ap, fr);
355229fe 1735 address = va_arg(ap, char *);
1736 va_end(ap);
98c88242 1737
355229fe 1738 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1739
1740 return 1;
78b3fb13 1741}
d410cf58 1742
031c2fb3 1743static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1744{
1745
1746 aim_sendpauseack(sess, fr->conn);
1747
1748 return 1;
1749}
1750
1751static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1752{
1753 va_list ap;
1754 aim_conn_t *bosconn;
1755 char *bosip;
1756 fu8_t *cookie;
1757
1758 va_start(ap, fr);
1759 bosip = va_arg(ap, char *);
1760 cookie = va_arg(ap, fu8_t *);
1761 va_end(ap);
1762
1763 dvprintf("migration in progress -- new BOS is %s -- disconnecting\n", bosip);
1764 aim_conn_kill(sess, &fr->conn);
1765
1766 if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1767 dprintf("migrate: could not connect to BOS: internal error\n");
1768 return 1;
1769 } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
1770 dprintf("migrate: could not connect to BOS\n");
1771 aim_conn_kill(sess, &bosconn);
1772 return 1;
1773 }
1774
1775 /* Login will happen all over again. */
1776 addcb_bos(sess, bosconn);
1777
1778 aim_auth_sendcookie(sess, bosconn, cookie);
1779
1780 return 1;
1781}
1782
d410cf58 1783void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
1784{
1785
1786 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1787
1788 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1789 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */
1790 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
1791 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1792 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1793 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1794 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1795 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1796 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
1797 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1798 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
1799 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
1800 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
1801 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1802 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1803 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1804 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1805 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1806 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1807 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
1808 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1809 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
1810 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1811 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
1812 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1813
1814 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1815 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1816 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
031c2fb3 1817 aim_conn_addhandler(sess, bosconn, 0x0001, 0x000b, serverpause, 0);
1818 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0012, migrate, 0);
d410cf58 1819
1820#ifdef MID_REWROTE_ALL_THE_CRAP
1821 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
1822#endif
1823
1824 return;
1825}
1826
This page took 0.734503 seconds and 5 git commands to generate.