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