]> andersk Git - libfaim.git/blame_incremental - utils/faimtest/faimtest.c
- Wed Jun 27 00:13:20 EDT 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 int);
556 defflags = va_arg(ap, unsigned long);
557 maxicbmlen = va_arg(ap, unsigned int);
558 maxsenderwarn = va_arg(ap, unsigned int);
559 maxrecverwarn = va_arg(ap, unsigned int);
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 char realmsg[8192+1] = {""};
1377
1378 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1379 va_end(ap);
1380
1381 clienttype = aim_fingerprintclient(args->fingerprint, args->finlen);
1382
1383 dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1384 dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1385 dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1386 dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1387 printuserflags(userinfo->flags);
1388 dinlineprintf("\n");
1389
1390 dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1391 dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1392 dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1393 dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1394
1395 dprintf("faimtest: icbm: icbmflags = ");
1396 if (args->icbmflags & AIM_IMFLAGS_AWAY)
1397 dinlineprintf("away ");
1398 if (args->icbmflags & AIM_IMFLAGS_ACK)
1399 dinlineprintf("ackrequest ");
1400 if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)
1401 dinlineprintf("buddyreq ");
1402 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1403 dinlineprintf("hasicon ");
1404 dinlineprintf("\n");
1405
1406 dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2);
1407
1408 /*
1409 * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1410 * characters with their equivelent HTML entity.
1411 */
1412 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1413 int i;
1414
1415 for (i = 0; i < args->msglen; i += 2) {
1416 unsigned short uni;
1417
1418 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1419
1420 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1421
1422 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg),
1423 "%c", uni);
1424
1425 } else { /* something else, do UNICODE entity */
1426
1427 snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg),
1428 "&#%04x;", uni);
1429
1430 }
1431
1432 }
1433
1434 } else {
1435
1436 /*
1437 * For non-UNICODE encodings (ASCII and ISO 8859-1), there is no
1438 * need to do anything special here. Most terminals/whatever will
1439 * be able to display such characters unmodified.
1440 *
1441 * Beware that PC-ASCII 128 through 159 are _not_ actually defined in
1442 * ASCII or ISO 8859-1, and you should send them as UNICODE. WinAIM
1443 * will send these characters in a UNICODE message, so you need
1444 * to do so as well.
1445 *
1446 * You may not think it necessary to handle UNICODE messages. You're
1447 * probably wrong. For one thing, Microsoft "Smart Quotes" will
1448 * be sent by WinAIM as UNICODE (not HTML UNICODE, but real UNICODE).
1449 * If you don't parse UNICODE at all, your users will get a blank
1450 * message instead of the message containing Smart Quotes.
1451 *
1452 */
1453 strncpy(realmsg, args->msg, sizeof(realmsg));
1454 }
1455
1456 dvprintf("faimtest: icbm: message: %s\n", realmsg);
1457
1458 if (args->icbmflags & AIM_IMFLAGS_HASICON)
1459 aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1460
1461 if (realmsg) {
1462 int i = 0;
1463
1464 while (realmsg[i] == '<') {
1465 if (realmsg[i] == '<') {
1466 while (realmsg[i] != '>')
1467 i++;
1468 i++;
1469 }
1470 }
1471 tmpstr = realmsg+i;
1472
1473 faimtest_handlecmd(sess, command, userinfo, tmpstr);
1474
1475 }
1476 }
1477 /*
1478 * Channel 2: Rendevous Request
1479 */
1480 else if (channel == 2) {
1481 struct aim_incomingim_ch2_args *args;
1482
1483 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1484 va_end(ap);
1485
1486 switch (args->reqclass) {
1487 case AIM_CAPS_VOICE: {
1488
1489 dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1490 dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1491 dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1492 printuserflags(userinfo->flags);
1493 dinlineprintf("\n");
1494
1495 /* we dont get membersince on chat invites! */
1496 dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1497 dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1498
1499 break;
1500 }
1501 case AIM_CAPS_GETFILE: {
1502 struct aim_conn_t *newconn;
1503 struct aim_fileheader_t *fh;
1504
1505 dvprintf("faimtest: get file request from %s (at %s) %x\n", userinfo->sn, args->info.getfile.ip, args->reqclass);
1506
1507 fh = aim_getlisting(sess, listingfile);
1508
1509 newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, args->info.getfile.cookie, args->info.getfile.ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass);
1510
1511 if ( (!newconn) || (newconn->fd == -1) ) {
1512 dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n");
1513 if(newconn)
1514 aim_conn_kill(sess, &newconn);
1515 break;
1516 }
1517
1518 free(fh);
1519
1520 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1521 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0);
1522 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1523 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);
1524
1525 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);
1526
1527 dprintf("faimtest: getfile connect succeeded, handlers added.\n");
1528
1529 break;
1530 }
1531 case AIM_CAPS_SENDFILE: {
1532 dprintf("faimtest: send file!\n");
1533 break;
1534 }
1535 case AIM_CAPS_CHAT: {
1536
1537 dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1538 dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1539 dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1540 printuserflags(userinfo->flags);
1541 dinlineprintf("\n");
1542
1543 /* we dont get membersince on chat invites! */
1544 dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1545 dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1546
1547 dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg);
1548 dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1549 dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding);
1550 dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang);
1551 dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1552 dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1553 dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name);
1554
1555 /*
1556 * Automatically join room...
1557 */
1558 aim_chat_join(sess, command->conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name);
1559 break;
1560 }
1561 case AIM_CAPS_IMIMAGE: {
1562 struct aim_conn_t *newconn;
1563
1564 dprintf("faimtest: icbm: rendezvous imimage\n");
1565
1566 dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, args->info.directim->ip);
1567
1568 newconn = aim_directim_connect(sess, command->conn, args->info.directim);
1569
1570 if ( (!newconn) || (newconn->fd == -1) ) {
1571 dprintf("faimtest: icbm: imimage: could not connect\n");
1572
1573 if (newconn)
1574 aim_conn_kill(sess, &newconn);
1575
1576 break;
1577 }
1578
1579 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1580 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1581 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1582
1583 dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn);
1584
1585 aim_send_im_direct(sess, newconn, "goodday");
1586
1587 break;
1588 }
1589 case AIM_CAPS_BUDDYICON: {
1590
1591 dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, args->info.icon.length);
1592 break;
1593 }
1594 default:
1595 dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass);
1596 } /* switch */
1597 } else
1598 dvprintf("faimtest does not support channels > 2 (chan = %02x)\n", channel);
1599
1600 dprintf("faimtest: icbm: done with ICBM handling\n");
1601
1602 return 1;
1603}
1604
1605int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1606{
1607 va_list ap;
1608 struct aim_directim_priv *priv;
1609 struct aim_conn_t *newconn, *listenerconn;
1610
1611 va_start(ap, command);
1612 newconn = va_arg(ap, struct aim_conn_t *);
1613 listenerconn = va_arg(ap, struct aim_conn_t *);
1614 va_end(ap);
1615
1616 aim_conn_close(listenerconn);
1617 aim_conn_kill(sess, &listenerconn);
1618
1619 priv = (struct aim_directim_priv *)newconn->priv;
1620
1621 dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip);
1622
1623 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1624 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1625 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1626
1627 aim_send_im_direct(sess, newconn, "goodday");
1628
1629 dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn);
1630
1631 return 1;
1632}
1633
1634int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1635{
1636 va_list ap;
1637 struct aim_directim_priv *priv;
1638
1639 va_start(ap, command);
1640 priv = va_arg(ap, struct aim_directim_priv *);
1641
1642 va_end(ap);
1643
1644 dprintf("faimtest: directim_connect\n");
1645
1646 return 1;
1647}
1648
1649int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1650{
1651 va_list ap;
1652 char *msg = NULL;
1653 struct aim_conn_t *conn;
1654 struct aim_directim_priv *priv;
1655
1656 va_start(ap, command);
1657 conn = va_arg(ap, struct aim_conn_t *);
1658 msg = va_arg(ap, char *);
1659 va_end(ap);
1660
1661 if(!(priv = conn->priv)) {
1662 dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd);
1663 return -1;
1664 }
1665
1666 dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg);
1667 if (!strncmp(msg, "sendmsg", 7)) {
1668 int i;
1669 i = atoi(msg+8);
1670 if (i < 10000) {
1671 char *newbuf;
1672 int z;
1673
1674 newbuf = malloc(i+1);
1675 for (z = 0; z < i; z++) {
1676 newbuf[z] = (z % 10)+0x30;
1677 }
1678 newbuf[i] = '\0';
1679 aim_send_im_direct(sess, conn, newbuf);
1680 free(newbuf);
1681 }
1682 } else if (!strncmp(msg, "goodday", 7)) {
1683 aim_send_im_direct(sess, conn, "Good day to you, too");
1684 } else {
1685 char newmsg[1024];
1686 snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1687 aim_send_im_direct(sess, conn, newmsg);
1688 }
1689 return 1;
1690}
1691
1692int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1693{
1694 va_list ap;
1695 struct aim_conn_t *conn;
1696 char *sn;
1697
1698 va_start(ap, command);
1699 conn = va_arg(ap, struct aim_conn_t *);
1700 sn = va_arg(ap, char *);
1701 va_end(ap);
1702
1703 dvprintf("faimtest: directim: disconnected from %s\n", sn);
1704
1705 aim_conn_kill(sess, &conn);
1706 return 1;
1707}
1708
1709int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1710{
1711 va_list ap;
1712 struct aim_conn_t *conn;
1713 struct aim_directim_priv *priv;
1714
1715 va_start(ap, command);
1716 conn = va_arg(ap, struct aim_conn_t *);
1717 va_end(ap);
1718
1719 if(!(priv = (struct aim_directim_priv *)conn->priv)) {
1720 dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd);
1721 return -1;
1722 }
1723
1724 dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
1725 return 1;
1726}
1727
1728int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1729{
1730 unsigned short change = 0;
1731 int perms, type, length, str;
1732 char *val;
1733 va_list ap;
1734
1735 va_start(ap, command);
1736 perms = va_arg(ap, int);
1737 type = va_arg(ap, int);
1738 length = va_arg(ap, int);
1739 val = va_arg(ap, char *);
1740 str = va_arg(ap, int);
1741 va_end(ap);
1742
1743 if (aimutil_get16(command->data+2) == 0x0005)
1744 change = 1;
1745
1746 dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1747
1748 return 1;
1749}
1750
1751int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1752{
1753 struct aim_userinfo_s *userinfo;
1754
1755 va_list ap;
1756 va_start(ap, command);
1757 userinfo = va_arg(ap, struct aim_userinfo_s *);
1758 va_end(ap);
1759
1760 dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1761 time(NULL),
1762 userinfo->sn, userinfo->flags,
1763 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1764 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1765 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1766 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1767 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1768 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1769 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1770 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1771 userinfo->capabilities);
1772 return 1;
1773}
1774
1775int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1776{
1777 struct aim_userinfo_s *userinfo;
1778
1779 va_list ap;
1780 va_start(ap, command);
1781 userinfo = va_arg(ap, struct aim_userinfo_s *);
1782 va_end(ap);
1783
1784 dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1785 time(NULL),
1786 userinfo->sn, userinfo->flags,
1787 (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1788 (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1789 (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1790 (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1791 (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1792 (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1793 (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1794 (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1795 userinfo->capabilities);
1796 return 1;
1797}
1798
1799int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1800{
1801 static char *codes[] = {
1802 "Unknown",
1803 "Mandatory upgrade",
1804 "Advisory upgrade",
1805 "System bulletin",
1806 "Top o' the world!"};
1807 static int codeslen = 5;
1808
1809 char *msg;
1810 unsigned short id;
1811 va_list ap;
1812
1813 va_start(ap, command);
1814 id = va_arg(ap, int);
1815 msg = va_arg(ap, char *);
1816 va_end(ap);
1817
1818 dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id,
1819 (id < codeslen)?codes[id]:"unknown");
1820
1821 if (!connected)
1822 connected++;
1823
1824#if 0
1825 aim_bos_reqservice(sess, command->conn, 0x0005); /* adverts */
1826 aim_bos_reqservice(sess, command->conn, 0x000f); /* user directory */
1827
1828 /* Don't know what this does... */
1829 /* XXX sess->sn should be normalized by the 0001/000f handler */
1830 aim_0002_000b(sess, command->conn, sess->sn);
1831#endif
1832
1833 return 1;
1834}
1835
1836int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1837{
1838 va_list ap;
1839 unsigned short reason;
1840
1841 va_start(ap, command);
1842 reason = va_arg(ap, int);
1843 va_end(ap);
1844
1845 dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1846
1847 return 1;
1848}
1849
1850int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1851{
1852 va_list ap;
1853 char *destsn;
1854 unsigned short reason;
1855
1856 va_start(ap, command);
1857 reason = va_arg(ap, int);
1858 destsn = va_arg(ap, char *);
1859 va_end(ap);
1860
1861 dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1862
1863 return 1;
1864}
1865
1866int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1867{
1868 va_list ap;
1869 char *destsn;
1870 unsigned short reason;
1871
1872 va_start(ap, command);
1873 reason = va_arg(ap, int);
1874 destsn = va_arg(ap, char *);
1875 va_end(ap);
1876
1877 dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1878
1879 return 1;
1880}
1881
1882/*
1883 * Handles callbacks for AIM_CB_MISSED_CALL.
1884 */
1885int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1886{
1887 static char *missedreasons[] = {
1888 "Unknown",
1889 "Message too large"};
1890 static int missedreasonslen = 2;
1891
1892 va_list ap;
1893 unsigned short chan, nummissed, reason;
1894 struct aim_userinfo_s *userinfo;
1895
1896 va_start(ap, command);
1897 chan = va_arg(ap, int);
1898 userinfo = va_arg(ap, struct aim_userinfo_s *);
1899 nummissed = va_arg(ap, int);
1900 reason = va_arg(ap, int);
1901 va_end(ap);
1902
1903 dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1904
1905 return 1;
1906}
1907
1908int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1909{
1910 struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
1911 char *key;
1912 va_list ap;
1913
1914 va_start(ap, command);
1915 key = va_arg(ap, char *);
1916 va_end(ap);
1917
1918 aim_send_login(sess, command->conn, screenname, password, &info, key);
1919
1920 return 1;
1921}
1922
1923int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1924{
1925 va_list ap;
1926 struct aim_userinfo_s *userinfo;
1927 int count = 0, i = 0;
1928
1929 va_start(ap, command);
1930 count = va_arg(ap, int);
1931 userinfo = va_arg(ap, struct aim_userinfo_s *);
1932 va_end(ap);
1933
1934 dvprintf("faimtest: chat: %s: New occupants have joined:\n", (char *)command->conn->priv);
1935 while (i < count)
1936 dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1937
1938 return 1;
1939}
1940
1941int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1942{
1943 va_list ap;
1944 struct aim_userinfo_s *userinfo;
1945 int count = 0, i = 0;
1946
1947 va_start(ap, command);
1948 count = va_arg(ap, int);
1949 userinfo = va_arg(ap, struct aim_userinfo_s *);
1950 va_end(ap);
1951
1952 dvprintf("faimtest: chat: %s: Some occupants have left:\n", (char *)command->conn->priv);
1953
1954 for (i = 0; i < count; )
1955 dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1956
1957 return 1;
1958}
1959
1960int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1961{
1962 va_list ap;
1963 struct aim_userinfo_s *userinfo;
1964 struct aim_chat_roominfo *roominfo;
1965 char *roomname;
1966 int usercount,i;
1967 char *roomdesc;
1968 unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1969 unsigned long creationtime;
1970
1971 va_start(ap, command);
1972 roominfo = va_arg(ap, struct aim_chat_roominfo *);
1973 roomname = va_arg(ap, char *);
1974 usercount= va_arg(ap, int);
1975 userinfo = va_arg(ap, struct aim_userinfo_s *);
1976 roomdesc = va_arg(ap, char *);
1977 unknown_c9 = va_arg(ap, int);
1978 creationtime = va_arg(ap, unsigned long);
1979 maxmsglen = va_arg(ap, int);
1980 unknown_d2 = va_arg(ap, int);
1981 unknown_d5 = va_arg(ap, int);
1982 va_end(ap);
1983
1984 dvprintf("faimtest: chat: %s: info update:\n", (char *)command->conn->priv);
1985 dvprintf("faimtest: chat: %s: \tRoominfo: {%04x, %s, %04x}\n",
1986 (char *)command->conn->priv,
1987 roominfo->exchange,
1988 roominfo->name,
1989 roominfo->instance);
1990 dvprintf("faimtest: chat: %s: \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1991 dvprintf("faimtest: chat: %s: \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1992 dvprintf("faimtest: chat: %s: \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1993
1994 for (i = 0; i < usercount; )
1995 dvprintf("faimtest: chat: %s: \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1996
1997 dvprintf("faimtest: chat: %s: \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1998 dvprintf("faimtest: chat: %s: \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1999 dvprintf("faimtest: chat: %s: \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
2000 dvprintf("faimtest: chat: %s: \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
2001 dvprintf("faimtest: chat: %s: \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
2002
2003 return 1;
2004}
2005
2006int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2007{
2008 va_list ap;
2009 struct aim_userinfo_s *userinfo;
2010 char *msg;
2011 char tmpbuf[1152];
2012
2013 va_start(ap, command);
2014 userinfo = va_arg(ap, struct aim_userinfo_s *);
2015 msg = va_arg(ap, char *);
2016 va_end(ap);
2017
2018 dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
2019
2020 /*
2021 * Do an echo for testing purposes. But not for ourselves ("oops!")
2022 */
2023 if (strcmp(userinfo->sn, sess->sn) != 0)
2024 {
2025 sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
2026 aim_chat_send_im(sess, command->conn, 0, tmpbuf, strlen(tmpbuf));
2027 }
2028
2029 return 1;
2030}
2031
2032int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2033{
2034 unsigned short type;
2035 va_list ap;
2036
2037 va_start(ap, command);
2038 type = va_arg(ap, int);
2039
2040 switch(type) {
2041 case 0x0002: {
2042 int maxrooms;
2043 struct aim_chat_exchangeinfo *exchanges;
2044 int exchangecount,i = 0;
2045
2046 maxrooms = va_arg(ap, int);
2047 exchangecount = va_arg(ap, int);
2048 exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2049 va_end(ap);
2050
2051 dprintf("faimtest: chat info: Chat Rights:\n");
2052 dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2053
2054 dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
2055 for (i = 0; i < exchangecount; i++) {
2056 dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n",
2057 exchanges[i].number,
2058 exchanges[i].name,
2059 exchanges[i].charset1,
2060 exchanges[i].lang1);
2061 }
2062
2063 }
2064 break;
2065 case 0x0008: {
2066 char *fqcn, *name, *ck;
2067 unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2068 unsigned char createperms;
2069 unsigned long createtime;
2070
2071 fqcn = va_arg(ap, char *);
2072 instance = va_arg(ap, int);
2073 exchange = va_arg(ap, int);
2074 flags = va_arg(ap, int);
2075 createtime = va_arg(ap, unsigned long);
2076 maxmsglen = va_arg(ap, int);
2077 maxoccupancy = va_arg(ap, int);
2078 createperms = va_arg(ap, int);
2079 unknown = va_arg(ap, int);
2080 name = va_arg(ap, char *);
2081 ck = va_arg(ap, char *);
2082 va_end(ap);
2083
2084 dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange);
2085 }
2086 break;
2087 default:
2088 va_end(ap);
2089 dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
2090 }
2091 return 1;
2092}
2093
2094int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2095{
2096 va_list ap;
2097 unsigned short code;
2098 char *msg = NULL;
2099
2100 va_start(ap, command);
2101 code = va_arg(ap, int);
2102 msg = va_arg(ap, char *);
2103 va_end(ap);
2104
2105 dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
2106 aim_conn_kill(sess, &command->conn); /* this will break the main loop */
2107
2108 connected = 0;
2109
2110 return 1;
2111}
2112
2113int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2114{
2115 dprintf("faimtest: connecting to an aimdebugd!\n");
2116
2117 /* convert the authorizer connection to a BOS connection */
2118 command->conn->type = AIM_CONN_TYPE_BOS;
2119
2120 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
2121
2122 /* tell the aimddebugd we're ready */
2123 aim_debugconn_sendconnect(sess, command->conn);
2124
2125 /* go right into main loop (don't open a BOS connection, etc) */
2126 return 1;
2127}
2128
2129/*
2130 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
2131 */
2132int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2133{
2134 va_list ap;
2135 unsigned short type;
2136 char *sn = NULL;
2137
2138 va_start(ap, command);
2139 type = va_arg(ap, int);
2140 sn = va_arg(ap, char *);
2141 va_end(ap);
2142
2143 dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
2144
2145 return 1;
2146}
2147
2148int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
2149{
2150 va_list ap;
2151 struct aim_conn_t *oftconn;
2152 struct aim_fileheader_t *fh;
2153 char *cookie;
2154
2155 va_start(ap, command);
2156 oftconn = va_arg(ap, struct aim_conn_t *);
2157 fh = va_arg(ap, struct aim_fileheader_t *);
2158 cookie = va_arg(ap, char *);
2159 va_end(ap);
2160
2161 dvprintf("faimtest: request for file %s.\n", fh->name);
2162
2163 return 1;
2164}
2165
2166
2167int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2168{
2169 va_list ap;
2170 struct aim_conn_t *oftconn;
2171 struct aim_fileheader_t *fh;
2172 char *path, *cookie;
2173 int pos, bufpos = 0, bufsize = 2048, i;
2174 char *buf;
2175
2176 FILE *file;
2177
2178 va_start(ap, command);
2179 oftconn = va_arg(ap, struct aim_conn_t *);
2180 fh = va_arg(ap, struct aim_fileheader_t *);
2181 cookie = va_arg(ap, char *);
2182 va_end(ap);
2183
2184 dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
2185
2186 if(!(buf = malloc(2048)))
2187 return -1;
2188
2189 if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
2190 dperror("calloc");
2191 dprintf("faimtest: error in calloc of path\n");
2192 return 0; /* XXX: no idea what winaim expects here =) */
2193 }
2194
2195 snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
2196
2197
2198 if( (file = fopen(path, "r")) == NULL) {
2199 dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
2200 return 0;
2201 }
2202
2203 /*
2204 * This is a mess. Remember that faimtest is demonstration code
2205 * only and for the sake of the gods, don't use this code in any
2206 * of your clients. --mid
2207 */
2208 for(pos = 0; pos < fh->size; pos++) {
2209 bufpos = pos % bufsize;
2210
2211 if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2212 if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2213 dperror("faim: getfile_send: write1");
2214 dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2215 free(buf);
2216 return -1;
2217 }
2218 }
2219 if( (buf[bufpos] = fgetc(file)) == EOF) {
2220 if(pos != fh->size) {
2221 dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2222 free(buf);
2223 return -1;
2224 }
2225 }
2226 dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
2227 }
2228
2229 if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2230 dperror("faim: getfile_send: write2");
2231 dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2232 free(buf);
2233 return -1;
2234 }
2235
2236 free(buf);
2237 free(fh);
2238 return 1;
2239}
2240
2241int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2242{
2243 va_list ap;
2244 struct aim_conn_t *conn;
2245 struct aim_fileheader_t *fh;
2246
2247 va_start(ap, command);
2248 conn = va_arg(ap, struct aim_conn_t *);
2249 fh = va_arg(ap, struct aim_fileheader_t *);
2250 va_end(ap);
2251
2252 dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
2253
2254 aim_conn_close(conn);
2255 aim_conn_kill(sess, &conn);
2256 return 1;
2257}
2258
2259int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2260{
2261 va_list ap;
2262 struct aim_conn_t *conn;
2263 char *sn;
2264
2265 va_start(ap, command);
2266 conn = va_arg(ap, struct aim_conn_t *);
2267 sn = va_arg(ap, char *);
2268 va_end(ap);
2269
2270 aim_conn_kill(sess, &conn);
2271
2272 dvprintf("faimtest: getfile: disconnected from %s\n", sn);
2273 return 1;
2274}
2275int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2276{
2277 va_list ap;
2278 struct aim_conn_t *conn, *listenerconn;
2279 struct aim_filetransfer_priv *priv;
2280
2281 va_start(ap, command);
2282 conn = va_arg(ap, struct aim_conn_t *);
2283 listenerconn = va_arg(ap, struct aim_conn_t *);
2284 va_end(ap);
2285
2286 aim_conn_close(listenerconn);
2287 aim_conn_kill(sess, &listenerconn);
2288
2289 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0);
2290 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2291 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);
2292 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);
2293 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2294 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2295 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2296 aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
2297
2298 priv = (struct aim_filetransfer_priv *)conn->priv;
2299
2300 dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd);
2301 return 1;
2302}
2303
2304int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2305{
2306 va_list ap;
2307 struct aim_conn_t *conn;
2308 char *listing;
2309 struct aim_filetransfer_priv *ft;
2310 char *filename, *nameend, *sizec;
2311 int filesize, namelen;
2312
2313 va_start(ap, command);
2314 conn = va_arg(ap, struct aim_conn_t *);
2315 ft = va_arg(ap, struct aim_filetransfer_priv *);
2316 listing = va_arg(ap, char *);
2317 va_end(ap);
2318
2319 dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
2320
2321 nameend = strstr(listing+0x1a, "\r");
2322
2323 namelen = nameend - (listing + 0x1a);
2324
2325 filename = malloc(namelen + 1);
2326 strncpy(filename, listing+0x1a, namelen);
2327 filename[namelen] = 0x00;
2328
2329 sizec = malloc(8+1);
2330 memcpy(sizec, listing + 0x11, 8);
2331 sizec[8] = 0x00;
2332
2333 filesize = strtol(sizec, (char **)NULL, 10);
2334
2335 dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
2336
2337 aim_oft_getfile_request(sess, conn, filename, filesize);
2338
2339 free(filename);
2340 free(sizec);
2341
2342 return 0;
2343}
2344
2345int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2346{
2347 va_list ap;
2348 struct aim_conn_t *oftconn;
2349 struct aim_fileheader_t *fh;
2350 int pos, bufpos = 0, bufsize = 2048, i;
2351 char *buf;
2352
2353 va_start(ap, command);
2354 oftconn = va_arg(ap, struct aim_conn_t *);
2355 fh = va_arg(ap, struct aim_fileheader_t *);
2356 va_end(ap);
2357
2358 dvprintf("faimtest: sending listing of size %ld\n", fh->size);
2359
2360 if(!(buf = malloc(2048)))
2361 return -1;
2362
2363 for(pos = 0; pos < fh->size; pos++) {
2364 bufpos = pos % bufsize;
2365
2366 if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2367 if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2368 dperror("faim: getfile_send: write1");
2369 dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2370 free(buf);
2371 return -1;
2372 }
2373 }
2374 if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
2375 if(pos != fh->size) {
2376 dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2377 free(buf);
2378 return -1;
2379 }
2380 }
2381 }
2382
2383 if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2384 dperror("faim: getfile_send: write2");
2385 dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2386 free(buf);
2387 return -1;
2388 }
2389
2390 dprintf("faimtest: sent listing\n");
2391 free(buf);
2392 return 0;
2393}
2394
2395int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2396{
2397 va_list ap;
2398 struct aim_conn_t *conn;
2399 struct aim_filetransfer_priv *ft;
2400 unsigned char data;
2401 int pos;
2402
2403 va_start(ap, command);
2404 conn = va_arg(ap, struct aim_conn_t *);
2405 ft = va_arg(ap, struct aim_filetransfer_priv *);
2406 va_end(ap);
2407
2408 dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
2409
2410 for(pos = 0; pos < ft->fh.size; pos++) {
2411 read(conn->fd, &data, 1);
2412 printf("%c(%02x) ", data, data);
2413 }
2414
2415 printf("\n");
2416
2417 aim_oft_getfile_end(sess, conn);
2418
2419 return 0;
2420}
2421
2422int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2423{
2424 va_list ap;
2425 struct aim_conn_t *conn;
2426
2427 va_start(ap, command);
2428 conn = va_arg(ap, struct aim_conn_t *);
2429 va_end(ap);
2430
2431 aim_conn_close(conn);
2432 aim_conn_kill(sess, &conn);
2433 return 0;
2434}
2435
2436
2437int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2438{
2439 static char *codes[5] = {"invalid",
2440 "change",
2441 "warning",
2442 "limit",
2443 "limit cleared"};
2444 va_list ap;
2445 int code;
2446 unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
2447 unsigned long currentavg, maxavg;
2448
2449 va_start(ap, command);
2450
2451 /* See code explanations below */
2452 code = va_arg(ap, int);
2453
2454 /*
2455 * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
2456 */
2457 rateclass = va_arg(ap, unsigned long);
2458
2459 /*
2460 * Not sure what this is exactly. I think its the temporal
2461 * relation factor (ie, how to make the rest of the numbers
2462 * make sense in the real world).
2463 */
2464 windowsize = va_arg(ap, unsigned long);
2465
2466 /* Explained below */
2467 clear = va_arg(ap, unsigned long);
2468 alert = va_arg(ap, unsigned long);
2469 limit = va_arg(ap, unsigned long);
2470 disconnect = va_arg(ap, unsigned long);
2471 currentavg = va_arg(ap, unsigned long);
2472 maxavg = va_arg(ap, unsigned long);
2473
2474 va_end(ap);
2475
2476
2477 dvprintf("faimtest: rate %s (rate class 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
2478 (code < 5)?codes[code]:"invalid",
2479 rateclass,
2480 currentavg, maxavg,
2481 alert, clear,
2482 limit, disconnect,
2483 windowsize);
2484
2485 if (code == AIM_RATE_CODE_CHANGE) {
2486 /*
2487 * Not real sure when these get sent.
2488 */
2489 if (currentavg >= clear)
2490 aim_conn_setlatency(command->conn, 0);
2491
2492 } else if (code == AIM_RATE_CODE_WARNING) {
2493 /*
2494 * We start getting WARNINGs the first time we go below the 'alert'
2495 * limit (currentavg < alert) and they stop when either we pause
2496 * long enough for currentavg to go above 'clear', or until we
2497 * flood it bad enough to go below 'limit' (and start getting
2498 * LIMITs instead) or even further and go below 'disconnect' and
2499 * get disconnected completely (and won't be able to login right
2500 * away either).
2501 */
2502 aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */
2503
2504 } else if (code == AIM_RATE_CODE_LIMIT) {
2505 /*
2506 * When we hit LIMIT, messages will start getting dropped.
2507 */
2508 aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */
2509
2510 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2511 /*
2512 * The limit is cleared when curavg goes above 'clear'.
2513 */
2514 aim_conn_setlatency(command->conn, 0);
2515 }
2516
2517 return 1;
2518}
2519
2520int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2521{
2522 va_list ap;
2523 int newevil;
2524 struct aim_userinfo_s *userinfo;
2525
2526 va_start(ap, command);
2527 newevil = va_arg(ap, int);
2528 userinfo = va_arg(ap, struct aim_userinfo_s *);
2529 va_end(ap);
2530
2531 /*
2532 * Evil Notifications that are lacking userinfo->sn are anon-warns
2533 * if they are an evil increases, but are not warnings at all if its
2534 * a decrease (its the natural backoff happening).
2535 *
2536 * newevil is passed as an int representing the new evil value times
2537 * ten.
2538 */
2539 dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
2540
2541 return 1;
2542}
2543
2544int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2545{
2546 va_list ap;
2547 char *address, *SNs;
2548 int i, num;
2549
2550 va_start(ap, command);
2551 address = va_arg(ap, char *);
2552 num = va_arg(ap, int);
2553 SNs = va_arg(ap, char *);
2554 va_end(ap);
2555
2556 dvprintf("faimtest: E-Mail Search Results for %s: ", address);
2557
2558 for(i = 0; i < num; i++)
2559 dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2560 dinlineprintf("\n");
2561
2562 return 1;
2563}
2564
2565int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2566{
2567 va_list ap;
2568 char *address;
2569
2570 va_start(ap, command);
2571 address = va_arg(ap, char *);
2572 va_end(ap);
2573
2574 dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2575
2576 return 1;
2577}
This page took 0.094405 seconds and 5 git commands to generate.