]> andersk Git - libfaim.git/blame_incremental - utils/faimtest/faimtest.c
- Mon Sep 3 18:48:26 PDT 2001
[libfaim.git] / utils / faimtest / faimtest.c
... / ...
CommitLineData
1/*
2 * faimtest.
3 *
4 * The point of faimtest is twofold:
5 * - Test the functionality of libfaim.
6 * - Demonstrate the functionality of libfaim and how to use it.
7 *
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?)
15 *
16 * The faimtest code is very ugly. Probably always will be.
17 *
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.
21 *
22 */
23
24#include "faimtest.h"
25#include <sys/stat.h>
26
27char *dprintf_ctime(void)
28{
29 static char retbuf[64];
30 struct tm *lt;
31 struct timeval tv;
32 struct timezone tz;
33
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;
39}
40
41static char *msgerrreasons[] = {
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};
68static int msgerrreasonslen = 25;
69
70aim_session_t aimsess;
71int keepgoing = 1;
72
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)
81{
82
83 vfprintf(stderr, format, va);
84
85 return;
86}
87
88int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
89{
90
91 /* XXX fix libfaim to support this */
92 dvprintf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
93
94#if 0
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 */
99 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
100 /* do NOT send a flapversion, request_login will send it if needed */
101 aim_request_login(sess, fr->conn, priv->screenname);
102 dprintf("faimtest: login request sent\n");
103 }
104#endif
105
106 return 1;
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 */
117int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
118{
119 va_list ap;
120 aim_conn_t *conn;
121
122 va_start(ap, fr);
123 conn = va_arg(ap, aim_conn_t *);
124 va_end(ap);
125
126 if (conn)
127 dvprintf("faimtest: connection on %d completed\n", conn->fd);
128
129 return 1;
130}
131
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
137 * on win32, but I'm fairly sure it should work.
138 */
139static int initwsa(void)
140{
141 WORD wVersionRequested;
142 WSADATA wsaData;
143
144 wVersionRequested = MAKEWORD(2,2);
145 return WSAStartup(wVersionRequested, &wsaData);
146}
147#endif /* _WIN32 */
148
149/*
150 * This is unrealistic. Most clients will not be able to do this.
151 */
152int faimtest_init(void)
153{
154 aim_conn_t *stdinconn = NULL;
155
156 if (!(stdinconn = aim_newconn(&aimsess, 0, NULL))) {
157 dprintf("unable to create connection for stdin!\n");
158 return -1;
159 }
160
161 stdinconn->fd = STDIN_FILENO;
162
163 return 0;
164}
165
166int main(int argc, char **argv)
167{
168 aim_conn_t *waitingconn = NULL;
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;
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 };
182
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");
189
190 priv.listingpath = getenv("LISTINGPATH");
191
192 while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:i:")) != EOF) {
193 switch (i) {
194 case 'u': priv.screenname = optarg; break;
195 case 'p': priv.password = optarg; break;
196 case 'a': priv.server = optarg; break;
197 case 'U': priv.proxyusername = optarg; break;
198 case 'P': priv.proxypass = optarg; break;
199 case 'A': priv.proxy = optarg; break;
200 case 'l': priv.listingpath = optarg; break;
201 case 'c': priv.ohcaptainmycaptain = optarg; break;
202 case 'o': faimtest_mode = 1; break; /* half old interface */
203 case 'O': faimtest_mode = 2; break; /* full old interface */
204 case 'b': priv.aimbinarypath = optarg; break;
205 case 'i': buddyiconpath = optarg; break;
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 }
225
226#ifdef _WIN32
227 if (initwsa() != 0) {
228 dprintf("faimtest: could not initialize windows sockets\n");
229 return -1;
230 }
231#endif /* _WIN32 */
232
233 /* Pass zero as flags if you want blocking connects */
234 aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 1);
235 aim_setdebuggingcb(&aimsess, faimtest_debugcb); /* still needed even if debuglevel = 0 ! */
236 aimsess.aux_data = &priv;
237
238 if (priv.listingpath) {
239 char *listingname;
240
241 listingname = (char *)calloc(1, strlen(priv.listingpath)+strlen("/listing.txt"));
242 sprintf(listingname, "%s/listing.txt", priv.listingpath);
243
244 if ((priv.listingfile = fopen(listingname, "r")) == NULL)
245 dvprintf("Couldn't open %s... disabling that shit.\n", listingname);
246
247 free(listingname);
248 }
249
250 if (buddyiconpath) {
251 struct stat st;
252 FILE *f;
253
254 if ((stat(buddyiconpath, &st) != -1) && (st.st_size <= MAXICONLEN) && (f = fopen(buddyiconpath, "r"))) {
255
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);
260
261 priv.buddyiconsum = aim_iconsum(priv.buddyicon, priv.buddyiconlen);
262
263 dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", priv.buddyiconlen, buddyiconpath, priv.buddyiconsum);
264
265 fclose(f);
266
267 } else
268 dvprintf("could not open buddy icon %s\n", buddyiconpath);
269
270 }
271
272 faimtest_init();
273
274 if (faimtest_mode < 2)
275 cmd_init();
276
277 if (faimtest_mode >= 1) {
278 if (login(&aimsess, priv.screenname, priv.password) == -1) {
279 if (faimtest_mode < 2)
280 cmd_uninit();
281 exit(-1);
282 }
283 }
284
285 while (keepgoing) {
286
287 /* XXX uh. */
288 tv.tv_sec = 5;
289 tv.tv_usec = 0;
290
291 waitingconn = aim_select(&aimsess, &tv, &selstat);
292
293 if (priv.connected && ((time(NULL) - lastnop) > 30)) {
294 lastnop = time(NULL);
295 aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS));
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 0
310 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
311 dprintf("connection error (rend out)\n");
312 aim_conn_kill(&aimsess, &waitingconn);
313 }
314#endif
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 }
335 }
336
337 /* close up all connections, dead or no */
338 aim_session_kill(&aimsess);
339
340 if (faimtest_mode < 2) {
341 printf("\n");
342 cmd_uninit();
343 }
344
345 free(priv.buddyicon);
346
347 /* Get out */
348 exit(0);
349}
350
351int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...)
352{
353 int famcount, i;
354 fu16_t *families;
355 va_list ap;
356
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");
366
367 if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
368
369 aim_auth_setversions(sess, fr->conn);
370 aim_bos_reqrate(sess, fr->conn); /* request rate info */
371
372 dprintf("done with auth server ready\n");
373
374 } else if (fr->conn->type == AIM_CONN_TYPE_BOS) {
375
376 aim_setversions(sess, fr->conn);
377 aim_bos_reqrate(sess, fr->conn); /* request rate info */
378
379 dprintf("done with BOS server ready\n");
380 }
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));
453 }
454 dinlineprintf("\n\n");
455
456 return 1;
457}
458#endif
459
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, ...)
563{
564 struct aim_icbmparameters *params;
565 va_list ap;
566
567 va_start(ap, fr);
568 params = va_arg(ap, struct aim_icbmparameters *);
569 va_end(ap);
570
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);
572
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 */
579 params->maxmsglen = 8000;
580 params->minmsginterval = 0; /* in milliseconds */
581
582 aim_seticbmparam(sess, fr->conn, params);
583
584 return 1;
585}
586
587static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...)
588{
589 int vercount, i;
590 fu8_t *versions;
591 va_list ap;
592
593 va_start(ap, fr);
594 vercount = va_arg(ap, int); /* number of family/version pairs */
595 versions = va_arg(ap, fu8_t *);
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");
605
606 return 1;
607}
608
609static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
610{
611 va_list ap;
612 fu16_t maxbuddies, maxwatchers;
613
614 va_start(ap, fr);
615 maxbuddies = va_arg(ap, int);
616 maxwatchers = va_arg(ap, int);
617 va_end(ap);
618
619 dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
620
621 return 1;
622}
623
624static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
625{
626 va_list ap;
627 fu16_t maxpermits, maxdenies;
628
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);
635
636 aim_bos_clientready(sess, fr->conn);
637
638 dprintf("officially connected to BOS.\n");
639
640 return 1;
641}
642
643static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
644{
645 va_list ap;
646 fu16_t maxsiglen;
647
648 va_start(ap, fr);
649 maxsiglen = va_arg(ap, int);
650 va_end(ap);
651
652 dvprintf("locate rights: max signature length = %d\n", maxsiglen);
653
654 return 1;
655}
656
657static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
658{
659 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
660 va_list ap;
661 fu16_t interval;
662
663 va_start(ap, fr);
664 interval = va_arg(ap, int);
665 va_end(ap);
666
667 dvprintf("minimum report interval: %d (seconds?)\n", interval);
668
669 if (!priv->connected)
670 priv->connected++;
671
672#if 0
673 aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */
674 aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */
675
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
680
681 aim_reqicbmparams(sess, fr->conn);
682
683 return 1;
684}
685
686static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
687{
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;
708}
709
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 */
730static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
731{
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;
742
743 if (modname) {
744
745 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
746 dperror("memrequest: malloc");
747 return -1;
748 }
749
750 sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
751
752 } else {
753
754 if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
755 dperror("memrequest: malloc");
756 return -1;
757 }
758
759 sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
760
761 }
762
763 if (stat(filename, &st) == -1) {
764 if (!modname) {
765 dperror("memrequest: stat");
766 free(filename);
767 return -1;
768 }
769 invalid = 1;
770 }
771
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 }
780
781 if (!invalid && len)
782 len %= 4096;
783
784 if (invalid) {
785 int i;
786
787 free(filename); /* not needed */
788
789 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
790
791 i = 8;
792 if (modname)
793 i += strlen(modname);
794
795 if (!(buf = malloc(i)))
796 return -1;
797
798 i = 0;
799
800 if (modname) {
801 memcpy(buf, modname, strlen(modname));
802 i += strlen(modname);
803 }
804
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;
814
815 *bufret = buf;
816 *buflenret = i;
817
818 } else {
819
820 if (!(buf = malloc(len))) {
821 free(filename);
822 return -1;
823 }
824
825 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
826
827 if (!(f = fopen(filename, "r"))) {
828 dperror("memrequest: fopen");
829 free(filename);
830 free(buf);
831 return -1;
832 }
833
834 free(filename);
835
836 if (fseek(f, offset, SEEK_SET) == -1) {
837 dperror("memrequest: fseek");
838 fclose(f);
839 free(buf);
840 return -1;
841 }
842
843 if (fread(buf, len, 1, f) != 1) {
844 dperror("memrequest: fread");
845 fclose(f);
846 free(buf);
847 return -1;
848 }
849
850 fclose(f);
851
852 *bufret = buf;
853 *buflenret = len;
854
855 }
856
857 return 0; /* success! */
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 */
867static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
868{
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);
881
882 if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
883
884 aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
885
886 free(buf);
887
888 } else {
889
890 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
891
892 aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
893
894 }
895
896 return 1;
897}
898
899static void printuserflags(fu16_t flags)
900{
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;
918}
919
920static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
921{
922 struct aim_userinfo_s *userinfo;
923 char *prof_encoding = NULL;
924 char *prof = NULL;
925 fu16_t inforeq = 0;
926
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;
955}
956
957static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr)
958{
959 struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data;
960
961 if (!strncmp(tmpstr, "disconnect", 10)) {
962
963 logout(sess);
964
965 } else if (strstr(tmpstr, "goodday")) {
966
967 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
968
969 } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
970 struct aim_sendimext_args args;
971 static const char iconmsg[] = {"I have an icon"};
972
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;
980
981 aim_send_im_ext(sess, conn, &args);
982
983 } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
984
985 aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
986
987 } else if (strstr(tmpstr, "warnme")) {
988
989 dprintf("faimtest: icbm: sending non-anon warning\n");
990 aim_send_warning(sess, conn, userinfo->sn, 0);
991
992 } else if (strstr(tmpstr, "anonwarn")) {
993
994 dprintf("faimtest: icbm: sending anon warning\n");
995 aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
996
997 } else if (strstr(tmpstr, "setdirectoryinfo")) {
998
999 dprintf("faimtest: icbm: sending backwards profile data\n");
1000 aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1001
1002 } else if (strstr(tmpstr, "setinterests")) {
1003
1004 dprintf("faimtest: icbm: setting fun interests\n");
1005 aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1006
1007 } else if (!strncmp(tmpstr, "getfile", 7)) {
1008
1009 if (!priv->ohcaptainmycaptain) {
1010
1011 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1012
1013 } else
1014 getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1015
1016 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1017
1018 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1019
1020 } else if (!strncmp(tmpstr, "create", 6)) {
1021
1022 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1023
1024 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1025 aim_conn_t *chatnavconn;
1026
1027 if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1028 aim_conn_kill(sess, &chatnavconn);
1029
1030 } else if (!strncmp(tmpstr, "join", 4)) {
1031
1032 aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1033
1034 } else if (!strncmp(tmpstr, "leave", 5)) {
1035
1036 aim_chat_leaveroom(sess, "worlddomination");
1037
1038 } else if (!strncmp(tmpstr, "getinfo", 7)) {
1039
1040 aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO);
1041 aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1042 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1043 aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1044
1045 } else if (!strncmp(tmpstr, "open directim", 13)) {
1046
1047 directim_start(sess, conn, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1048
1049 } else if(!(strncmp(tmpstr, "lookup", 6))) {
1050
1051 aim_usersearch_address(sess, conn, tmpstr+7);
1052
1053 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1054
1055 aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1056
1057 } else if (!strncmp(tmpstr, "reqauth", 7)) {
1058
1059 aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1060
1061 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1062
1063 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1064
1065 } else if (!strncmp(tmpstr, "reqemail", 8)) {
1066
1067 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1068
1069 } else if (!strncmp(tmpstr, "changepass", 8)) {
1070
1071 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1072
1073 } else if (!strncmp(tmpstr, "setemail", 8)) {
1074
1075 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1076
1077 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1078 int i;
1079
1080 i = atoi(tmpstr+8);
1081 if (i < 10000) {
1082 char *newbuf;
1083 int z;
1084
1085 newbuf = malloc(i+1);
1086 for (z = 0; z < i; z++)
1087 newbuf[z] = (z % 10)+0x30;
1088 newbuf[i] = '\0';
1089 aim_send_im(sess, conn, userinfo->sn, 0, newbuf);
1090 free(newbuf);
1091 }
1092
1093 } else {
1094
1095 dprintf("unknown command.\n");
1096 aim_add_buddy(sess, conn, userinfo->sn);
1097
1098 }
1099
1100 return 0;
1101}
1102
1103/*
1104 * Channel 1: Standard Message
1105 */
1106static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1107{
1108 char *tmpstr;
1109 struct aim_incomingim_ch1_args *args;
1110 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1111 char realmsg[8192+1] = {""};
1112
1113 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1114 va_end(ap);
1115
1116 clienttype = aim_fingerprintclient(args->fingerprint, args->finlen);
1117
1118 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1119 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1120 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1121 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1122 printuserflags(userinfo->flags);
1123 dinlineprintf("\n");
1124
1125 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1126 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1127 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1128 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1129
1130 dprintf("faimtest: icbm: icbmflags = ");
1131 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1132 dinlineprintf("away ");
1133 if (args->icbmflags & AIM_IMFLAGS_ACK)
1134 dinlineprintf("ackrequest ");
1135 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1136 dinlineprintf("buddyreq ");
1137 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1138 dinlineprintf("hasicon ");
1139 dinlineprintf("\n");
1140
1141 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
1142
1143 /*
1144 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1145 * characters with their equivelent HTML entity.
1146 */
1147 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1148 int i;
1149
1150 for (i = 0; i < args->msglen; i += 2) {
1151 fu16_t uni;
1152
1153 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1154
1155 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1156
1157 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1158
1159 } else { /* something else, do UNICODE entity */
1160
1161 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1162
1163 }
1164
1165 }
1166
1167 } else {
1168
1169 /*
1170 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1171 * no need to do anything special here. Most
1172 * terminals/whatever will be able to display such characters
1173 * unmodified.
1174 *
1175 * Beware that PC-ASCII 128 through 159 are _not_ actually
1176 * defined in ASCII or ISO 8859-1, and you should send them as
1177 * UNICODE. WinAIM will send these characters in a UNICODE
1178 * message, so you need to do so as well.
1179 *
1180 * You may not think it necessary to handle UNICODE messages.
1181 * You're probably wrong. For one thing, Microsoft "Smart
1182 * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1183 * but real UNICODE). If you don't parse UNICODE at all, your
1184 * users will get a blank message instead of the message
1185 * containing Smart Quotes.
1186 *
1187 */
1188 strncpy(realmsg, args->msg, sizeof(realmsg));
1189 }
1190
1191 dvprintf("faimtest: icbm: message: %s\n", realmsg);
1192
1193 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1194 aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1195
1196 if (realmsg) {
1197 int i = 0;
1198
1199 while (realmsg[i] == '<') {
1200 if (realmsg[i] == '<') {
1201 while (realmsg[i] != '>')
1202 i++;
1203 i++;
1204 }
1205 }
1206 tmpstr = realmsg+i;
1207
1208 faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1209
1210 }
1211
1212 return 1;
1213}
1214
1215/*
1216 * Channel 2: Rendevous Request
1217 */
1218static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap)
1219{
1220 struct aim_incomingim_ch2_args *args;
1221
1222 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1223 va_end(ap);
1224
1225 if (args->reqclass == AIM_CAPS_VOICE) {
1226
1227 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1228 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1229 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1230 printuserflags(userinfo->flags);
1231 dinlineprintf("\n");
1232
1233 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1234 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1235
1236 } else if (args->reqclass == AIM_CAPS_GETFILE) {
1237
1238 getfile_requested(sess, conn, userinfo, args);
1239
1240 } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1241
1242 dprintf("faimtest: send file!\n");
1243
1244 } else if (args->reqclass == AIM_CAPS_CHAT) {
1245
1246 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1247 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1248 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1249 printuserflags(userinfo->flags);
1250 dinlineprintf("\n");
1251
1252 /* we dont get membersince on chat invites! */
1253 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1254 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1255
1256 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1257 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1258 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1259 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1260 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1261 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1262 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
1263
1264 /* Automatically join room... */
1265 aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
1266
1267 } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1268
1269 dprintf("faimtest: icbm: rendezvous imimage\n");
1270
1271 directim_requested(sess, conn, userinfo, args);
1272
1273 } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1274
1275 dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, args->info.icon.length);
1276
1277 } else {
1278
1279 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1280 }
1281
1282 return 1;
1283}
1284
1285static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1286{
1287 fu16_t channel;
1288 struct aim_userinfo_s *userinfo;
1289 va_list ap;
1290 int ret = 0;
1291
1292 va_start(ap, fr);
1293 channel = va_arg(ap, fu16_t);
1294 userinfo = va_arg(ap, struct aim_userinfo_s *);
1295
1296 if (channel == 1)
1297 ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, ap);
1298 else if (channel == 2)
1299 ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap);
1300 else
1301 dvprintf("unsupported channel 0x%04x\n", channel);
1302
1303 dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret);
1304
1305 return 1;
1306}
1307
1308#ifdef MID_REWROTE_ALL_THE_CRAP
1309static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
1310{
1311 fu16_t change = 0, perms, type;
1312 int length, str;
1313 char *val;
1314 va_list ap;
1315
1316 va_start(ap, fr);
1317 perms = va_arg(ap, fu16_t);
1318 type = va_arg(ap, fu16_t);
1319 length = va_arg(ap, int);
1320 val = va_arg(ap, char *);
1321 str = va_arg(ap, int);
1322 va_end(ap);
1323
1324 if (aimutil_get16(command->data+2) == 0x0005)
1325 change = 1;
1326
1327 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1328
1329 return 1;
1330}
1331#endif
1332
1333static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1334{
1335 struct aim_userinfo_s *userinfo;
1336
1337 va_list ap;
1338 va_start(ap, fr);
1339 userinfo = va_arg(ap, struct aim_userinfo_s *);
1340 va_end(ap);
1341
1342 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1343 time(NULL),
1344 userinfo->sn, userinfo->flags,
1345 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1346 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1347 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1348 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1349 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1350 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1351 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1352 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1353 userinfo->capabilities);
1354 return 1;
1355}
1356
1357static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1358{
1359 struct aim_userinfo_s *userinfo;
1360 va_list ap;
1361
1362 va_start(ap, fr);
1363 userinfo = va_arg(ap, struct aim_userinfo_s *);
1364 va_end(ap);
1365
1366 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1367 time(NULL),
1368 userinfo->sn, userinfo->flags,
1369 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1370 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1371 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1372 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1373 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1374 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1375 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1376 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1377 userinfo->capabilities);
1378
1379 return 1;
1380}
1381
1382static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1383{
1384 va_list ap;
1385 fu16_t reason;
1386
1387 va_start(ap, fr);
1388 reason = va_arg(ap, fu16_t);
1389 va_end(ap);
1390
1391 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1392
1393 return 1;
1394}
1395
1396static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1397{
1398 va_list ap;
1399 char *destsn;
1400 fu16_t reason;
1401
1402 va_start(ap, fr);
1403 reason = va_arg(ap, fu16_t);
1404 destsn = va_arg(ap, char *);
1405 va_end(ap);
1406
1407 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1408
1409 return 1;
1410}
1411
1412static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1413{
1414 va_list ap;
1415 char *destsn;
1416 fu16_t reason;
1417
1418 va_start(ap, fr);
1419 reason = va_arg(ap, fu16_t);
1420 destsn = va_arg(ap, char *);
1421 va_end(ap);
1422
1423 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1424
1425 return 1;
1426}
1427
1428static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1429{
1430 static char *missedreasons[] = {
1431 "Invalid (0)",
1432 "Message too large",
1433 "Rate exceeded",
1434 "Evil Sender",
1435 "Evil Receiver"
1436 };
1437 static int missedreasonslen = 5;
1438
1439 va_list ap;
1440 fu16_t chan, nummissed, reason;
1441 struct aim_userinfo_s *userinfo;
1442
1443 va_start(ap, fr);
1444 chan = va_arg(ap, fu16_t);
1445 userinfo = va_arg(ap, struct aim_userinfo_s *);
1446 nummissed = va_arg(ap, fu16_t);
1447 reason = va_arg(ap, fu16_t);
1448 va_end(ap);
1449
1450 dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1451
1452 return 1;
1453}
1454
1455/*
1456 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1457 */
1458static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1459{
1460 va_list ap;
1461 fu16_t type;
1462 char *sn = NULL;
1463
1464 va_start(ap, fr);
1465 type = va_arg(ap, fu16_t);
1466 sn = va_arg(ap, char *);
1467 va_end(ap);
1468
1469 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1470
1471 return 1;
1472}
1473
1474static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1475{
1476 static char *codes[5] = {
1477 "invalid",
1478 "change",
1479 "warning",
1480 "limit",
1481 "limit cleared"
1482 };
1483 va_list ap;
1484 fu16_t code, rateclass;
1485 fu32_t windowsize, clear, alert, limit, disconnect;
1486 fu32_t currentavg, maxavg;
1487
1488 va_start(ap, fr);
1489
1490 /* See code explanations below */
1491 code = va_arg(ap, fu16_t);
1492
1493 /*
1494 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1495 */
1496 rateclass = va_arg(ap, fu16_t);
1497
1498 /*
1499 * Not sure what this is exactly. I think its the temporal
1500 * relation factor (ie, how to make the rest of the numbers
1501 * make sense in the real world).
1502 */
1503 windowsize = va_arg(ap, fu32_t);
1504
1505 /* Explained below */
1506 clear = va_arg(ap, fu32_t);
1507 alert = va_arg(ap, fu32_t);
1508 limit = va_arg(ap, fu32_t);
1509 disconnect = va_arg(ap, fu32_t);
1510 currentavg = va_arg(ap, fu32_t);
1511 maxavg = va_arg(ap, fu32_t);
1512
1513 va_end(ap);
1514
1515
1516 dvprintf("faimtest: rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1517 (code < 5)?codes[code]:"invalid",
1518 rateclass,
1519 currentavg, maxavg,
1520 alert, clear,
1521 limit, disconnect,
1522 windowsize);
1523
1524 if (code == AIM_RATE_CODE_CHANGE) {
1525 /*
1526 * Not real sure when these get sent.
1527 */
1528 if (currentavg >= clear)
1529 aim_conn_setlatency(fr->conn, 0);
1530
1531 } else if (code == AIM_RATE_CODE_WARNING) {
1532 /*
1533 * We start getting WARNINGs the first time we go below the
1534 * 'alert' limit (currentavg < alert) and they stop when
1535 * either we pause long enough for currentavg to go above
1536 * 'clear', or until we flood it bad enough to go below
1537 * 'limit' (and start getting LIMITs instead) or even further
1538 * and go below 'disconnect' and get disconnected completely
1539 * (and won't be able to login right away either).
1540 */
1541 aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */
1542
1543 } else if (code == AIM_RATE_CODE_LIMIT) {
1544 /*
1545 * When we hit LIMIT, messages will start getting dropped.
1546 */
1547 aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */
1548
1549 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1550 /*
1551 * The limit is cleared when curavg goes above 'clear'.
1552 */
1553 aim_conn_setlatency(fr->conn, 0);
1554 }
1555
1556 return 1;
1557}
1558
1559static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1560{
1561 va_list ap;
1562 fu16_t newevil;
1563 struct aim_userinfo_s *userinfo;
1564
1565 va_start(ap, fr);
1566 newevil = va_arg(ap, fu16_t);
1567 userinfo = va_arg(ap, struct aim_userinfo_s *);
1568 va_end(ap);
1569
1570 /*
1571 * Evil Notifications that are lacking userinfo->sn are anon-warns
1572 * if they are an evil increases, but are not warnings at all if its
1573 * a decrease (its the natural backoff happening).
1574 *
1575 * newevil is passed as an int representing the new evil value times
1576 * ten.
1577 */
1578 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1579
1580 return 1;
1581}
1582
1583static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1584{
1585 va_list ap;
1586 char *address, *SNs;
1587 int i, num;
1588
1589 va_start(ap, fr);
1590 address = va_arg(ap, char *);
1591 num = va_arg(ap, int);
1592 SNs = va_arg(ap, char *);
1593 va_end(ap);
1594
1595 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
1596
1597 for(i = 0; i < num; i++)
1598 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1599 dinlineprintf("\n");
1600
1601 return 1;
1602}
1603
1604static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1605{
1606 va_list ap;
1607 char *address;
1608
1609 va_start(ap, fr);
1610 address = va_arg(ap, char *);
1611 va_end(ap);
1612
1613 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1614
1615 return 1;
1616}
1617
1618void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
1619{
1620
1621 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1622
1623 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1624 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */
1625 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
1626 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1627 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1628 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1629 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1630 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1631 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
1632 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1633 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
1634 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
1635 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
1636 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1637 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1638 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1639 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1640 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1641 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1642 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
1643 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1644 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
1645 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1646 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
1647 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1648
1649 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1650 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1651 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
1652
1653#ifdef MID_REWROTE_ALL_THE_CRAP
1654 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
1655#endif
1656
1657 return;
1658}
1659
This page took 0.05231 seconds and 5 git commands to generate.