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