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