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