]> andersk Git - libfaim.git/blob - utils/faimtest/faimtest.c
- Mon Mar 26 16:08:45 PST 2001
[libfaim.git] / utils / faimtest / faimtest.c
1 /* 
2  *  -----------------------------------------------------------
3  *  ProtoFAIM: v1.xx.xxplxx
4  *  -----------------------------------------------------------
5  *
6  *  This is ProtoFAIM v1.xx.xxplxx!!! Its nearly completely 
7  *  different than that ugly thing called v0.  This app is
8  *  compatible with the latest version of the libfaim library.
9  *  Work is continuing. 
10  *
11  *  ProtoFAIM should only be used for two things...
12  *   1) Testing the libfaim backend.
13  *   2) For reference on the libfaim API when developing clients.
14  * 
15  *  Its very ugly.  Probably always will be.  Nothing is more
16  *  ugly than the backend itself, however.
17  *
18  *  -----------------------------------------------------------
19  *
20  *  I'm releasing this code and all it's associated linkage
21  *  under the GNU General Public License.  For more information,
22  *  please refer to http://www.fsf.org.  For any questions,
23  *  please contact me at the address below.
24  *
25  *  Most everything:
26  *  (c) 1998 Adam Fritzler, PST, mid@zigamoprh.net
27  *
28  *  The password algorithms
29  *  (c) 1998 Brock Wilcox, awwaiid@zigamorph.net
30  *
31  *  THERE IS NO CODE FROM AOL'S AIM IN THIS CODE, NOR
32  *  WAS THERE ANY DISASSEMBLAGE TO DEFINE PROTOCOL.  All
33  *  information was gained through painstakingly comparing
34  *  TCP dumps while the AIM Java client was running.  Nothing
35  *  more than that, except for a lot of experimenting.
36  *
37  *  -----------------------------------------------------------
38  *
39  */
40
41 #include "faimtest.h"
42
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   struct aim_userinfo_s *userinfo;
1476    
1477   va_list ap;
1478   va_start(ap, command);
1479   userinfo = va_arg(ap, struct aim_userinfo_s *);
1480   va_end(ap);
1481
1482   dvprintf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1483          time(NULL),
1484          userinfo->sn, userinfo->flags,
1485          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1486          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1487          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1488          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1489          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1490          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1491          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1492          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1493          userinfo->capabilities);
1494   return 1;
1495 }
1496
1497 int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1498 {
1499   static char *codes[] = {
1500     "Unknown",
1501     "Mandatory upgrade",
1502     "Advisory upgrade",
1503     "System bulletin",
1504     "Top o' the world!"};
1505   static int codeslen = 5;
1506
1507   char *msg;
1508   unsigned short id;
1509   va_list ap;
1510   
1511   va_start(ap, command);
1512   id = va_arg(ap, int);
1513   msg = va_arg(ap, char *);
1514   va_end(ap);
1515
1516   dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, 
1517            (id < codeslen)?codes[id]:"unknown");
1518
1519   if (!connected)
1520     connected++;
1521
1522 #if 0
1523   aim_bos_reqservice(sess, command->conn, 0x0005); /* adverts */
1524   aim_bos_reqservice(sess, command->conn, 0x000f); /* user directory */
1525
1526   /* Don't know what this does... */
1527   /* XXX sess->sn should be normalized by the 0001/000f handler */
1528   aim_0002_000b(sess, command->conn, sess->sn);
1529 #endif
1530
1531   /* As of 26 Mar 2001 you need to send this to keep from getting kicked off */
1532   aim_0001_0020(sess, command->conn);
1533
1534
1535   return 1;
1536 }
1537
1538 int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1539 {
1540   va_list ap;
1541   unsigned short reason;
1542
1543   va_start(ap, command);
1544   reason = va_arg(ap, int);
1545   va_end(ap);
1546
1547   dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1548   
1549   return 1;
1550 }
1551
1552 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1553 {
1554   va_list ap;
1555   char *destsn;
1556   unsigned short reason;
1557
1558   va_start(ap, command);
1559   reason = va_arg(ap, int);
1560   destsn = va_arg(ap, char *);
1561   va_end(ap);
1562
1563   dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1564   
1565   return 1;
1566 }
1567
1568 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1569 {
1570   va_list ap;
1571   char *destsn;
1572   unsigned short reason;
1573
1574   va_start(ap, command);
1575   reason = va_arg(ap, int);
1576   destsn = va_arg(ap, char *);
1577   va_end(ap);
1578
1579   dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1580   
1581   return 1;
1582 }
1583
1584 /* 
1585  * Handles callbacks for AIM_CB_MISSED_CALL.
1586  */
1587 int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1588 {
1589   static char *missedreasons[] = {
1590     "Unknown",
1591     "Message too large"};
1592   static int missedreasonslen = 2;
1593
1594   va_list ap;
1595   unsigned short chan, nummissed, reason;
1596   struct aim_userinfo_s *userinfo;
1597   
1598   va_start(ap, command);
1599   chan = va_arg(ap, int);
1600   userinfo = va_arg(ap, struct aim_userinfo_s *);
1601   nummissed = va_arg(ap, int);
1602   reason = va_arg(ap, int);
1603   va_end(ap);
1604
1605   dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1606   
1607   return 1;
1608 }
1609
1610 int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1611 {
1612   struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
1613   char *key;
1614   va_list ap;
1615   
1616   va_start(ap, command);
1617   key = va_arg(ap, char *);
1618   va_end(ap);
1619
1620   aim_send_login(sess, command->conn, screenname, password, &info, key);
1621  
1622   return 1;
1623 }
1624
1625 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1626 {
1627   va_list ap;
1628   struct aim_userinfo_s *userinfo;
1629   int count = 0, i = 0;
1630   
1631   va_start(ap, command);
1632   count = va_arg(ap, int);
1633   userinfo = va_arg(ap, struct aim_userinfo_s *);
1634   va_end(ap);
1635
1636   dvprintf("faimtest: chat: %s:  New occupants have joined:\n", (char *)command->conn->priv);
1637   while (i < count)
1638     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1639
1640   return 1;
1641 }
1642
1643 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1644 {
1645   va_list ap;
1646   struct aim_userinfo_s *userinfo;
1647   int count = 0, i = 0;
1648   
1649   va_start(ap, command);
1650   count = va_arg(ap, int);
1651   userinfo = va_arg(ap, struct aim_userinfo_s *);
1652   va_end(ap);
1653
1654   dvprintf("faimtest: chat: %s:  Some occupants have left:\n", (char *)command->conn->priv);
1655
1656   for (i = 0; i < count; )
1657     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1658
1659   return 1;
1660 }
1661
1662 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1663 {
1664   va_list ap;
1665   struct aim_userinfo_s *userinfo;
1666   struct aim_chat_roominfo *roominfo;
1667   char *roomname;
1668   int usercount,i;
1669   char *roomdesc;
1670   unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1671   unsigned long creationtime;
1672
1673   va_start(ap, command);
1674   roominfo = va_arg(ap, struct aim_chat_roominfo *);
1675   roomname = va_arg(ap, char *);
1676   usercount= va_arg(ap, int);
1677   userinfo = va_arg(ap, struct aim_userinfo_s *);
1678   roomdesc = va_arg(ap, char *);
1679   unknown_c9 = va_arg(ap, int);
1680   creationtime = va_arg(ap, unsigned long);
1681   maxmsglen = va_arg(ap, int);
1682   unknown_d2 = va_arg(ap, int);
1683   unknown_d5 = va_arg(ap, int);
1684   va_end(ap);
1685
1686   dvprintf("faimtest: chat: %s:  info update:\n", (char *)command->conn->priv);
1687   dvprintf("faimtest: chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", 
1688          (char *)command->conn->priv,
1689          roominfo->exchange,
1690          roominfo->name,
1691          roominfo->instance);
1692   dvprintf("faimtest: chat: %s:  \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1693   dvprintf("faimtest: chat: %s:  \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1694   dvprintf("faimtest: chat: %s:  \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1695   
1696   for (i = 0; i < usercount; )
1697     dvprintf("faimtest: chat: %s:  \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1698
1699   dvprintf("faimtest: chat: %s:  \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1700   dvprintf("faimtest: chat: %s:  \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1701   dvprintf("faimtest: chat: %s:  \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
1702   dvprintf("faimtest: chat: %s:  \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
1703   dvprintf("faimtest: chat: %s:  \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
1704
1705   return 1;
1706 }
1707
1708 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1709 {
1710   va_list ap;
1711   struct aim_userinfo_s *userinfo;
1712   char *msg;
1713   char tmpbuf[1152];
1714  
1715   va_start(ap, command);
1716   userinfo = va_arg(ap, struct aim_userinfo_s *);       
1717   msg = va_arg(ap, char *);
1718   va_end(ap);
1719
1720   dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
1721
1722   /*
1723    * Do an echo for testing purposes.  But not for ourselves ("oops!")
1724    */
1725   if (strcmp(userinfo->sn, sess->sn) != 0)
1726     {
1727       sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
1728       aim_chat_send_im(sess, command->conn, tmpbuf);
1729     }
1730
1731   return 1;
1732 }
1733
1734 int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1735 {
1736   unsigned short type;
1737   va_list ap;
1738
1739   va_start(ap, command);
1740   type = va_arg(ap, int);
1741
1742   switch(type) {
1743   case 0x0002: {
1744     int maxrooms;
1745     struct aim_chat_exchangeinfo *exchanges;
1746     int exchangecount,i = 0;
1747     
1748     maxrooms = va_arg(ap, int);
1749     exchangecount = va_arg(ap, int);
1750     exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1751     va_end(ap);
1752     
1753     dprintf("faimtest: chat info: Chat Rights:\n");
1754     dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1755     
1756     dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
1757     for (i = 0; i < exchangecount; i++) {
1758       dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", 
1759                exchanges[i].number,     
1760                exchanges[i].name,
1761                exchanges[i].charset1,
1762                exchanges[i].lang1);
1763     }
1764     
1765   }
1766   break;
1767   case 0x0008: {
1768     char *fqcn, *name, *ck;
1769     unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1770     unsigned char createperms;
1771     unsigned long createtime;
1772
1773     fqcn = va_arg(ap, char *);
1774     instance = va_arg(ap, int);
1775     exchange = va_arg(ap, int);
1776     flags = va_arg(ap, int);
1777     createtime = va_arg(ap, unsigned long);
1778     maxmsglen = va_arg(ap, int);
1779     maxoccupancy = va_arg(ap, int);
1780     createperms = va_arg(ap, int);
1781     unknown = va_arg(ap, int);
1782     name = va_arg(ap, char *);
1783     ck = va_arg(ap, char *);
1784     va_end(ap);
1785
1786     dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange);
1787   }
1788   break;
1789   default:
1790     va_end(ap);
1791     dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
1792   }
1793   return 1;
1794 }
1795
1796 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1797 {
1798   va_list ap;
1799   unsigned short code;
1800   char *msg = NULL;
1801
1802   va_start(ap, command);
1803   code = va_arg(ap, int);
1804   msg = va_arg(ap, char *);
1805   va_end(ap);
1806
1807   dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
1808   aim_conn_kill(sess, &command->conn); /* this will break the main loop */
1809
1810   return 1;
1811 }
1812
1813 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1814 {       
1815   dprintf("faimtest: connecting to an aimdebugd!\n");
1816
1817   /* convert the authorizer connection to a BOS connection */
1818   command->conn->type = AIM_CONN_TYPE_BOS;
1819
1820   aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1821
1822   /* tell the aimddebugd we're ready */
1823   aim_debugconn_sendconnect(sess, command->conn); 
1824
1825   /* go right into main loop (don't open a BOS connection, etc) */
1826   return 1;
1827 }
1828
1829 /*
1830  * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1831  */
1832 int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1833 {
1834   va_list ap;
1835   unsigned short type;
1836   char *sn = NULL;
1837
1838   va_start(ap, command);
1839   type = va_arg(ap, int);
1840   sn = va_arg(ap, char *);
1841   va_end(ap);
1842
1843   dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1844
1845   return 1;
1846 }
1847
1848 int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
1849 {
1850   va_list ap;
1851   struct aim_conn_t *oftconn;
1852   struct aim_fileheader_t *fh;
1853   char *cookie;
1854
1855   va_start(ap, command);
1856   oftconn = va_arg(ap, struct aim_conn_t *);
1857   fh = va_arg(ap, struct aim_fileheader_t *);
1858   cookie = va_arg(ap, char *);
1859   va_end(ap);
1860
1861   dvprintf("faimtest: request for file %s.\n", fh->name);
1862
1863   return 1;
1864 }
1865
1866
1867 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1868 {
1869   va_list ap;
1870   struct aim_conn_t *oftconn;
1871   struct aim_fileheader_t *fh;
1872   char *path, *cookie;
1873   int pos, bufpos = 0, bufsize = 2048, i;
1874   char *buf;
1875
1876   FILE *file;
1877
1878   va_start(ap, command);
1879   oftconn = va_arg(ap, struct aim_conn_t *);
1880   fh = va_arg(ap, struct aim_fileheader_t *);
1881   cookie = va_arg(ap, char *);
1882   va_end(ap);
1883
1884   dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
1885
1886   if(!(buf = malloc(2048)))
1887      return -1;
1888
1889   if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
1890     dperror("calloc");
1891     dprintf("faimtest: error in calloc of path\n");
1892     return 0; /* XXX: no idea what winaim expects here =) */
1893   }
1894   
1895   snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
1896
1897
1898   if( (file = fopen(path, "r")) == NULL) {
1899     dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
1900     return 0;
1901   }
1902
1903   /* 
1904    * This is a mess. Remember that faimtest is demonstration code
1905    * only and for the sake of the gods, don't use this code in any
1906    * of your clients. --mid
1907    */
1908   for(pos = 0; pos < fh->size; pos++) {
1909     bufpos = pos % bufsize;
1910
1911     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1912       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
1913         dperror("faim: getfile_send: write1");
1914         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
1915         free(buf);   
1916         return -1;
1917       }
1918     }
1919     if( (buf[bufpos] = fgetc(file)) == EOF) {
1920       if(pos != fh->size) {
1921         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1922         free(buf);   
1923         return -1;
1924       }
1925     }      
1926     dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
1927   }
1928
1929   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
1930     dperror("faim: getfile_send: write2");
1931     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1932     free(buf);   
1933     return -1;
1934   }
1935
1936   free(buf);
1937   free(fh);  
1938   return 1;
1939 }
1940
1941 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) 
1942 {
1943   va_list ap;
1944   struct aim_conn_t *conn;
1945   struct aim_fileheader_t *fh;
1946
1947   va_start(ap, command);
1948   conn = va_arg(ap, struct aim_conn_t *);
1949   fh = va_arg(ap, struct aim_fileheader_t *);
1950   va_end(ap);
1951
1952   dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
1953
1954   aim_conn_close(conn);
1955   aim_conn_kill(sess, &conn);
1956   return 1;
1957 }
1958
1959 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1960 {
1961   va_list ap;
1962   struct aim_conn_t *conn;
1963   char *sn;
1964
1965   va_start(ap, command);
1966   conn = va_arg(ap, struct aim_conn_t *);
1967   sn = va_arg(ap, char *);
1968   va_end(ap);
1969
1970   aim_conn_kill(sess, &conn);
1971
1972   dvprintf("faimtest: getfile: disconnected from %s\n", sn);
1973   return 1;
1974 }
1975 int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1976 {
1977   va_list ap;
1978   struct aim_conn_t *conn, *listenerconn;
1979   struct aim_filetransfer_priv *priv;
1980
1981   va_start(ap, command);
1982   conn = va_arg(ap, struct aim_conn_t *);
1983   listenerconn = va_arg(ap, struct aim_conn_t *);
1984   va_end(ap);
1985
1986   aim_conn_close(listenerconn);
1987   aim_conn_kill(sess, &listenerconn);
1988
1989   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
1990   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1991   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
1992   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
1993   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
1994   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1995   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
1996   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
1997   
1998   priv = (struct aim_filetransfer_priv *)conn->priv;
1999
2000   dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd);
2001   return 1;
2002 }
2003
2004 int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2005 {
2006   va_list ap;
2007   struct aim_conn_t *conn;
2008   char *listing;
2009   struct aim_filetransfer_priv *ft;
2010   char *filename, *nameend, *sizec;
2011   int filesize, namelen;
2012
2013   va_start(ap, command);
2014   conn = va_arg(ap, struct aim_conn_t *);
2015   ft = va_arg(ap, struct aim_filetransfer_priv *);
2016   listing = va_arg(ap, char *);
2017   va_end(ap);
2018
2019   dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
2020
2021   nameend = strstr(listing+0x1a, "\r");
2022
2023   namelen = nameend - (listing + 0x1a);
2024
2025   filename = malloc(namelen + 1);
2026   strncpy(filename, listing+0x1a, namelen);
2027   filename[namelen] = 0x00;
2028
2029   sizec = malloc(8+1);
2030   memcpy(sizec, listing + 0x11, 8);
2031   sizec[8] = 0x00;
2032
2033   filesize =  strtol(sizec, (char **)NULL, 10);
2034
2035   dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
2036
2037   aim_oft_getfile_request(sess, conn, filename, filesize);
2038
2039   free(filename);
2040   free(sizec);
2041
2042   return 0;
2043 }
2044
2045 int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2046 {
2047   va_list ap;
2048   struct aim_conn_t *oftconn;
2049   struct aim_fileheader_t *fh;
2050   int pos, bufpos = 0, bufsize = 2048, i;
2051   char *buf;
2052
2053   va_start(ap, command);
2054   oftconn = va_arg(ap, struct aim_conn_t *);
2055   fh = va_arg(ap, struct aim_fileheader_t *);
2056   va_end(ap);
2057
2058   dvprintf("faimtest: sending listing of size %ld\n", fh->size);
2059
2060   if(!(buf = malloc(2048)))
2061     return -1;
2062
2063   for(pos = 0; pos < fh->size; pos++) {
2064     bufpos = pos % bufsize;
2065
2066     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2067       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2068         dperror("faim: getfile_send: write1");
2069         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2070         free(buf);   
2071         return -1;
2072       }
2073     }
2074     if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
2075       if(pos != fh->size) {
2076         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2077         free(buf);   
2078         return -1;
2079       }
2080     }      
2081   }
2082
2083   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2084     dperror("faim: getfile_send: write2");
2085     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2086     free(buf);   
2087     return -1;
2088   }
2089
2090   dprintf("faimtest: sent listing\n");
2091   free(buf);
2092   return 0;
2093 }
2094
2095 int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2096 {
2097   va_list ap;
2098   struct aim_conn_t *conn;
2099   struct aim_filetransfer_priv *ft;
2100   unsigned char data;
2101   int pos;
2102
2103   va_start(ap, command);
2104   conn = va_arg(ap, struct aim_conn_t *);
2105   ft = va_arg(ap, struct aim_filetransfer_priv *);
2106   va_end(ap);
2107
2108   dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
2109
2110   for(pos = 0; pos < ft->fh.size; pos++) {
2111     read(conn->fd, &data, 1);
2112     printf("%c(%02x) ", data, data);
2113   }
2114    
2115   printf("\n");
2116
2117   aim_oft_getfile_end(sess, conn);
2118
2119   return 0;
2120 }
2121
2122 int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2123 {
2124   va_list ap;
2125   struct aim_conn_t *conn;
2126
2127   va_start(ap, command);
2128   conn = va_arg(ap, struct aim_conn_t *);
2129   va_end(ap);
2130
2131   aim_conn_close(conn);
2132   aim_conn_kill(sess, &conn);
2133   return 0;
2134 }
2135
2136
2137 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2138 {
2139   static char *codes[5] = {"invalid",
2140                            "change",
2141                            "warning",
2142                            "limit",
2143                            "limit cleared"};
2144   va_list ap;
2145   int code;
2146   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
2147   unsigned long currentavg, maxavg;
2148
2149   va_start(ap, command); 
2150
2151   /* See code explanations below */
2152   code = va_arg(ap, int);
2153
2154   /*
2155    * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
2156    */
2157   rateclass = va_arg(ap, unsigned long);
2158
2159   /*
2160    * Not sure what this is exactly.  I think its the temporal 
2161    * relation factor (ie, how to make the rest of the numbers
2162    * make sense in the real world). 
2163    */
2164   windowsize = va_arg(ap, unsigned long);
2165
2166   /* Explained below */
2167   clear = va_arg(ap, unsigned long);
2168   alert = va_arg(ap, unsigned long);
2169   limit = va_arg(ap, unsigned long);
2170   disconnect = va_arg(ap, unsigned long);
2171   currentavg = va_arg(ap, unsigned long);
2172   maxavg = va_arg(ap, unsigned long);
2173
2174   va_end(ap);
2175
2176
2177   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",
2178          (code < 5)?codes[code]:"invalid",
2179          rateclass,
2180          currentavg, maxavg,
2181          alert, clear,
2182          limit, disconnect,
2183          windowsize);
2184
2185   if (code == AIM_RATE_CODE_CHANGE) {
2186     /*
2187      * Not real sure when these get sent.
2188      */
2189     if (currentavg >= clear)
2190       aim_conn_setlatency(command->conn, 0);
2191
2192   } else if (code == AIM_RATE_CODE_WARNING) {
2193     /*
2194      * We start getting WARNINGs the first time we go below the 'alert'
2195      * limit (currentavg < alert) and they stop when either we pause
2196      * long enough for currentavg to go above 'clear', or until we
2197      * flood it bad enough to go below 'limit' (and start getting
2198      * LIMITs instead) or even further and go below 'disconnect' and 
2199      * get disconnected completely (and won't be able to login right
2200      * away either).
2201      */
2202     aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ 
2203
2204   } else if (code == AIM_RATE_CODE_LIMIT) {
2205     /*
2206      * When we hit LIMIT, messages will start getting dropped.
2207      */
2208     aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ 
2209
2210   } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2211     /*
2212      * The limit is cleared when curavg goes above 'clear'.
2213      */
2214     aim_conn_setlatency(command->conn, 0); 
2215   }
2216
2217   return 1;
2218 }
2219
2220 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2221 {
2222   va_list ap;
2223   int newevil;
2224   struct aim_userinfo_s *userinfo;
2225
2226   va_start(ap, command);
2227   newevil = va_arg(ap, int);
2228   userinfo = va_arg(ap, struct aim_userinfo_s *);
2229   va_end(ap);
2230
2231   /*
2232    * Evil Notifications that are lacking userinfo->sn are anon-warns
2233    * if they are an evil increases, but are not warnings at all if its
2234    * a decrease (its the natural backoff happening).
2235    *
2236    * newevil is passed as an int representing the new evil value times
2237    * ten.
2238    */
2239   dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
2240
2241   return 1;
2242 }
2243
2244 int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2245 {
2246   va_list ap;
2247   char *address, *SNs;
2248   int i, num;
2249   
2250   va_start(ap, command);
2251   address = va_arg(ap, char *);
2252   num = va_arg(ap, int);
2253   SNs = va_arg(ap, char *);
2254   va_end(ap);
2255
2256   dvprintf("faimtest: E-Mail Search Results for %s: ", address);
2257
2258   for(i = 0; i < num; i++)
2259     dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2260   dinlineprintf("\n");
2261
2262   return 1;
2263 }
2264
2265 int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2266 {
2267   va_list ap;
2268   char *address;
2269   
2270   va_start(ap, command);
2271   address = va_arg(ap, char *);
2272   va_end(ap);
2273
2274   dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2275
2276   return 1;
2277 }
This page took 0.740669 seconds and 5 git commands to generate.