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