]> andersk Git - libfaim.git/blame - utils/faimtest/faimtest.c
- Sat Aug 25 18:35:13 PDT 2001
[libfaim.git] / utils / faimtest / faimtest.c
CommitLineData
9de3ca7e 1/*
2 * -----------------------------------------------------------
3 * ProtoFAIM: v1.xx.xxplxx
4 * -----------------------------------------------------------
5 *
6 * This is ProtoFAIM v1.xx.xxplxx!!! Its nearly completely
7 * different than that ugly thing called v0. This app is
8 * compatible with the latest version of the libfaim library.
9 * Work is continuing.
10 *
11 * ProtoFAIM should only be used for two things...
12 * 1) Testing the libfaim backend.
13 * 2) For reference on the libfaim API when developing clients.
14 *
15 * Its very ugly. Probably always will be. Nothing is more
16 * ugly than the backend itself, however.
17 *
18 * -----------------------------------------------------------
19 *
20 * I'm releasing this code and all it's associated linkage
21 * under the GNU General Public License. For more information,
22 * please refer to http://www.fsf.org. For any questions,
23 * please contact me at the address below.
24 *
25 * Most everything:
646c6b52 26 * (c) 1998 Adam Fritzler, PST, mid@zigamoprh.net
9de3ca7e 27 *
28 * The password algorithms
646c6b52 29 * (c) 1998 Brock Wilcox, awwaiid@zigamorph.net
9de3ca7e 30 *
31 * THERE IS NO CODE FROM AOL'S AIM IN THIS CODE, NOR
32 * WAS THERE ANY DISASSEMBLAGE TO DEFINE PROTOCOL. All
33 * information was gained through painstakingly comparing
34 * TCP dumps while the AIM Java client was running. Nothing
35 * more than that, except for a lot of experimenting.
36 *
37 * -----------------------------------------------------------
38 *
39 */
40
b562f484 41#include "faimtest.h"
83ae98f8 42#include <sys/stat.h>
397055b1 43
37ee990e 44static char *dprintf_ctime(void)
45{
46 static char retbuf[64];
47 struct tm *lt;
48 struct timeval tv;
49 struct timezone tz;
50
51 gettimeofday(&tv, &tz);
52 lt = localtime((time_t *)&tv.tv_sec);
53 strftime(retbuf, 64, "%a %b %e %H:%M:%S %Z %Y", lt);
54 return retbuf;
55}
56
646c6b52 57#define DPRINTF_OUTSTREAM stdout
37ee990e 58#define dprintf(x) { \
646c6b52 59 fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest"); \
60 fflush(DPRINTF_OUTSTREAM); \
37ee990e 61}
62#define dvprintf(x, y...) { \
646c6b52 63 fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest", y); \
64 fflush(DPRINTF_OUTSTREAM); \
37ee990e 65}
66#define dinlineprintf(x) { \
646c6b52 67 fprintf(DPRINTF_OUTSTREAM, x); \
68 fflush(DPRINTF_OUTSTREAM); \
37ee990e 69}
70#define dvinlineprintf(x, y...) { \
646c6b52 71 fprintf(DPRINTF_OUTSTREAM, x, y); \
72 fflush(DPRINTF_OUTSTREAM); \
37ee990e 73}
74#define dperror(x) dvprintf("%s: %s\n", x, strerror(errno));
75
397055b1 76int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, ...);
77int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...);
78int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...);
b1eac25a 79static int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...);
397055b1 80int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...);
81int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...);
82int faimtest_handleredirect(struct aim_session_t *, struct command_rx_struct *command, ...);
64c78745 83int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...);
397055b1 84int faimtest_serverready(struct aim_session_t *, struct command_rx_struct *command, ...);
ee49b735 85int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...);
397055b1 86int faimtest_parse_misses(struct aim_session_t *, struct command_rx_struct *command, ...);
1a8c261b 87int faimtest_parse_msgack(struct aim_session_t *, struct command_rx_struct *command, ...);
01b59e1e 88int faimtest_parse_motd(struct aim_session_t *, struct command_rx_struct *command, ...);
89int faimtest_parse_login(struct aim_session_t *, struct command_rx_struct *command, ...);
0c20631f 90int faimtest_chatnav_info(struct aim_session_t *, struct command_rx_struct *command, ...);
91int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...);
92int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...);
93int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...);
94int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...);
5e02cf44 95int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
e5012450 96int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
49c8a2fa 97
7392c79f 98int faimtest_directim_request(struct aim_session_t *sess, struct command_rx_struct *command, ...);
99int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...);
100int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
101int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...);
102int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
103int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...);
646c6b52 104
871e2fd0 105int faimtest_getfile_filereq(struct aim_session_t *sess, struct command_rx_struct *command, ...);
106int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...);
107int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...);
108int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
37ee990e 109int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...);
110int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...);
111int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...);
646c6b52 112int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...);
113int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...);
871e2fd0 114
1a8c261b 115int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...);
98c88242 116int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...);
37ee990e 117int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...);
118int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...);
96f8b1ed 119int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
120int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...);
121int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
1449ad2b 122int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
96f8b1ed 123
124static char *msgerrreasons[] = {
125 "Invalid error",
126 "Invalid SNAC",
127 "Rate to host",
128 "Rate to client",
129 "Not logged on",
130 "Service unavailable",
131 "Service not defined",
132 "Obsolete SNAC",
133 "Not supported by host",
134 "Not supported by client",
135 "Refused by client",
136 "Reply too big",
137 "Responses lost",
138 "Request denied",
139 "Busted SNAC payload",
140 "Insufficient rights",
141 "In local permit/deny",
142 "Too evil (sender)",
143 "Too evil (receiver)",
144 "User temporarily unavailable",
145 "No match",
146 "List overflow",
147 "Request ambiguous",
148 "Queue full",
149 "Not while on AOL"};
150static int msgerrreasonslen = 25;
7392c79f 151
b1eac25a 152static char *aimbinarypath = NULL;
22517493 153static char *screenname,*password,*server=NULL;
b562f484 154static char *proxy = NULL, *proxyusername = NULL, *proxypass = NULL;
37ee990e 155static char *ohcaptainmycaptain = NULL;
ee49b735 156static int connected = 0;
22517493 157
b562f484 158struct aim_session_t aimsess;
159int keepgoing = 1;
160
161static FILE *listingfile;
162static char *listingpath;
646c6b52 163
7b91722d 164static unsigned char *buddyicon = NULL;
165static int buddyiconlen = 0;
166static time_t buddyiconstamp = 0;
50038c74 167static unsigned short buddyiconsum = 0;
7b91722d 168
646c6b52 169static void faimtest_debugcb(struct aim_session_t *sess, int level, const char *format, va_list va)
170{
171
355229fe 172 vfprintf(stderr, format, va);
646c6b52 173
355229fe 174 return;
646c6b52 175}
37ee990e 176
f0a7908e 177int faimtest_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...)
178{
355229fe 179 va_list ap;
180 unsigned short interval = 0;
9f1a4013 181
355229fe 182 va_start(ap, command);
183 interval = va_arg(ap, int);
184 va_end(ap);
9f1a4013 185
355229fe 186 dvprintf("aim: minimum report interval: %d (seconds?)\n", interval);
9f1a4013 187
355229fe 188 if (!connected)
189 connected++;
190
191#if 0
192 aim_bos_reqservice(sess, command->conn, 0x0005); /* adverts */
193 aim_bos_reqservice(sess, command->conn, 0x000f); /* user directory */
194
195 /* Don't know what this does... */
196 /* XXX sess->sn should be normalized by the 0001/000f handler */
197 aim_0002_000b(sess, command->conn, sess->sn);
198#endif
199
200 aim_reqicbmparams(sess, command->conn);
201
202 return 1;
f0a7908e 203}
204
22517493 205int faimtest_flapversion(struct aim_session_t *sess, struct command_rx_struct *command, ...)
206{
207
355229fe 208 dvprintf("faimtest: using FLAP version %u\n", aimutil_get32(command->data));
22517493 209
210#if 0
355229fe 211 /*
212 * This is an alternate location for starting the login process.
213 */
214 /* XXX should do more checking to make sure its really the right AUTH conn */
215 if (command->conn->type == AIM_CONN_TYPE_AUTH) {
216 /* do NOT send a flapversion, request_login will send it if needed */
217 aim_request_login(sess, command->conn, screenname);
218 dprintf("faimtest: login request sent\n");
219 }
22517493 220#endif
221
355229fe 222 return 1;
22517493 223}
224
225/*
226 * This is a frivilous callback. You don't need it. I only used it for
227 * debugging non-blocking connects.
228 *
229 * If packets are sent to a conn before its fully connected, they
230 * will be queued and then transmitted when the connection completes.
231 *
232 */
233int faimtest_conncomplete(struct aim_session_t *sess, struct command_rx_struct *command, ...)
234{
355229fe 235 va_list ap;
236 struct aim_conn_t *conn;
22517493 237
355229fe 238 va_start(ap, command);
239 conn = va_arg(ap, struct aim_conn_t *);
240 va_end(ap);
22517493 241
355229fe 242 if (conn)
243 dvprintf("faimtest: connection on %d completed\n", conn->fd);
244
245 return 1;
22517493 246}
247
999b6d5f 248#ifdef _WIN32
249/*
250 * This is really all thats needed to link against libfaim on win32.
251 *
252 * Note that this particular version of faimtest has never been tested
253 * on win32, but I'm fairly sure it should.
254 */
255int initwsa(void)
256{
355229fe 257 WORD wVersionRequested;
258 WSADATA wsaData;
999b6d5f 259
355229fe 260 wVersionRequested = MAKEWORD(2,2);
261 return WSAStartup(wVersionRequested, &wsaData);
999b6d5f 262}
263#endif /* _WIN32 */
264
b562f484 265int faimtest_init(void)
266{
355229fe 267 struct aim_conn_t *stdinconn = NULL;
b562f484 268
355229fe 269 if (!(stdinconn = aim_newconn(&aimsess, 0, NULL))) {
270 dprintf("unable to create connection for stdin!\n");
271 return -1;
272 }
b562f484 273
355229fe 274 stdinconn->fd = STDIN_FILENO;
b562f484 275
355229fe 276 return 0;
b562f484 277}
278
279int logout(void)
280{
d2587300 281
355229fe 282 if (ohcaptainmycaptain)
283 aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), ohcaptainmycaptain, 0, "ta ta...");
d2587300 284
355229fe 285 aim_session_kill(&aimsess);
b562f484 286
355229fe 287 if (faimtest_init() == -1)
288 dprintf("faimtest_init failed\n");
b562f484 289
355229fe 290 return 0;
b562f484 291}
292
293int login(const char *sn, const char *passwd)
294{
355229fe 295 struct aim_conn_t *authconn;
b562f484 296
355229fe 297 if (sn)
298 screenname = strdup(sn);
299 if (passwd)
300 password = strdup(passwd);
b562f484 301
355229fe 302 if (proxy)
303 aim_setupproxy(&aimsess, proxy, proxyusername, proxypass);
b562f484 304
355229fe 305 if (!screenname || !password) {
306 dprintf("need SN and password\n");
307 return -1;
308 }
b562f484 309
355229fe 310 if (!(authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, server?server:FAIM_LOGIN_SERVER))) {
311 dprintf("faimtest: internal connection error while in aim_login. bailing out.\n");
312 return -1;
313 } else if (authconn->fd == -1) {
314 if (authconn->status & AIM_CONN_STATUS_RESOLVERR) {
315 dprintf("faimtest: could not resolve authorizer name\n");
316 } else if (authconn->status & AIM_CONN_STATUS_CONNERR) {
317 dprintf("faimtest: could not connect to authorizer\n");
318 }
319 aim_conn_kill(&aimsess, &authconn);
320 return -1;
321 }
b562f484 322
355229fe 323 aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
324 aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
325 aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0);
326 aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0);
b562f484 327
355229fe 328 aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0);
b562f484 329
355229fe 330 /* If the connection is in progress, this will just be queued */
331 aim_request_login(&aimsess, authconn, screenname);
332 dprintf("faimtest: login request sent\n");
b562f484 333
355229fe 334 return 0;
b562f484 335}
336
37ee990e 337int main(int argc, char **argv)
9de3ca7e 338{
355229fe 339 struct aim_conn_t *waitingconn = NULL;
340 int i;
341 int selstat = 0;
342 static int faimtest_mode = 0;
343 struct timeval tv;
344 time_t lastnop = 0;
345 const char *buddyiconpath = NULL;
346
347 screenname = getenv("SCREENNAME");
348 password = getenv("PASSWORD");
349 server = getenv("AUTHSERVER");
350 proxy = getenv("SOCKSPROXY");
351 proxyusername = getenv("SOCKSNAME");
352 proxypass = getenv("SOCKSPASS");
353
354 listingpath = getenv("LISTINGPATH");
355
356 while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:i:")) != EOF) {
357 switch (i) {
358 case 'u': screenname = optarg; break;
359 case 'p': password = optarg; break;
360 case 'a': server = optarg; break;
361 case 'U': proxyusername = optarg; break;
362 case 'P': proxypass = optarg; break;
363 case 'A': proxy = optarg; break;
364 case 'l': listingpath = optarg; break;
365 case 'c': ohcaptainmycaptain = optarg; break;
366 case 'o': faimtest_mode = 1; break; /* half old interface */
367 case 'O': faimtest_mode = 2; break; /* full old interface */
368 case 'b': aimbinarypath = optarg; break;
369 case 'i': buddyiconpath = optarg; break;
370 case 'h':
371 default:
372 printf("faimtest\n");
373 printf(" Options: \n");
374 printf(" -u name Screen name ($SCREENNAME)\n");
375 printf(" -p passwd Password ($PASSWORD)\n");
376 printf(" -a host:port Authorizer ($AUTHSERVER)\n");
377 printf(" -U name Proxy user name ($SOCKSPROXY)\n");
378 printf(" -P passwd Proxy password ($SOCKSNAME)\n");
379 printf(" -A host:port Proxy host ($SOCKSPASS)\n");
380 printf(" -l path Path to listing file ($LISTINGPATH)\n");
381 printf(" -c name Screen name of owner\n");
382 printf(" -o Login at startup, then prompt\n");
383 printf(" -O Login, never give prompt\n");
384 printf(" -b path Path to AIM 3.5.1670 binaries\n");
385 printf(" -i file Buddy Icon to send\n");
386 exit(0);
387 }
388 }
37ee990e 389
999b6d5f 390#ifdef _WIN32
355229fe 391 if (initwsa() != 0) {
392 dprintf("faimtest: could not initialize windows sockets\n");
393 return -1;
394 }
999b6d5f 395#endif /* _WIN32 */
396
355229fe 397 /* Pass zero as flags if you want blocking connects */
398 aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 1);
399 aim_setdebuggingcb(&aimsess, faimtest_debugcb); /* still needed even if debuglevel = 0 ! */
7b91722d 400
355229fe 401 if (listingpath) {
402 char *listingname;
403
404 if (!(listingname = (char *)calloc(1, strlen(listingpath)+strlen("/listing.txt")))) {
405 dperror("listingname calloc");
406 exit(-1);
407 }
7b91722d 408
355229fe 409 sprintf(listingname, "%s/listing.txt", listingpath);
410
411 if ((listingfile = fopen(listingname, "r")) == NULL)
412 dvprintf("Couldn't open %s... disabling that shit.\n", listingname);
7b91722d 413
355229fe 414 free(listingname);
415 }
50038c74 416
355229fe 417 if (buddyiconpath) {
418 struct stat st;
419 FILE *f;
7b91722d 420
355229fe 421 if ((stat(buddyiconpath, &st) != -1) && (st.st_size <= MAXICONLEN) && (f = fopen(buddyiconpath, "r"))) {
7b91722d 422
355229fe 423 buddyiconlen = st.st_size;
424 buddyiconstamp = st.st_mtime;
425 buddyicon = malloc(buddyiconlen);
426 fread(buddyicon, 1, st.st_size, f);
7b91722d 427
355229fe 428 buddyiconsum = aim_iconsum(buddyicon, buddyiconlen);
7b91722d 429
355229fe 430 dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", buddyiconlen, buddyiconpath, buddyiconsum);
bb0dc593 431
355229fe 432 fclose(f);
9bf14d44 433
355229fe 434 } else
435 dvprintf("could not open buddy icon %s\n", buddyiconpath);
9de3ca7e 436
355229fe 437 }
d32954e7 438
355229fe 439 faimtest_init();
d32954e7 440
355229fe 441 if (faimtest_mode < 2)
442 cmd_init();
d32954e7 443
355229fe 444 if (faimtest_mode >= 1) {
445 if (login(screenname, password) == -1) {
446 if (faimtest_mode < 2)
447 cmd_uninit();
448 exit(-1);
449 }
450 }
b8d0da45 451
355229fe 452 while (keepgoing) {
453
454 tv.tv_sec = 5;
455 tv.tv_usec = 0;
456
457 waitingconn = aim_select(&aimsess, &tv, &selstat);
458
459 if (connected && ((time(NULL) - lastnop) > 30)) {
460 lastnop = time(NULL);
461 aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS));
462 }
463
464 if (selstat == -1) { /* error */
465 keepgoing = 0; /* fall through */
466 } else if (selstat == 0) { /* no events pending */
467 ;
468 } else if (selstat == 1) { /* outgoing data pending */
469 aim_tx_flushqueue(&aimsess);
470 } else if (selstat == 2) { /* incoming data pending */
471 if ((faimtest_mode < 2) && (waitingconn->fd == STDIN_FILENO)) {
472 cmd_gotkey();
473 } else {
474 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
475 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
476 dprintf("connection error (rend out)\n");
477 aim_conn_kill(&aimsess, &waitingconn);
478 }
479 } else {
480 if (aim_get_command(&aimsess, waitingconn) >= 0) {
481 aim_rxdispatch(&aimsess);
482 } else {
483 dvprintf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype);
484 /* we should have callbacks for all these, else the library will do the conn_kill for us. */
485 if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
486 dprintf("connection error: rendezvous connection. you forgot register a disconnect callback, right?\n");
487 aim_conn_kill(&aimsess, &waitingconn);
488 } else
489 aim_conn_kill(&aimsess, &waitingconn);
490 if (!aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)) {
491 dprintf("major connection error\n");
492 if (faimtest_mode == 2)
493 break;
494 }
495 }
496 }
497 }
498 }
7392c79f 499 }
9de3ca7e 500
355229fe 501 /* close up all connections, dead or no */
502 aim_session_kill(&aimsess);
9de3ca7e 503
355229fe 504 if (faimtest_mode < 2) {
505 printf("\n");
506 cmd_uninit();
507 }
b562f484 508
355229fe 509 free(buddyicon);
7b91722d 510
355229fe 511 /* Get out */
512 exit(0);
9de3ca7e 513}
514
c78446b5 515int faimtest_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...)
516{
517
355229fe 518 switch(command->conn->type) {
519 case AIM_CONN_TYPE_BOS: {
520 /* this is the new buddy list */
521 char buddies[128];
522 /* this is the new profile */
523 char profile[256];
524 char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
c78446b5 525
355229fe 526 /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
527 snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", ohcaptainmycaptain?ohcaptainmycaptain:"blah");
528 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.", ohcaptainmycaptain);
c78446b5 529
355229fe 530 aim_bos_ackrateresp(sess, command->conn); /* ack rate info response */
531 aim_bos_reqpersonalinfo(sess, command->conn);
532 aim_bos_reqlocaterights(sess, command->conn);
533 aim_bos_setprofile(sess, command->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE /*| AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS*/);
534 aim_bos_reqbuddyrights(sess, command->conn);
c78446b5 535
355229fe 536 /* send the buddy list and profile (required, even if empty) */
537 aim_bos_setbuddylist(sess, command->conn, buddies);
538
539 aim_reqicbmparams(sess, command->conn);
540
541 aim_bos_reqrights(sess, command->conn);
542 /* set group permissions -- all user classes */
543 aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS);
544 aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE);
545
546 break;
547 }
548 case AIM_CONN_TYPE_AUTH:
549 aim_bos_ackrateresp(sess, command->conn);
550 aim_auth_clientready(sess, command->conn);
551 dprintf("faimtest: connected to authorization/admin service\n");
552 break;
553
554 default:
555 dvprintf("faimtest: got rate response for unhandled connection type %04x\n", command->conn->type);
556 break;
557 }
558
559 return 1;
c78446b5 560}
561
00ef5271 562static int faimtest_icbmparaminfo(struct aim_session_t *sess, struct command_rx_struct *command, ...)
563{
355229fe 564 struct aim_icbmparameters *params;
565 va_list ap;
00ef5271 566
355229fe 567 va_start(ap, command);
568 params = va_arg(ap, struct aim_icbmparameters *);
569 va_end(ap);
00ef5271 570
355229fe 571 dvprintf("ICBM Parameters: maxchannel = %d, default flags = 0x%08lx, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %ld\n", params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval);
00ef5271 572
355229fe 573 params->maxchan = 0; /* this has to be set to zero in the response */
574 //params->flags = 0;
575 params->maxmsglen = 8000;
576 params->minmsginterval = 0;
577
578 aim_seticbmparam(sess, command->conn, params);
579
580 return 1;
00ef5271 581}
582
ee49b735 583int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...)
584{
355229fe 585 int vercount, i;
586 unsigned char *versions;
587 va_list ap;
588
589 va_start(ap, command);
590 vercount = va_arg(ap, int); /* number of family/version pairs */
591 versions = va_arg(ap, unsigned char *);
592 va_end(ap);
593
594 dprintf("faimtest: SNAC versions supported by this host: ");
595 for (i = 0; i < vercount*4; i += 4) {
596 dvinlineprintf("0x%04x:0x%04x ",
597 aimutil_get16(versions+i), /* SNAC family */
598 aimutil_get16(versions+i+2) /* Version number */);
599 }
600 dinlineprintf("\n");
ee49b735 601
355229fe 602 return 1;
ee49b735 603}
604
64c78745 605int faimtest_accountconfirm(struct aim_session_t *sess, struct command_rx_struct *command, ...)
606{
355229fe 607 int status;
608 va_list ap;
64c78745 609
355229fe 610 va_start(ap, command);
611 status = va_arg(ap, int); /* status code of confirmation request */
612 va_end(ap);
64c78745 613
355229fe 614 dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
64c78745 615
355229fe 616 return 1;
64c78745 617}
618
397055b1 619int faimtest_serverready(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 620{
ee49b735 621 int famcount, i;
622 unsigned short *families;
623 va_list ap;
26af6789 624
ee49b735 625 va_start(ap, command);
626 famcount = va_arg(ap, int);
627 families = va_arg(ap, unsigned short *);
628 va_end(ap);
9de3ca7e 629
37ee990e 630 dvprintf("faimtest: SNAC families supported by this host (type %d): ", command->conn->type);
ee49b735 631 for (i = 0; i < famcount; i++)
37ee990e 632 dvinlineprintf("0x%04x ", families[i]);
633 dinlineprintf("\n");
0c20631f 634
ee49b735 635 switch (command->conn->type) {
64c78745 636 case AIM_CONN_TYPE_AUTH:
637 aim_auth_setversions(sess, command->conn);
638 aim_bos_reqrate(sess, command->conn); /* request rate info */
639
640 dprintf("faimtest: done with auth ServerReady\n");
641 break;
642
ee49b735 643 case AIM_CONN_TYPE_BOS:
0c20631f 644
ee49b735 645 aim_setversions(sess, command->conn);
646 aim_bos_reqrate(sess, command->conn); /* request rate info */
7392c79f 647
37ee990e 648 dprintf("faimtest: done with BOS ServerReady\n");
ee49b735 649 break;
650
651 case AIM_CONN_TYPE_CHATNAV:
37ee990e 652 dprintf("faimtest: chatnav: got server ready\n");
ee49b735 653 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
654 aim_bos_reqrate(sess, command->conn);
655 aim_bos_ackrateresp(sess, command->conn);
656 aim_chatnav_clientready(sess, command->conn);
657 aim_chatnav_reqrights(sess, command->conn);
658
659 break;
660
661 case AIM_CONN_TYPE_CHAT:
662 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
663 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
664 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
665 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
666 aim_bos_reqrate(sess, command->conn);
667 aim_bos_ackrateresp(sess, command->conn);
668 aim_chat_clientready(sess, command->conn);
669 break;
670
671 case AIM_CONN_TYPE_RENDEZVOUS: /* empty */
672 break;
673
674 default:
64c78745 675 dvprintf("faimtest: unknown connection type on Host Online (0x%04x)\n", command->conn->type);
ee49b735 676 }
7392c79f 677
9de3ca7e 678 return 1;
679}
680
96f8b1ed 681int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...)
00f3b08b 682{
96f8b1ed 683 va_list ap;
684 unsigned short maxbuddies, maxwatchers;
685
686 va_start(ap, command);
e7fb57f5 687 maxbuddies = va_arg(ap, int);
688 maxwatchers = va_arg(ap, int);
96f8b1ed 689 va_end(ap);
690
37ee990e 691 dvprintf("faimtest: buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
96f8b1ed 692
693 return 1;
694}
695
c78446b5 696int faimtest_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...)
697{
96f8b1ed 698 unsigned short maxpermits, maxdenies;
699 va_list ap;
700
701 va_start(ap, command);
e7fb57f5 702 maxpermits = va_arg(ap, int);
703 maxdenies = va_arg(ap, int);
96f8b1ed 704 va_end(ap);
705
37ee990e 706 dvprintf("faimtest: BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
96f8b1ed 707
c78446b5 708 aim_bos_clientready(sess, command->conn);
709
37ee990e 710 dprintf("faimtest: officially connected to BOS.\n");
711
712 return 1;
713}
714
b39e0a91 715int faimtest_locrights(struct aim_session_t *sess, struct command_rx_struct *command, ...)
716{
717 unsigned short maxsiglen;
718 va_list ap;
719
720 va_start(ap, command);
721 maxsiglen = va_arg(ap, int);
722 va_end(ap);
723
724 dvprintf("faimtest: locate rights: max signature length = %d\n", maxsiglen);
725
726 return 1;
727}
728
37ee990e 729int faimtest_parse_unknown(struct aim_session_t *sess, struct command_rx_struct *command, ...)
730{
731 int i = 0;
732
733 if (!sess || !command)
734 return 1;
735
646c6b52 736 dprintf("\nReceived unknown packet:");
37ee990e 737 for (i = 0; i < command->commandlen; i++) {
738 if ((i % 8) == 0)
739 dinlineprintf("\n\t");
740 dvinlineprintf("0x%2x ", command->data[i]);
741 }
742 dinlineprintf("\n\n");
c78446b5 743
744 return 1;
745}
746
9de3ca7e 747/*
748 handleredirect()...
749
750 This, of course, handles Service Redirects from OSCAR.
751
752 Should get passed in the following:
753 struct command_rx_struct *command
754 the raw command data
755 int serviceid
756 the destination service ID
757 char *serverip
758 the IP address of the service's server
759 char *cookie
760 the raw auth cookie
761 */
397055b1 762int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 763{
764 va_list ap;
765 int serviceid;
766 char *ip;
78b3fb13 767 unsigned char *cookie;
9de3ca7e 768
9de3ca7e 769 va_start(ap, command);
770 serviceid = va_arg(ap, int);
771 ip = va_arg(ap, char *);
78b3fb13 772 cookie = va_arg(ap, unsigned char *);
0c20631f 773
e80a0fa9 774 switch(serviceid) {
775 case 0x0005: { /* Adverts */
776 struct aim_conn_t *tstconn;
64c78745 777
e80a0fa9 778 tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, ip);
779 if ((tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
780 dprintf("faimtest: unable to reconnect with authorizer\n");
781 } else {
782 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
783 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
784 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
785 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
786 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
787 aim_auth_sendcookie(sess, tstconn, cookie);
788 dprintf("sent cookie to adverts host\n");
789 }
790 break;
791 }
792 case 0x0007: { /* Authorizer */
793 struct aim_conn_t *tstconn;
794 /* Open a connection to the Auth */
795 tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
796 if ((tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
797 dprintf("faimtest: unable to reconnect with authorizer\n");
798 } else {
799 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
800 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
801 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
802 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
803 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
804 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
805 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
806 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
807 /* Send the cookie to the Auth */
808 aim_auth_sendcookie(sess, tstconn, cookie);
809 dprintf("sent cookie to authorizer host\n");
810 }
811 break;
812 }
813 case 0x000d: { /* ChatNav */
814 struct aim_conn_t *tstconn = NULL;
815 tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip);
816 if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
817 dprintf("faimtest: unable to connect to chatnav server\n");
818 if (tstconn) aim_conn_kill(sess, &tstconn);
819 return 1;
820 }
9de3ca7e 821
e80a0fa9 822 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
823 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
824 aim_auth_sendcookie(sess, tstconn, cookie);
825 dprintf("\achatnav: connected\n");
826 break;
827 }
828 case 0x000e: { /* Chat */
829 char *roomname = NULL;
830 int exchange;
831 struct aim_conn_t *tstconn = NULL;
832
833 roomname = va_arg(ap, char *);
834 exchange = va_arg(ap, int);
835
836 tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip);
837 if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
838 dprintf("faimtest: unable to connect to chat server\n");
839 if (tstconn) aim_conn_kill(sess, &tstconn);
840 return 1;
841 }
842 dvprintf("faimtest: chat: connected to %s on exchange %d\n", roomname, exchange);
843
844 /*
845 * We must do this to attach the stored name to the connection!
846 */
847 aim_chat_attachname(tstconn, roomname);
848
849 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
850 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
851 aim_auth_sendcookie(sess, tstconn, cookie);
00ef5271 852
e80a0fa9 853 break;
854 }
855 default:
856 dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
857 /* dunno */
858 }
9de3ca7e 859
9de3ca7e 860 va_end(ap);
861
0c20631f 862 return 1;
9de3ca7e 863}
864
83ae98f8 865/*
866 * This is a little more complicated than it looks. The module
867 * name (proto, boscore, etc) may or may not be given. If it is
868 * not given, then use aim.exe. If it is given, put ".ocm" on the
869 * end of it.
870 *
871 * Now, if the offset or length requested would cause a read past
872 * the end of the file, then the request is considered invalid. Invalid
873 * requests are processed specially. The value hashed is the
874 * the request, put into little-endian (eight bytes: offset followed
875 * by length).
876 *
877 * Additionally, if the request is valid, the length is mod 4096. It is
878 * important that the length is checked for validity first before doing
879 * the mod.
880 *
881 * Note to Bosco's Brigade: if you'd like to break this, put the
882 * module name on an invalid request.
883 *
884 */
885static int getaimdata(unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
b1eac25a 886{
887 FILE *f;
5ac961d5 888 static const char defaultmod[] = "aim.exe";
889 char *filename = NULL;
83ae98f8 890 struct stat st;
891 unsigned char *buf;
892 int invalid = 0;
b1eac25a 893
6c05e183 894 if (!bufret || !buflenret)
83ae98f8 895 return -1;
001c9b80 896
5ac961d5 897 if (modname) {
328837f7 898
5ac961d5 899 if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(modname)+4+1))) {
900 dperror("memrequest: malloc");
901 return -1;
902 }
903
904 sprintf(filename, "%s/%s.ocm", aimbinarypath, modname);
905
906 } else {
907
908 if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(defaultmod)+1))) {
909 dperror("memrequest: malloc");
910 return -1;
911 }
912
913 sprintf(filename, "%s/%s", aimbinarypath, defaultmod);
328837f7 914
328837f7 915 }
916
83ae98f8 917 if (stat(filename, &st) == -1) {
f6a4f6b7 918 if (!modname) {
919 dperror("memrequest: stat");
920 free(filename);
921 return -1;
922 }
923 invalid = 1;
b1eac25a 924 }
925
f6a4f6b7 926 if (!invalid) {
927 if ((offset > st.st_size) || (len > st.st_size))
928 invalid = 1;
929 else if ((st.st_size - offset) < len)
930 len = st.st_size - offset;
931 else if ((st.st_size - len) < len)
932 len = st.st_size - len;
933 }
83ae98f8 934
935 if (!invalid && len)
936 len %= 4096;
937
938 if (invalid) {
f6a4f6b7 939 int i;
83ae98f8 940
941 free(filename); /* not needed */
942
f6a4f6b7 943 dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
944
945 i = 8;
946 if (modname)
947 i += strlen(modname);
948
949 if (!(buf = malloc(i)))
83ae98f8 950 return -1;
951
f6a4f6b7 952 i = 0;
953
954 if (modname) {
955 memcpy(buf, modname, strlen(modname));
956 i += strlen(modname);
957 }
83ae98f8 958
959 /* Damn endianness. This must be little (LSB first) endian. */
f6a4f6b7 960 buf[i++] = offset & 0xff;
961 buf[i++] = (offset >> 8) & 0xff;
962 buf[i++] = (offset >> 16) & 0xff;
963 buf[i++] = (offset >> 24) & 0xff;
964 buf[i++] = len & 0xff;
965 buf[i++] = (len >> 8) & 0xff;
966 buf[i++] = (len >> 16) & 0xff;
967 buf[i++] = (len >> 24) & 0xff;
83ae98f8 968
969 *bufret = buf;
f6a4f6b7 970 *buflenret = i;
83ae98f8 971
972 } else {
973
974 if (!(buf = malloc(len))) {
975 free(filename);
976 return -1;
977 }
978
979 dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename);
980
981 if (!(f = fopen(filename, "r"))) {
982 dperror("memrequest: fopen");
983 free(filename);
984 free(buf);
985 return -1;
986 }
987
988 free(filename);
5ac961d5 989
001c9b80 990 if (fseek(f, offset, SEEK_SET) == -1) {
991 dperror("memrequest: fseek");
992 fclose(f);
83ae98f8 993 free(buf);
001c9b80 994 return -1;
995 }
b1eac25a 996
83ae98f8 997 if (fread(buf, len, 1, f) != 1) {
001c9b80 998 dperror("memrequest: fread");
999 fclose(f);
83ae98f8 1000 free(buf);
001c9b80 1001 return -1;
1002 }
b1eac25a 1003
83ae98f8 1004 fclose(f);
1005
1006 *bufret = buf;
1007 *buflenret = len;
1008
1009 }
b1eac25a 1010
83ae98f8 1011 return 0; /* success! */
b1eac25a 1012}
1013
1014/*
1015 * This will get an offset and a length. The client should read this
1016 * data out of whatever AIM.EXE binary the user has provided (hopefully
1017 * it matches the client information thats sent at login) and pass a
1018 * buffer back to libfaim so it can hash the data and send it to AOL for
1019 * inspection by the client police.
1020 */
1021static int faimtest_memrequest(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1022{
1023 va_list ap;
1024 unsigned long offset, len;
328837f7 1025 char *modname;
83ae98f8 1026 unsigned char *buf;
1027 int buflen;
b1eac25a 1028
1029 va_start(ap, command);
1030 offset = va_arg(ap, unsigned long);
1031 len = va_arg(ap, unsigned long);
328837f7 1032 modname = va_arg(ap, char *);
b1eac25a 1033 va_end(ap);
1034
83ae98f8 1035 if (aimbinarypath && (getaimdata(&buf, &buflen, offset, len, modname) == 0)) {
b1eac25a 1036
83ae98f8 1037 aim_sendmemblock(sess, command->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 1038
83ae98f8 1039 free(buf);
b1eac25a 1040
1041 } else {
1042
328837f7 1043 dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", aimbinarypath, modname);
b1eac25a 1044
d2698e03 1045 aim_sendmemblock(sess, command->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
b1eac25a 1046
1047 }
1048
b1eac25a 1049 return 1;
1050}
1051
1052static int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1053{
355982c5 1054 va_list ap;
9de3ca7e 1055 struct aim_conn_t *bosconn = NULL;
355982c5 1056 char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
1057 unsigned char *cookie = NULL;
1058 int errorcode = 0, regstatus = 0;
89bce177 1059 int latestbuild = 0, latestbetabuild = 0;
1060 char *latestrelease = NULL, *latestbeta = NULL;
1061 char *latestreleaseurl = NULL, *latestbetaurl = NULL;
1062 char *latestreleaseinfo = NULL, *latestbetainfo = NULL;
1063
355982c5 1064 va_start(ap, command);
1065 sn = va_arg(ap, char *);
1066 errorcode = va_arg(ap, int);
1067 errurl = va_arg(ap, char *);
1068 regstatus = va_arg(ap, int);
1069 email = va_arg(ap, char *);
1070 bosip = va_arg(ap, char *);
1071 cookie = va_arg(ap, unsigned char *);
89bce177 1072
1073 latestrelease = va_arg(ap, char *);
1074 latestbuild = va_arg(ap, int);
1075 latestreleaseurl = va_arg(ap, char *);
1076 latestreleaseinfo = va_arg(ap, char *);
1077
1078 latestbeta = va_arg(ap, char *);
1079 latestbetabuild = va_arg(ap, int);
1080 latestbetaurl = va_arg(ap, char *);
1081 latestbetainfo = va_arg(ap, char *);
1082
355982c5 1083 va_end(ap);
01b59e1e 1084
37ee990e 1085 dvprintf("Screen name: %s\n", sn);
01b59e1e 1086
1087 /*
1088 * Check for error.
1089 */
355982c5 1090 if (errorcode || !bosip || !cookie) {
37ee990e 1091 dvprintf("Login Error Code 0x%04x\n", errorcode);
1092 dvprintf("Error URL: %s\n", errurl);
9bf14d44 1093 aim_conn_kill(sess, &command->conn);
355982c5 1094 return 1;
1095 }
01b59e1e 1096
37ee990e 1097 dvprintf("Reg status: %2d\n", regstatus);
1098 dvprintf("Email: %s\n", email);
1099 dvprintf("BOS IP: %s\n", bosip);
9de3ca7e 1100
89bce177 1101 if (latestbeta)
37ee990e 1102 dvprintf("Latest beta version: %s, build %d, at %s (more info at %s)\n", latestbeta, latestbetabuild, latestbetaurl, latestbetainfo);
89bce177 1103
1104 if (latestrelease)
37ee990e 1105 dvprintf("Latest released version: %s, build %d, at %s (more info at %s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo);
89bce177 1106
37ee990e 1107 dprintf("Closing auth connection...\n");
040457cc 1108 aim_conn_kill(sess, &command->conn);
355982c5 1109 if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
37ee990e 1110 dprintf("faimtest: could not connect to BOS: internal error\n");
355982c5 1111 return 1;
22517493 1112 } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
37ee990e 1113 dprintf("faimtest: could not connect to BOS\n");
040457cc 1114 aim_conn_kill(sess, &bosconn);
355982c5 1115 return 1;
1116 }
1117
1118 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1119 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
1120 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
1121 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
ee49b735 1122 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
355982c5 1123 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
1124 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
1125 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
1126 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
1127 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
1128 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
1129 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
1130 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1131 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
1132 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
1133 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
1134 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
37ee990e 1135 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
1136 aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
355982c5 1137 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
1138 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
b39e0a91 1139 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
355982c5 1140 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
1141
355982c5 1142 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
00ef5271 1143
1144 aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
1449ad2b 1145 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
1146 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
1147 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
1148
355982c5 1149 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
b1eac25a 1150 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
d32954e7 1151 aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
1449ad2b 1152
355982c5 1153 aim_auth_sendcookie(sess, bosconn, cookie);
1154
9de3ca7e 1155 return 1;
1156}
1157
a15d82b1 1158static void printuserflags(unsigned short flags)
1159{
1160 if (flags & AIM_FLAG_UNCONFIRMED)
37ee990e 1161 dinlineprintf("UNCONFIRMED ");
a15d82b1 1162 if (flags & AIM_FLAG_ADMINISTRATOR)
37ee990e 1163 dinlineprintf("ADMINISTRATOR ");
a15d82b1 1164 if (flags & AIM_FLAG_AOL)
37ee990e 1165 dinlineprintf("AOL ");
a15d82b1 1166 if (flags & AIM_FLAG_OSCAR_PAY)
37ee990e 1167 dinlineprintf("OSCAR_PAY ");
a15d82b1 1168 if (flags & AIM_FLAG_FREE)
37ee990e 1169 dinlineprintf("FREE ");
a15d82b1 1170 if (flags & AIM_FLAG_AWAY)
37ee990e 1171 dinlineprintf("AWAY ");
a15d82b1 1172 if (flags & AIM_FLAG_UNKNOWN40)
37ee990e 1173 dinlineprintf("ICQ? ");
a15d82b1 1174 if (flags & AIM_FLAG_UNKNOWN80)
37ee990e 1175 dinlineprintf("UNKNOWN80 ");
a15d82b1 1176 return;
1177}
1178
397055b1 1179int faimtest_parse_userinfo(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1180{
1181 struct aim_userinfo_s *userinfo;
1182 char *prof_encoding = NULL;
1183 char *prof = NULL;
5e02cf44 1184 unsigned short inforeq = 0;
9de3ca7e 1185
1186 va_list ap;
1187 va_start(ap, command);
1188 userinfo = va_arg(ap, struct aim_userinfo_s *);
1189 prof_encoding = va_arg(ap, char *);
1190 prof = va_arg(ap, char *);
e7fb57f5 1191 inforeq = va_arg(ap, int);
9de3ca7e 1192 va_end(ap);
1193
37ee990e 1194 dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn);
1195 dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
1196 dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
a15d82b1 1197 printuserflags(userinfo->flags);
37ee990e 1198 dinlineprintf("\n");
9de3ca7e 1199
37ee990e 1200 dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
1201 dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
1202 dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
9de3ca7e 1203
5e02cf44 1204 if (inforeq == AIM_GETINFO_GENERALINFO) {
37ee990e 1205 dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1206 dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
5e02cf44 1207 } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
37ee990e 1208 dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1209 dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
5e02cf44 1210 } else
37ee990e 1211 dprintf("faimtest: userinfo: unknown info request\n");
9de3ca7e 1212
1213 return 1;
1214}
1215
d2587300 1216static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_struct *command, struct aim_userinfo_s *userinfo, char *tmpstr)
1217{
1218
1219 if (!strncmp(tmpstr, "disconnect", 10)) {
1220
1221 logout();
1222
1223 } else if (strstr(tmpstr, "goodday")) {
1224
7b91722d 1225 aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
1226
1227 } else if (strstr(tmpstr, "haveicon") && buddyicon) {
1228 struct aim_sendimext_args args;
1229 static const char iconmsg[] = {"I have an icon"};
1230
1231 args.destsn = userinfo->sn;
1232 args.flags = AIM_IMFLAGS_HASICON;
1233 args.msg = iconmsg;
1234 args.msglen = strlen(iconmsg);
1235 args.iconlen = buddyiconlen;
1236 args.iconstamp = buddyiconstamp;
50038c74 1237 args.iconsum = buddyiconsum;
7b91722d 1238
1239 aim_send_im_ext(sess, command->conn, &args);
1240
1241 } else if (strstr(tmpstr, "sendicon") && buddyicon) {
1242
50038c74 1243 aim_send_icon(sess, command->conn, userinfo->sn, buddyicon, buddyiconlen, buddyiconstamp, buddyiconsum);
d2587300 1244
1245 } else if (strstr(tmpstr, "warnme")) {
1246
1247 dprintf("faimtest: icbm: sending non-anon warning\n");
1248 aim_send_warning(sess, command->conn, userinfo->sn, 0);
1249
1250 } else if (strstr(tmpstr, "anonwarn")) {
1251
1252 dprintf("faimtest: icbm: sending anon warning\n");
1253 aim_send_warning(sess, command->conn, userinfo->sn, AIM_WARN_ANON);
1254
1255 } else if (strstr(tmpstr, "setdirectoryinfo")) {
1256
1257 dprintf("faimtest: icbm: sending backwards profile data\n");
1258 aim_setdirectoryinfo(sess, command->conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1259
1260 } else if (strstr(tmpstr, "setinterests")) {
1261
1262 dprintf("faimtest: icbm: setting fun interests\n");
1263 aim_setuserinterests(sess, command->conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1264
1265 } else if (!strncmp(tmpstr, "getfile", 7)) {
1266
1267 if (!ohcaptainmycaptain) {
1268
7b91722d 1269 aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
d2587300 1270
1271 } else {
1272 struct aim_conn_t *newconn;
1273
1274 newconn = aim_getfile_initiate(sess, command->conn, (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
1275 dvprintf("faimtest: getting file listing from %s\n", (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
1276 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
1277 }
1278
1279 } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1280
1281 aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
1282
1283 } else if (!strncmp(tmpstr, "create", 6)) {
1284
1285 aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1286
1287 } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1288 struct aim_conn_t *chatnavconn;
1289
1290 chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV);
1291 aim_conn_kill(sess, &chatnavconn);
1292
1293 } else if (!strncmp(tmpstr, "join", 4)) {
1294
1295 aim_chat_join(sess, command->conn, 0x0004, "worlddomination");
1296
1297 } else if (!strncmp(tmpstr, "leave", 5)) {
1298
1299 aim_chat_leaveroom(sess, "worlddomination");
1300
1301 } else if (!strncmp(tmpstr, "getinfo", 7)) {
1302
1303 aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
1304 aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
00ef5271 1305 aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_GENERALINFO);
1306 aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
d2587300 1307
1308 } else if (!strncmp(tmpstr, "open directim", 13)) {
1309 struct aim_conn_t *newconn;
1310
1311 printf("faimtest: opening directim to %s\n", (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1312 newconn = aim_directim_initiate(sess, command->conn, NULL, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1313 if(!newconn || newconn->fd == -1)
1314 printf("connection failed!\n");
1315 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate,0);
1316
1317 } else if(!(strncmp(tmpstr, "lookup", 6))) {
1318
1319 aim_usersearch_address(sess, command->conn, tmpstr+7);
1320
1321 } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1322
7b91722d 1323 aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900");
d2587300 1324
1325 } else if (!strncmp(tmpstr, "reqauth", 7)) {
1326
1327 aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_AUTH);
1328
1329 } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1330
1331 aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1332
1333 } else if (!strncmp(tmpstr, "reqemail", 8)) {
1334
1335 aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1336
1337 } else if (!strncmp(tmpstr, "changepass", 8)) {
1338
1339 aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1340
1341 } else if (!strncmp(tmpstr, "setemail", 8)) {
1342
1343 aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1344
1345 } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1346 int i;
1347 i = atoi(tmpstr+8);
1348 if (i < 10000) {
1349 char *newbuf;
1350 int z;
1351
1352 newbuf = malloc(i+1);
1353 for (z = 0; z < i; z++) {
1354 newbuf[z] = (z % 10)+0x30;
1355 }
1356 newbuf[i] = '\0';
7b91722d 1357 aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf);
d2587300 1358 free(newbuf);
1359 }
1360
1361 } else {
1362
1363 dprintf("unknown command.\n");
1364 aim_add_buddy(sess, command->conn, userinfo->sn);
1365
1366 }
1367
1368 return 0;
1369}
1370
9de3ca7e 1371/*
1372 * The user-level Incoming ICBM callback.
1373 *
9de3ca7e 1374 */
397055b1 1375int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1376{
26af6789 1377 int channel;
7b91722d 1378 struct aim_userinfo_s *userinfo;
9de3ca7e 1379 va_list ap;
9de3ca7e 1380
1381 va_start(ap, command);
26af6789 1382 channel = va_arg(ap, int);
7b91722d 1383 userinfo = va_arg(ap, struct aim_userinfo_s *);
9de3ca7e 1384
26af6789 1385 /*
1386 * Channel 1: Standard Message
1387 */
040457cc 1388 if (channel == 1) {
7b91722d 1389 char *tmpstr;
1390 struct aim_incomingim_ch1_args *args;
9d83220c 1391 int clienttype = AIM_CLIENTTYPE_UNKNOWN;
7a449b5d 1392 char realmsg[8192+1] = {""};
7b91722d 1393
1394 args = va_arg(ap, struct aim_incomingim_ch1_args *);
040457cc 1395 va_end(ap);
1396
7b91722d 1397 clienttype = aim_fingerprintclient(args->fingerprint, args->finlen);
9d83220c 1398
37ee990e 1399 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
9d83220c 1400 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
37ee990e 1401 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1402 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
a15d82b1 1403 printuserflags(userinfo->flags);
37ee990e 1404 dinlineprintf("\n");
a15d82b1 1405
37ee990e 1406 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1407 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1408 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1409 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
040457cc 1410
37ee990e 1411 dprintf("faimtest: icbm: icbmflags = ");
7b91722d 1412 if (args->icbmflags & AIM_IMFLAGS_AWAY)
37ee990e 1413 dinlineprintf("away ");
7b91722d 1414 if (args->icbmflags & AIM_IMFLAGS_ACK)
37ee990e 1415 dinlineprintf("ackrequest ");
7b91722d 1416 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1417 dinlineprintf("buddyreq ");
1418 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1419 dinlineprintf("hasicon ");
37ee990e 1420 dinlineprintf("\n");
040457cc 1421
7b91722d 1422 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
1423
7a449b5d 1424 /*
1425 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1426 * characters with their equivelent HTML entity.
1427 */
1428 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1429 int i;
1430
1431 for (i = 0; i < args->msglen; i += 2) {
1432 unsigned short uni;
1433
1434 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1435
1436 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1437
1438 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg),
1439 "%c", uni);
1440
1441 } else { /* something else, do UNICODE entity */
1442
1443 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg),
1444 "&#%04x;", uni);
1445
1446 }
1447
1448 }
1449
1450 } else {
1451
1452 /*
1453 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is no
1454 * need to do anything special here. Most terminals/whatever will
1455 * be able to display such characters unmodified.
1456 *
1457 * Beware that PC-ASCII 128 through 159 are _not_ actually defined in
1458 * ASCII or ISO 8859-1, and you should send them as UNICODE. WinAIM
1459 * will send these characters in a UNICODE message, so you need
1460 * to do so as well.
1461 *
1462 * You may not think it necessary to handle UNICODE messages. You're
1463 * probably wrong. For one thing, Microsoft "Smart Quotes" will
1464 * be sent by WinAIM as UNICODE (not HTML UNICODE, but real UNICODE).
1465 * If you don't parse UNICODE at all, your users will get a blank
1466 * message instead of the message containing Smart Quotes.
1467 *
1468 */
1469 strncpy(realmsg, args->msg, sizeof(realmsg));
1470 }
1471
1472 dvprintf("faimtest: icbm: message: %s\n", realmsg);
7b91722d 1473
1474 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1475 aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1476
7a449b5d 1477 if (realmsg) {
b69540e3 1478 int i = 0;
1479
7a449b5d 1480 while (realmsg[i] == '<') {
1481 if (realmsg[i] == '<') {
1482 while (realmsg[i] != '>')
b69540e3 1483 i++;
1484 i++;
1485 }
1486 }
7a449b5d 1487 tmpstr = realmsg+i;
b69540e3 1488
d2587300 1489 faimtest_handlecmd(sess, command, userinfo, tmpstr);
1490
040457cc 1491 }
1492 }
1493 /*
1494 * Channel 2: Rendevous Request
1495 */
1496 else if (channel == 2) {
7b91722d 1497 struct aim_incomingim_ch2_args *args;
040457cc 1498
7b91722d 1499 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1500 va_end(ap);
1501
1502 switch (args->reqclass) {
b69540e3 1503 case AIM_CAPS_VOICE: {
9de3ca7e 1504
37ee990e 1505 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1506 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1507 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
a15d82b1 1508 printuserflags(userinfo->flags);
37ee990e 1509 dinlineprintf("\n");
a15d82b1 1510
040457cc 1511 /* we dont get membersince on chat invites! */
37ee990e 1512 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1513 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
26af6789 1514
040457cc 1515 break;
1516 }
b69540e3 1517 case AIM_CAPS_GETFILE: {
871e2fd0 1518 struct aim_conn_t *newconn;
37ee990e 1519 struct aim_fileheader_t *fh;
871e2fd0 1520
7b91722d 1521 dvprintf("faimtest: get file request from %s (at %s) %x\n", userinfo->sn, args->info.getfile.ip, args->reqclass);
646c6b52 1522
7b91722d 1523 fh = aim_getlisting(sess, listingfile);
871e2fd0 1524
7b91722d 1525 newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, args->info.getfile.cookie, args->info.getfile.ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass);
871e2fd0 1526
7b91722d 1527 if ( (!newconn) || (newconn->fd == -1) ) {
37ee990e 1528 dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n");
646c6b52 1529 if(newconn)
1530 aim_conn_kill(sess, &newconn);
871e2fd0 1531 break;
1532 }
37ee990e 1533
1534 free(fh);
1535
1536 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
871e2fd0 1537 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0);
1538 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1539 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);
37ee990e 1540
871e2fd0 1541 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);
1542
37ee990e 1543 dprintf("faimtest: getfile connect succeeded, handlers added.\n");
871e2fd0 1544
040457cc 1545 break;
1546 }
b69540e3 1547 case AIM_CAPS_SENDFILE: {
37ee990e 1548 dprintf("faimtest: send file!\n");
b69540e3 1549 break;
1550 }
1551 case AIM_CAPS_CHAT: {
26af6789 1552
37ee990e 1553 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1554 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1555 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
a15d82b1 1556 printuserflags(userinfo->flags);
37ee990e 1557 dinlineprintf("\n");
a15d82b1 1558
040457cc 1559 /* we dont get membersince on chat invites! */
37ee990e 1560 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1561 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
26af6789 1562
7b91722d 1563 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1564 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1565 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1566 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1567 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1568 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1569 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
1570
040457cc 1571 /*
1572 * Automatically join room...
1573 */
7b91722d 1574 aim_chat_join(sess, command->conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name);
040457cc 1575 break;
1576 }
7392c79f 1577 case AIM_CAPS_IMIMAGE: {
7392c79f 1578 struct aim_conn_t *newconn;
1579
37ee990e 1580 dprintf("faimtest: icbm: rendezvous imimage\n");
7392c79f 1581
7b91722d 1582 dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, args->info.directim->ip);
7392c79f 1583
7b91722d 1584 newconn = aim_directim_connect(sess, command->conn, args->info.directim);
646c6b52 1585
1586 if ( (!newconn) || (newconn->fd == -1) ) {
37ee990e 1587 dprintf("faimtest: icbm: imimage: could not connect\n");
646c6b52 1588
1589 if (newconn)
1590 aim_conn_kill(sess, &newconn);
1591
7392c79f 1592 break;
1593 }
646c6b52 1594
7392c79f 1595 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1596 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1597 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1598
37ee990e 1599 dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn);
7392c79f 1600
3b101546 1601 aim_send_im_direct(sess, newconn, "goodday");
1602
7392c79f 1603 break;
1604 }
7b91722d 1605 case AIM_CAPS_BUDDYICON: {
1606
1607 dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, args->info.icon.length);
1608 break;
1609 }
040457cc 1610 default:
7b91722d 1611 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
040457cc 1612 } /* switch */
1613 } else
37ee990e 1614 dvprintf("faimtest does not support channels > 2 (chan = %02x)\n", channel);
7b91722d 1615
37ee990e 1616 dprintf("faimtest: icbm: done with ICBM handling\n");
9de3ca7e 1617
1618 return 1;
1619}
1620
7392c79f 1621int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1622{
1623 va_list ap;
1624 struct aim_directim_priv *priv;
646c6b52 1625 struct aim_conn_t *newconn, *listenerconn;
7392c79f 1626
e7fb57f5 1627 va_start(ap, command);
7392c79f 1628 newconn = va_arg(ap, struct aim_conn_t *);
646c6b52 1629 listenerconn = va_arg(ap, struct aim_conn_t *);
7392c79f 1630 va_end(ap);
1631
646c6b52 1632 aim_conn_close(listenerconn);
1633 aim_conn_kill(sess, &listenerconn);
1634
7392c79f 1635 priv = (struct aim_directim_priv *)newconn->priv;
1636
37ee990e 1637 dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip);
7392c79f 1638
1639 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1640 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1641 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1642
1643 aim_send_im_direct(sess, newconn, "goodday");
1644
37ee990e 1645 dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn);
7392c79f 1646
1647 return 1;
1648}
7392c79f 1649
1650int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1651{
1652 va_list ap;
1653 struct aim_directim_priv *priv;
1654
e7fb57f5 1655 va_start(ap, command);
7392c79f 1656 priv = va_arg(ap, struct aim_directim_priv *);
1657
1658 va_end(ap);
1659
37ee990e 1660 dprintf("faimtest: directim_connect\n");
7392c79f 1661
1662 return 1;
1663}
1664
1665int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1666{
1667 va_list ap;
9e8c4225 1668 char *msg = NULL;
7392c79f 1669 struct aim_conn_t *conn;
9e8c4225 1670 struct aim_directim_priv *priv;
7392c79f 1671
e7fb57f5 1672 va_start(ap, command);
7392c79f 1673 conn = va_arg(ap, struct aim_conn_t *);
7392c79f 1674 msg = va_arg(ap, char *);
1675 va_end(ap);
1676
9e8c4225 1677 if(!(priv = conn->priv)) {
1678 dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd);
1679 return -1;
1680 }
1681
1682 dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg);
7392c79f 1683 if (!strncmp(msg, "sendmsg", 7)) {
1684 int i;
1685 i = atoi(msg+8);
1686 if (i < 10000) {
1687 char *newbuf;
1688 int z;
1689
1690 newbuf = malloc(i+1);
1691 for (z = 0; z < i; z++) {
1692 newbuf[z] = (z % 10)+0x30;
1693 }
1694 newbuf[i] = '\0';
1695 aim_send_im_direct(sess, conn, newbuf);
1696 free(newbuf);
1697 }
1698 } else if (!strncmp(msg, "goodday", 7)) {
1699 aim_send_im_direct(sess, conn, "Good day to you, too");
1700 } else {
1701 char newmsg[1024];
1702 snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1703 aim_send_im_direct(sess, conn, newmsg);
1704 }
1705 return 1;
1706}
1707
1708int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1709{
871e2fd0 1710 va_list ap;
1711 struct aim_conn_t *conn;
1712 char *sn;
1713
e7fb57f5 1714 va_start(ap, command);
871e2fd0 1715 conn = va_arg(ap, struct aim_conn_t *);
1716 sn = va_arg(ap, char *);
1717 va_end(ap);
1718
37ee990e 1719 dvprintf("faimtest: directim: disconnected from %s\n", sn);
3b101546 1720
1721 aim_conn_kill(sess, &conn);
7392c79f 1722 return 1;
1723}
1724
1725int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1726{
1727 va_list ap;
9e8c4225 1728 struct aim_conn_t *conn;
1729 struct aim_directim_priv *priv;
1730
e7fb57f5 1731 va_start(ap, command);
9e8c4225 1732 conn = va_arg(ap, struct aim_conn_t *);
7392c79f 1733 va_end(ap);
9e8c4225 1734
1735 if(!(priv = (struct aim_directim_priv *)conn->priv)) {
1736 dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd);
1737 return -1;
1738 }
7392c79f 1739
9e8c4225 1740 dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
7392c79f 1741 return 1;
1742}
1743
64c78745 1744int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1745{
64c78745 1746 unsigned short change = 0;
1747 int perms, type, length, str;
1748 char *val;
1749 va_list ap;
9de3ca7e 1750
64c78745 1751 va_start(ap, command);
1752 perms = va_arg(ap, int);
1753 type = va_arg(ap, int);
1754 length = va_arg(ap, int);
1755 val = va_arg(ap, char *);
1756 str = va_arg(ap, int);
1757 va_end(ap);
9de3ca7e 1758
64c78745 1759 if (aimutil_get16(command->data+2) == 0x0005)
1760 change = 1;
1761
1762 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
9de3ca7e 1763
9de3ca7e 1764 return 1;
1765}
1766
397055b1 1767int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1768{
1769 struct aim_userinfo_s *userinfo;
1770
1771 va_list ap;
1772 va_start(ap, command);
1773 userinfo = va_arg(ap, struct aim_userinfo_s *);
1774 va_end(ap);
1775
37ee990e 1776 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
ee49b735 1777 time(NULL),
a15d82b1 1778 userinfo->sn, userinfo->flags,
1779 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1780 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1781 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1782 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1783 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1784 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1785 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1786 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
b69540e3 1787 userinfo->capabilities);
9de3ca7e 1788 return 1;
1789}
1790
397055b1 1791int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1792{
69e7980c 1793 struct aim_userinfo_s *userinfo;
1794
397055b1 1795 va_list ap;
397055b1 1796 va_start(ap, command);
69e7980c 1797 userinfo = va_arg(ap, struct aim_userinfo_s *);
397055b1 1798 va_end(ap);
9de3ca7e 1799
69e7980c 1800 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1801 time(NULL),
1802 userinfo->sn, userinfo->flags,
1803 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1804 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1805 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1806 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1807 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1808 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1809 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1810 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1811 userinfo->capabilities);
9de3ca7e 1812 return 1;
1813}
1814
01b59e1e 1815int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1816{
355229fe 1817 static char *codes[] = {
1818 "Unknown",
1819 "Mandatory upgrade",
1820 "Advisory upgrade",
1821 "System bulletin",
1822 "Top o' the world!"
1823 };
1824 static int codeslen = 5;
1825 char *msg;
1826 unsigned short id;
1827 va_list ap;
96f8b1ed 1828
355229fe 1829 va_start(ap, command);
1830 id = va_arg(ap, int);
1831 msg = va_arg(ap, char *);
1832 va_end(ap);
ee49b735 1833
355229fe 1834 dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown");
e80a0fa9 1835
355229fe 1836 return 1;
96f8b1ed 1837}
1838
1449ad2b 1839int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1840{
355229fe 1841 va_list ap;
1842 unsigned short reason;
1449ad2b 1843
355229fe 1844 va_start(ap, command);
1845 reason = va_arg(ap, int);
1846 va_end(ap);
1449ad2b 1847
355229fe 1848 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1849
1850 return 1;
1449ad2b 1851}
1852
96f8b1ed 1853int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1854{
355229fe 1855 va_list ap;
1856 char *destsn;
1857 unsigned short reason;
96f8b1ed 1858
355229fe 1859 va_start(ap, command);
1860 reason = va_arg(ap, int);
1861 destsn = va_arg(ap, char *);
1862 va_end(ap);
96f8b1ed 1863
355229fe 1864 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1865
1866 return 1;
96f8b1ed 1867}
1868
1869int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1870{
355229fe 1871 va_list ap;
1872 char *destsn;
1873 unsigned short reason;
96f8b1ed 1874
355229fe 1875 va_start(ap, command);
1876 reason = va_arg(ap, int);
1877 destsn = va_arg(ap, char *);
1878 va_end(ap);
01b59e1e 1879
355229fe 1880 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1881
1882 return 1;
01b59e1e 1883}
9de3ca7e 1884
1885/*
96f8b1ed 1886 * Handles callbacks for AIM_CB_MISSED_CALL.
9de3ca7e 1887 */
397055b1 1888int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
9de3ca7e 1889{
355229fe 1890 static char *missedreasons[] = {
1891 "Invalid (0)",
1892 "Message too large",
1893 "Rate exceeded",
1894 "Evil Sender",
1895 "Evil Receiver"
1896 };
1897 static int missedreasonslen = 5;
9de3ca7e 1898
355229fe 1899 va_list ap;
1900 unsigned short chan, nummissed, reason;
1901 struct aim_userinfo_s *userinfo;
9de3ca7e 1902
355229fe 1903 va_start(ap, command);
1904 chan = va_arg(ap, int);
1905 userinfo = va_arg(ap, struct aim_userinfo_s *);
1906 nummissed = va_arg(ap, int);
1907 reason = va_arg(ap, int);
1908 va_end(ap);
1909
1910 dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1911
1912 return 1;
9de3ca7e 1913}
1914
01b59e1e 1915int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1916{
355229fe 1917 struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
1918 char *key;
1919 va_list ap;
9de3ca7e 1920
355229fe 1921 va_start(ap, command);
1922 key = va_arg(ap, char *);
1923 va_end(ap);
1924
1925 aim_send_login(sess, command->conn, screenname, password, &info, key);
1926
1927 return 1;
01b59e1e 1928}
0c20631f 1929
1930int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1931{
355229fe 1932 va_list ap;
1933 struct aim_userinfo_s *userinfo;
1934 int count = 0, i = 0;
0c20631f 1935
355229fe 1936 va_start(ap, command);
1937 count = va_arg(ap, int);
1938 userinfo = va_arg(ap, struct aim_userinfo_s *);
1939 va_end(ap);
0c20631f 1940
355229fe 1941 dvprintf("faimtest: chat: %s: New occupants have joined:\n", (char *)command->conn->priv);
1942 while (i < count)
1943 dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1944
1945 return 1;
0c20631f 1946}
1947
1948int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1949{
355229fe 1950 va_list ap;
1951 struct aim_userinfo_s *userinfo;
1952 int count = 0, i = 0;
0c20631f 1953
355229fe 1954 va_start(ap, command);
1955 count = va_arg(ap, int);
1956 userinfo = va_arg(ap, struct aim_userinfo_s *);
1957 va_end(ap);
37ee990e 1958
355229fe 1959 dvprintf("faimtest: chat: %s: Some occupants have left:\n", (char *)command->conn->priv);
0c20631f 1960
355229fe 1961 for (i = 0; i < count; )
1962 dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1963
1964 return 1;
0c20631f 1965}
1966
1967int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1968{
355229fe 1969 va_list ap;
1970 struct aim_userinfo_s *userinfo;
1971 struct aim_chat_roominfo *roominfo;
1972 char *roomname;
1973 int usercount,i;
1974 char *roomdesc;
1975 unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1976 unsigned long creationtime;
1977
1978 va_start(ap, command);
1979 roominfo = va_arg(ap, struct aim_chat_roominfo *);
1980 roomname = va_arg(ap, char *);
1981 usercount= va_arg(ap, int);
1982 userinfo = va_arg(ap, struct aim_userinfo_s *);
1983 roomdesc = va_arg(ap, char *);
1984 unknown_c9 = va_arg(ap, int);
1985 creationtime = va_arg(ap, unsigned long);
1986 maxmsglen = va_arg(ap, int);
1987 unknown_d2 = va_arg(ap, int);
1988 unknown_d5 = va_arg(ap, int);
1989 va_end(ap);
1990
1991 dvprintf("faimtest: chat: %s: info update:\n", (char *)command->conn->priv);
1992 dvprintf("faimtest: chat: %s: \tRoominfo: {%04x, %s, %04x}\n", (char *)command->conn->priv, roominfo->exchange, roominfo->name, roominfo->instance);
1993 dvprintf("faimtest: chat: %s: \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1994 dvprintf("faimtest: chat: %s: \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1995 dvprintf("faimtest: chat: %s: \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1996
1997 for (i = 0; i < usercount; )
1998 dvprintf("faimtest: chat: %s: \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1999
2000 dvprintf("faimtest: chat: %s: \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
2001 dvprintf("faimtest: chat: %s: \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
2002 dvprintf("faimtest: chat: %s: \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
2003 dvprintf("faimtest: chat: %s: \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
2004 dvprintf("faimtest: chat: %s: \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
2005
2006 return 1;
0c20631f 2007}
2008
2009int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2010{
355229fe 2011 va_list ap;
2012 struct aim_userinfo_s *userinfo;
2013 char *msg;
2014 char tmpbuf[1152];
2015
2016 va_start(ap, command);
2017 userinfo = va_arg(ap, struct aim_userinfo_s *);
2018 msg = va_arg(ap, char *);
2019 va_end(ap);
2020
2021 dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
2022
2023 /*
2024 * Do an echo for testing purposes. But not for ourselves ("oops!")
2025 */
2026 if (strcmp(userinfo->sn, sess->sn) != 0) {
2027 sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
2028 aim_chat_send_im(sess, command->conn, 0, tmpbuf, strlen(tmpbuf));
2029 }
0c20631f 2030
355229fe 2031 return 1;
0c20631f 2032}
2033
2034int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2035{
e7fb57f5 2036 unsigned short type;
0c20631f 2037 va_list ap;
2038
e7fb57f5 2039 va_start(ap, command);
2040 type = va_arg(ap, int);
0c20631f 2041
efe9513b 2042 switch(type) {
2043 case 0x0002: {
2044 int maxrooms;
2045 struct aim_chat_exchangeinfo *exchanges;
2046 int exchangecount,i = 0;
2047
e7fb57f5 2048 maxrooms = va_arg(ap, int);
efe9513b 2049 exchangecount = va_arg(ap, int);
2050 exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2051 va_end(ap);
2052
37ee990e 2053 dprintf("faimtest: chat info: Chat Rights:\n");
2054 dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
efe9513b 2055
37ee990e 2056 dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
2057 for (i = 0; i < exchangecount; i++) {
2058 dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n",
2059 exchanges[i].number,
2060 exchanges[i].name,
2061 exchanges[i].charset1,
2062 exchanges[i].lang1);
0c20631f 2063 }
efe9513b 2064
2065 }
2066 break;
2067 case 0x0008: {
2068 char *fqcn, *name, *ck;
9dbda50b 2069 unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
efe9513b 2070 unsigned char createperms;
2071 unsigned long createtime;
2072
2073 fqcn = va_arg(ap, char *);
e7fb57f5 2074 instance = va_arg(ap, int);
9dbda50b 2075 exchange = va_arg(ap, int);
e7fb57f5 2076 flags = va_arg(ap, int);
efe9513b 2077 createtime = va_arg(ap, unsigned long);
e7fb57f5 2078 maxmsglen = va_arg(ap, int);
2079 maxoccupancy = va_arg(ap, int);
2080 createperms = va_arg(ap, int);
2081 unknown = va_arg(ap, int);
efe9513b 2082 name = va_arg(ap, char *);
2083 ck = va_arg(ap, char *);
2084 va_end(ap);
2085
646c6b52 2086 dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange);
efe9513b 2087 }
2088 break;
2089 default:
2090 va_end(ap);
37ee990e 2091 dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
efe9513b 2092 }
0c20631f 2093 return 1;
2094}
5e02cf44 2095
2096int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2097{
355229fe 2098 va_list ap;
2099 unsigned short code;
2100 char *msg = NULL;
5e02cf44 2101
355229fe 2102 va_start(ap, command);
2103 code = va_arg(ap, int);
2104 msg = va_arg(ap, char *);
2105 va_end(ap);
5e02cf44 2106
355229fe 2107 dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
2108 aim_conn_kill(sess, &command->conn); /* this will break the main loop */
5e02cf44 2109
355229fe 2110 connected = 0;
d32954e7 2111
355229fe 2112 return 1;
5e02cf44 2113}
e5012450 2114
2115int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2116{
355229fe 2117 dprintf("faimtest: connecting to an aimdebugd!\n");
e5012450 2118
355229fe 2119 /* convert the authorizer connection to a BOS connection */
2120 command->conn->type = AIM_CONN_TYPE_BOS;
e5012450 2121
355229fe 2122 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
e5012450 2123
355229fe 2124 /* tell the aimddebugd we're ready */
2125 aim_debugconn_sendconnect(sess, command->conn);
e5012450 2126
355229fe 2127 /* go right into main loop (don't open a BOS connection, etc) */
2128 return 1;
e5012450 2129}
1a8c261b 2130
2131/*
646c6b52 2132 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1a8c261b 2133 */
2134int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2135{
355229fe 2136 va_list ap;
2137 unsigned short type;
2138 char *sn = NULL;
1a8c261b 2139
355229fe 2140 va_start(ap, command);
2141 type = va_arg(ap, int);
2142 sn = va_arg(ap, char *);
2143 va_end(ap);
1a8c261b 2144
355229fe 2145 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1a8c261b 2146
355229fe 2147 return 1;
1a8c261b 2148}
2149
871e2fd0 2150int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
2151{
355229fe 2152 va_list ap;
2153 struct aim_conn_t *oftconn;
2154 struct aim_fileheader_t *fh;
2155 char *cookie;
871e2fd0 2156
355229fe 2157 va_start(ap, command);
2158 oftconn = va_arg(ap, struct aim_conn_t *);
2159 fh = va_arg(ap, struct aim_fileheader_t *);
2160 cookie = va_arg(ap, char *);
2161 va_end(ap);
871e2fd0 2162
355229fe 2163 dvprintf("faimtest: request for file %s.\n", fh->name);
871e2fd0 2164
355229fe 2165 return 1;
871e2fd0 2166}
2167
2168
2169int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2170{
2171 va_list ap;
2172 struct aim_conn_t *oftconn;
2173 struct aim_fileheader_t *fh;
2174 char *path, *cookie;
646c6b52 2175 int pos, bufpos = 0, bufsize = 2048, i;
2176 char *buf;
871e2fd0 2177
2178 FILE *file;
2179
e7fb57f5 2180 va_start(ap, command);
871e2fd0 2181 oftconn = va_arg(ap, struct aim_conn_t *);
2182 fh = va_arg(ap, struct aim_fileheader_t *);
2183 cookie = va_arg(ap, char *);
2184 va_end(ap);
2185
37ee990e 2186 dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
871e2fd0 2187
646c6b52 2188 if(!(buf = malloc(2048)))
2189 return -1;
2190
37ee990e 2191 if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
2192 dperror("calloc");
2193 dprintf("faimtest: error in calloc of path\n");
871e2fd0 2194 return 0; /* XXX: no idea what winaim expects here =) */
2195 }
2196
37ee990e 2197 snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
871e2fd0 2198
2199
2200 if( (file = fopen(path, "r")) == NULL) {
37ee990e 2201 dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
871e2fd0 2202 return 0;
2203 }
646c6b52 2204
2205 /*
2206 * This is a mess. Remember that faimtest is demonstration code
2207 * only and for the sake of the gods, don't use this code in any
2208 * of your clients. --mid
2209 */
37ee990e 2210 for(pos = 0; pos < fh->size; pos++) {
2211 bufpos = pos % bufsize;
2212
2213 if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2214 if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2215 dperror("faim: getfile_send: write1");
2216 dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2217 free(buf);
2218 return -1;
2219 }
2220 }
2221 if( (buf[bufpos] = fgetc(file)) == EOF) {
2222 if(pos != fh->size) {
2223 dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2224 free(buf);
2225 return -1;
2226 }
2227 }
2228 dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
2229 }
871e2fd0 2230
37ee990e 2231 if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2232 dperror("faim: getfile_send: write2");
2233 dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2234 free(buf);
2235 return -1;
871e2fd0 2236 }
2237
646c6b52 2238 free(buf);
871e2fd0 2239 free(fh);
2240 return 1;
2241}
2242
2243int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2244{
2245 va_list ap;
2246 struct aim_conn_t *conn;
2247 struct aim_fileheader_t *fh;
2248
e7fb57f5 2249 va_start(ap, command);
871e2fd0 2250 conn = va_arg(ap, struct aim_conn_t *);
2251 fh = va_arg(ap, struct aim_fileheader_t *);
2252 va_end(ap);
2253
37ee990e 2254 dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
871e2fd0 2255
37ee990e 2256 aim_conn_close(conn);
2257 aim_conn_kill(sess, &conn);
871e2fd0 2258 return 1;
2259}
2260
2261int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2262{
2263 va_list ap;
2264 struct aim_conn_t *conn;
2265 char *sn;
2266
e7fb57f5 2267 va_start(ap, command);
871e2fd0 2268 conn = va_arg(ap, struct aim_conn_t *);
2269 sn = va_arg(ap, char *);
2270 va_end(ap);
2271
2272 aim_conn_kill(sess, &conn);
2273
37ee990e 2274 dvprintf("faimtest: getfile: disconnected from %s\n", sn);
2275 return 1;
2276}
355229fe 2277
37ee990e 2278int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2279{
2280 va_list ap;
646c6b52 2281 struct aim_conn_t *conn, *listenerconn;
37ee990e 2282 struct aim_filetransfer_priv *priv;
2283
2284 va_start(ap, command);
2285 conn = va_arg(ap, struct aim_conn_t *);
646c6b52 2286 listenerconn = va_arg(ap, struct aim_conn_t *);
37ee990e 2287 va_end(ap);
2288
646c6b52 2289 aim_conn_close(listenerconn);
2290 aim_conn_kill(sess, &listenerconn);
2291
37ee990e 2292 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0);
2293 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2294 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);
2295 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);
2296 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2297 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
646c6b52 2298 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2299 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
37ee990e 2300
2301 priv = (struct aim_filetransfer_priv *)conn->priv;
2302
646c6b52 2303 dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd);
871e2fd0 2304 return 1;
2305}
871e2fd0 2306
37ee990e 2307int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2308{
2309 va_list ap;
2310 struct aim_conn_t *conn;
2311 char *listing;
2312 struct aim_filetransfer_priv *ft;
2313 char *filename, *nameend, *sizec;
2314 int filesize, namelen;
2315
2316 va_start(ap, command);
2317 conn = va_arg(ap, struct aim_conn_t *);
2318 ft = va_arg(ap, struct aim_filetransfer_priv *);
2319 listing = va_arg(ap, char *);
2320 va_end(ap);
2321
2322 dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
2323
2324 nameend = strstr(listing+0x1a, "\r");
2325
2326 namelen = nameend - (listing + 0x1a);
2327
2328 filename = malloc(namelen + 1);
2329 strncpy(filename, listing+0x1a, namelen);
2330 filename[namelen] = 0x00;
2331
2332 sizec = malloc(8+1);
2333 memcpy(sizec, listing + 0x11, 8);
2334 sizec[8] = 0x00;
2335
2336 filesize = strtol(sizec, (char **)NULL, 10);
2337
2338 dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
2339
2340 aim_oft_getfile_request(sess, conn, filename, filesize);
2341
2342 free(filename);
2343 free(sizec);
2344
2345 return 0;
2346}
2347
2348int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2349{
2350 va_list ap;
2351 struct aim_conn_t *oftconn;
2352 struct aim_fileheader_t *fh;
646c6b52 2353 int pos, bufpos = 0, bufsize = 2048, i;
2354 char *buf;
37ee990e 2355
2356 va_start(ap, command);
2357 oftconn = va_arg(ap, struct aim_conn_t *);
2358 fh = va_arg(ap, struct aim_fileheader_t *);
2359 va_end(ap);
2360
2361 dvprintf("faimtest: sending listing of size %ld\n", fh->size);
2362
646c6b52 2363 if(!(buf = malloc(2048)))
2364 return -1;
2365
37ee990e 2366 for(pos = 0; pos < fh->size; pos++) {
2367 bufpos = pos % bufsize;
2368
2369 if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2370 if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2371 dperror("faim: getfile_send: write1");
2372 dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2373 free(buf);
2374 return -1;
2375 }
2376 }
2377 if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
2378 if(pos != fh->size) {
2379 dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2380 free(buf);
2381 return -1;
2382 }
2383 }
2384 }
2385
2386 if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2387 dperror("faim: getfile_send: write2");
2388 dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2389 free(buf);
2390 return -1;
2391 }
2392
2393 dprintf("faimtest: sent listing\n");
646c6b52 2394 free(buf);
37ee990e 2395 return 0;
2396}
2397
646c6b52 2398int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...)
37ee990e 2399{
2400 va_list ap;
2401 struct aim_conn_t *conn;
2402 struct aim_filetransfer_priv *ft;
2403 unsigned char data;
2404 int pos;
2405
2406 va_start(ap, command);
2407 conn = va_arg(ap, struct aim_conn_t *);
2408 ft = va_arg(ap, struct aim_filetransfer_priv *);
2409 va_end(ap);
2410
2411 dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
2412
2413 for(pos = 0; pos < ft->fh.size; pos++) {
2414 read(conn->fd, &data, 1);
646c6b52 2415 printf("%c(%02x) ", data, data);
37ee990e 2416 }
2417
646c6b52 2418 printf("\n");
37ee990e 2419
37ee990e 2420 aim_oft_getfile_end(sess, conn);
2421
2422 return 0;
2423}
646c6b52 2424
2425int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2426{
2427 va_list ap;
2428 struct aim_conn_t *conn;
2429
2430 va_start(ap, command);
2431 conn = va_arg(ap, struct aim_conn_t *);
2432 va_end(ap);
2433
2434 aim_conn_close(conn);
2435 aim_conn_kill(sess, &conn);
2436 return 0;
2437}
2438
2439
1a8c261b 2440int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2441{
275a2ff8 2442 static char *codes[5] = {"invalid",
2443 "change",
2444 "warning",
2445 "limit",
2446 "limit cleared"};
1a8c261b 2447 va_list ap;
275a2ff8 2448 int code;
d6c9fcf0 2449 unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
275a2ff8 2450 unsigned long currentavg, maxavg;
2451
1a8c261b 2452 va_start(ap, command);
275a2ff8 2453
2454 /* See code explanations below */
2455 code = va_arg(ap, int);
2456
2457 /*
d6c9fcf0 2458 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
275a2ff8 2459 */
d6c9fcf0 2460 rateclass = va_arg(ap, unsigned long);
275a2ff8 2461
2462 /*
2463 * Not sure what this is exactly. I think its the temporal
2464 * relation factor (ie, how to make the rest of the numbers
2465 * make sense in the real world).
2466 */
2467 windowsize = va_arg(ap, unsigned long);
2468
2469 /* Explained below */
2470 clear = va_arg(ap, unsigned long);
2471 alert = va_arg(ap, unsigned long);
2472 limit = va_arg(ap, unsigned long);
2473 disconnect = va_arg(ap, unsigned long);
2474 currentavg = va_arg(ap, unsigned long);
2475 maxavg = va_arg(ap, unsigned long);
2476
1a8c261b 2477 va_end(ap);
2478
275a2ff8 2479
37ee990e 2480 dvprintf("faimtest: rate %s (rate class 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
275a2ff8 2481 (code < 5)?codes[code]:"invalid",
d6c9fcf0 2482 rateclass,
275a2ff8 2483 currentavg, maxavg,
2484 alert, clear,
2485 limit, disconnect,
2486 windowsize);
2487
2488 if (code == AIM_RATE_CODE_CHANGE) {
2489 /*
2490 * Not real sure when these get sent.
2491 */
2492 if (currentavg >= clear)
2493 aim_conn_setlatency(command->conn, 0);
2494
2495 } else if (code == AIM_RATE_CODE_WARNING) {
2496 /*
2497 * We start getting WARNINGs the first time we go below the 'alert'
2498 * limit (currentavg < alert) and they stop when either we pause
2499 * long enough for currentavg to go above 'clear', or until we
2500 * flood it bad enough to go below 'limit' (and start getting
2501 * LIMITs instead) or even further and go below 'disconnect' and
2502 * get disconnected completely (and won't be able to login right
2503 * away either).
2504 */
2505 aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */
2506
2507 } else if (code == AIM_RATE_CODE_LIMIT) {
2508 /*
2509 * When we hit LIMIT, messages will start getting dropped.
2510 */
2511 aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */
2512
2513 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2514 /*
2515 * The limit is cleared when curavg goes above 'clear'.
2516 */
2517 aim_conn_setlatency(command->conn, 0);
2518 }
1a8c261b 2519
871e2fd0 2520 return 1;
78b3fb13 2521}
98c88242 2522
2523int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2524{
355229fe 2525 va_list ap;
2526 int newevil;
2527 struct aim_userinfo_s *userinfo;
98c88242 2528
355229fe 2529 va_start(ap, command);
2530 newevil = va_arg(ap, int);
2531 userinfo = va_arg(ap, struct aim_userinfo_s *);
2532 va_end(ap);
98c88242 2533
355229fe 2534 /*
2535 * Evil Notifications that are lacking userinfo->sn are anon-warns
2536 * if they are an evil increases, but are not warnings at all if its
2537 * a decrease (its the natural backoff happening).
2538 *
2539 * newevil is passed as an int representing the new evil value times
2540 * ten.
2541 */
2542 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
37ee990e 2543
355229fe 2544 return 1;
37ee990e 2545}
2546
2547int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2548{
355229fe 2549 va_list ap;
2550 char *address, *SNs;
2551 int i, num;
37ee990e 2552
355229fe 2553 va_start(ap, command);
2554 address = va_arg(ap, char *);
2555 num = va_arg(ap, int);
2556 SNs = va_arg(ap, char *);
2557 va_end(ap);
37ee990e 2558
355229fe 2559 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
37ee990e 2560
355229fe 2561 for(i = 0; i < num; i++)
2562 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2563 dinlineprintf("\n");
2564
2565 return 1;
37ee990e 2566}
2567
2568int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2569{
355229fe 2570 va_list ap;
2571 char *address;
37ee990e 2572
355229fe 2573 va_start(ap, command);
2574 address = va_arg(ap, char *);
2575 va_end(ap);
98c88242 2576
355229fe 2577 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2578
2579 return 1;
78b3fb13 2580}
This page took 5.841543 seconds and 5 git commands to generate.