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