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