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