]> andersk Git - libfaim.git/blob - utils/faimtest/faimtest.c
bc6656abda29e729d329095e8c2fe69f99caa4ef
[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, char *modname)
801 {
802   FILE *f;
803
804   char *filename;
805   int len;
806
807   len = strlen(aimbinarypath)+1+strlen(modname)+1;
808
809   if(!(filename = malloc(len))) {
810     dperror("memrequest: malloc");
811     return -1;
812   }
813
814   memset(filename,0, len);
815   memcpy(filename, aimbinarypath, strlen(aimbinarypath));
816   filename[strlen(filename)] = '/';
817   strncat(filename, modname, len - strlen(filename));
818
819   if (!(f = fopen(filename, "r"))) {
820     dperror("memrequest: fopen");
821     return -1;
822   }
823
824   if (fseek(f, offset, SEEK_SET) == -1) {
825     dperror("memrequest: fseek");
826     fclose(f);
827     return -1;
828   }
829
830   if (fread(buf, buflen, 1, f) != 1) {
831     dperror("memrequest: fread");
832     fclose(f);
833     return -1;
834   }
835
836   fclose(f);
837
838   return buflen;
839 }
840
841 /*
842  * This will get an offset and a length.  The client should read this
843  * data out of whatever AIM.EXE binary the user has provided (hopefully
844  * it matches the client information thats sent at login) and pass a
845  * buffer back to libfaim so it can hash the data and send it to AOL for
846  * inspection by the client police.
847  */
848 static int faimtest_memrequest(struct aim_session_t *sess, struct command_rx_struct *command, ...)
849 {
850   va_list ap;
851   unsigned long offset, len;
852   unsigned char *buf;
853   char *modname;
854   
855   va_start(ap, command);
856   offset = va_arg(ap, unsigned long);
857   len = va_arg(ap, unsigned long);
858   modname = va_arg(ap, char *);
859   va_end(ap);
860
861   if (!(buf = malloc(len))) {
862     dperror("memrequest: malloc");
863     return 0;
864   }
865
866   if (aimbinarypath && (getaimdata(buf, len, offset, modname) == len)) {
867
868     dvprintf("memrequest: sending %ld bytes from 0x%08lx in \"%s/%s\"...\n", len, offset, aimbinarypath, modname);
869
870     aim_sendmemblock(sess, command->conn, offset, len, buf);
871
872   } else {
873
874     dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", aimbinarypath, modname);
875
876     aim_sendmemblock(sess, command->conn, offset, len, NULL);
877
878   }
879
880   free(buf);
881
882   return 1;
883 }
884
885 static int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...)
886 {
887   va_list ap;
888   struct aim_conn_t *bosconn = NULL;
889   char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
890   unsigned char *cookie = NULL;
891   int errorcode = 0, regstatus = 0;
892   int latestbuild = 0, latestbetabuild = 0;
893   char *latestrelease = NULL, *latestbeta = NULL;
894   char *latestreleaseurl = NULL, *latestbetaurl = NULL;
895   char *latestreleaseinfo = NULL, *latestbetainfo = NULL;
896
897   va_start(ap, command);
898   sn = va_arg(ap, char *);
899   errorcode = va_arg(ap, int);
900   errurl = va_arg(ap, char *);
901   regstatus = va_arg(ap, int);
902   email = va_arg(ap, char *);
903   bosip = va_arg(ap, char *);
904   cookie = va_arg(ap, unsigned char *);
905
906   latestrelease = va_arg(ap, char *);
907   latestbuild = va_arg(ap, int);
908   latestreleaseurl = va_arg(ap, char *);
909   latestreleaseinfo = va_arg(ap, char *);
910
911   latestbeta = va_arg(ap, char *);
912   latestbetabuild = va_arg(ap, int);
913   latestbetaurl = va_arg(ap, char *);
914   latestbetainfo = va_arg(ap, char *);
915
916   va_end(ap);
917
918   dvprintf("Screen name: %s\n", sn);
919
920   /*
921    * Check for error.
922    */
923   if (errorcode || !bosip || !cookie) {
924     dvprintf("Login Error Code 0x%04x\n", errorcode);
925     dvprintf("Error URL: %s\n", errurl);
926     aim_conn_kill(sess, &command->conn);
927     return 1;
928   }
929
930   dvprintf("Reg status: %2d\n", regstatus);
931   dvprintf("Email: %s\n", email);
932   dvprintf("BOS IP: %s\n", bosip);
933
934   if (latestbeta)
935     dvprintf("Latest beta version: %s, build %d, at %s (more info at %s)\n", latestbeta, latestbetabuild, latestbetaurl, latestbetainfo);
936
937   if (latestrelease)
938     dvprintf("Latest released version: %s, build %d, at %s (more info at %s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo);
939
940   dprintf("Closing auth connection...\n");
941   aim_conn_kill(sess, &command->conn);
942   if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
943     dprintf("faimtest: could not connect to BOS: internal error\n");
944     return 1;
945   } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
946     dprintf("faimtest: could not connect to BOS\n");
947     aim_conn_kill(sess, &bosconn);
948     return 1;
949   }
950
951   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
952   aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
953   aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
954   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
955   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
956   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
957   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
958   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
959   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
960   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
961   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
962   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
963   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
964   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
965   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
966   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
967   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
968   aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
969   aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
970   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
971   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
972   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
973
974   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
975
976   aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
977   aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
978   aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
979   aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
980
981   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
982   aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
983   aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
984
985   aim_auth_sendcookie(sess, bosconn, cookie);
986
987   return 1;
988 }
989
990 static void printuserflags(unsigned short flags)
991 {
992   if (flags & AIM_FLAG_UNCONFIRMED)
993     dinlineprintf("UNCONFIRMED ");
994   if (flags & AIM_FLAG_ADMINISTRATOR)
995     dinlineprintf("ADMINISTRATOR ");
996   if (flags & AIM_FLAG_AOL)
997     dinlineprintf("AOL ");
998   if (flags & AIM_FLAG_OSCAR_PAY)
999     dinlineprintf("OSCAR_PAY ");
1000   if (flags & AIM_FLAG_FREE)
1001     dinlineprintf("FREE ");
1002   if (flags & AIM_FLAG_AWAY)
1003     dinlineprintf("AWAY ");
1004   if (flags & AIM_FLAG_UNKNOWN40)
1005     dinlineprintf("ICQ? ");
1006   if (flags & AIM_FLAG_UNKNOWN80)
1007     dinlineprintf("UNKNOWN80 ");
1008   return;
1009 }
1010
1011 int faimtest_parse_userinfo(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1012 {
1013   struct aim_userinfo_s *userinfo;
1014   char *prof_encoding = NULL;
1015   char *prof = NULL;
1016   unsigned short inforeq = 0;
1017
1018   va_list ap;
1019   va_start(ap, command);
1020   userinfo = va_arg(ap, struct aim_userinfo_s *);
1021   prof_encoding = va_arg(ap, char *);
1022   prof = va_arg(ap, char *);
1023   inforeq = va_arg(ap, int);
1024   va_end(ap);
1025   
1026   dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn);
1027   dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
1028   dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
1029   printuserflags(userinfo->flags);
1030   dinlineprintf("\n");
1031   
1032   dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
1033   dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
1034   dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
1035   
1036   if (inforeq == AIM_GETINFO_GENERALINFO) {
1037     dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1038     dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
1039   } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
1040     dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1041     dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
1042   } else 
1043     dprintf("faimtest: userinfo: unknown info request\n");
1044   
1045   return 1;
1046 }
1047
1048 static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_struct *command, struct aim_userinfo_s *userinfo, char *tmpstr)
1049 {
1050
1051   if (!strncmp(tmpstr, "disconnect", 10)) {
1052
1053     logout();
1054
1055   } else if (strstr(tmpstr, "goodday")) {
1056
1057       aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.", strlen("Good day to you too."));
1058
1059   } else if (strstr(tmpstr, "warnme")) {
1060
1061     dprintf("faimtest: icbm: sending non-anon warning\n");
1062     aim_send_warning(sess, command->conn, userinfo->sn, 0);
1063
1064   } else if (strstr(tmpstr, "anonwarn")) {
1065
1066     dprintf("faimtest: icbm: sending anon warning\n");
1067     aim_send_warning(sess, command->conn, userinfo->sn, AIM_WARN_ANON);
1068
1069   } else if (strstr(tmpstr, "setdirectoryinfo")) {
1070
1071     dprintf("faimtest: icbm: sending backwards profile data\n");
1072     aim_setdirectoryinfo(sess, command->conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1073
1074   } else if (strstr(tmpstr, "setinterests")) {
1075
1076     dprintf("faimtest: icbm: setting fun interests\n");
1077     aim_setuserinterests(sess, command->conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1078
1079   } else if (!strncmp(tmpstr, "getfile", 7)) {
1080
1081     if (!ohcaptainmycaptain) {
1082
1083       aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!", strlen("I have no owner!"));
1084
1085     } else {
1086       struct aim_conn_t *newconn;
1087
1088       newconn = aim_getfile_initiate(sess, command->conn, (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
1089       dvprintf("faimtest: getting file listing from %s\n", (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
1090       aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
1091     }
1092
1093   } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1094
1095     aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
1096
1097   } else if (!strncmp(tmpstr, "create", 6)) {
1098
1099     aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1100
1101   } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1102     struct aim_conn_t *chatnavconn;
1103
1104     chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV);
1105     aim_conn_kill(sess, &chatnavconn);
1106
1107   } else if (!strncmp(tmpstr, "join", 4)) {
1108
1109     aim_chat_join(sess, command->conn, 0x0004, "worlddomination");
1110
1111   } else if (!strncmp(tmpstr, "leave", 5)) {
1112
1113     aim_chat_leaveroom(sess, "worlddomination");
1114
1115   } else if (!strncmp(tmpstr, "getinfo", 7)) {
1116
1117     aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
1118     aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1119     aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_GENERALINFO);
1120     aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1121
1122   } else if (!strncmp(tmpstr, "open directim", 13)) {
1123     struct aim_conn_t *newconn;
1124
1125     printf("faimtest: opening directim to %s\n", (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1126     newconn = aim_directim_initiate(sess, command->conn, NULL, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14);
1127     if(!newconn || newconn->fd == -1)
1128       printf("connection failed!\n");
1129     aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate,0);
1130
1131   } else if(!(strncmp(tmpstr, "lookup", 6))) {
1132
1133     aim_usersearch_address(sess, command->conn, tmpstr+7);
1134
1135   } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1136
1137     aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900", strlen("sendmsg 7900"));
1138
1139   } else if (!strncmp(tmpstr, "reqauth", 7)) {
1140
1141     aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_AUTH);
1142
1143   } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1144
1145     aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1146
1147   } else if (!strncmp(tmpstr, "reqemail", 8)) {
1148
1149     aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1150
1151   } else if (!strncmp(tmpstr, "changepass", 8)) {
1152
1153     aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1154
1155   } else if (!strncmp(tmpstr, "setemail", 8)) {
1156
1157     aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1158
1159   } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1160     int i;
1161     i = atoi(tmpstr+8);
1162     if (i < 10000) {
1163       char *newbuf;
1164       int z;
1165
1166       newbuf = malloc(i+1);
1167       for (z = 0; z < i; z++) {
1168         newbuf[z] = (z % 10)+0x30;
1169       }
1170       newbuf[i] = '\0';
1171       aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf, strlen(newbuf));
1172       free(newbuf);
1173     }
1174
1175   } else {
1176
1177     dprintf("unknown command.\n");
1178     aim_add_buddy(sess, command->conn, userinfo->sn);
1179
1180   }  
1181
1182   return 0;
1183 }
1184
1185 /*
1186  * The user-level Incoming ICBM callback.
1187  *
1188  */
1189 int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1190 {
1191   int channel;
1192   va_list ap;
1193
1194   va_start(ap, command);
1195   channel = va_arg(ap, int);
1196
1197   /*
1198    * Channel 1: Standard Message
1199    */
1200   if (channel == 1) {
1201     struct aim_userinfo_s *userinfo;
1202     char *msg = NULL;
1203     u_int icbmflags = 0;
1204     char *tmpstr = NULL;
1205     unsigned short flag1, flag2;
1206     int finlen = 0;
1207     unsigned char *fingerprint = NULL;
1208     int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1209     
1210     userinfo = va_arg(ap, struct aim_userinfo_s *);
1211     msg = va_arg(ap, char *);
1212     icbmflags = va_arg(ap, u_int);
1213     flag1 = va_arg(ap, int);
1214     flag2 = va_arg(ap, int);
1215     finlen = va_arg(ap, int);
1216     fingerprint = va_arg(ap, unsigned char *);
1217     va_end(ap);
1218     
1219     clienttype = aim_fingerprintclient(fingerprint, finlen);
1220
1221     dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
1222     dvprintf("faimtest: icbm: probable client type: %d\n", clienttype);
1223     dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
1224     dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
1225     printuserflags(userinfo->flags);
1226     dinlineprintf("\n");
1227
1228     dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
1229     dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
1230     dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
1231     dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
1232     
1233     dprintf("faimtest: icbm: icbmflags = ");
1234     if (icbmflags & AIM_IMFLAGS_AWAY)
1235       dinlineprintf("away ");
1236     if (icbmflags & AIM_IMFLAGS_ACK)
1237       dinlineprintf("ackrequest ");
1238     dinlineprintf("\n");
1239     
1240     dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", flag1, flag2);
1241     
1242     dvprintf("faimtest: icbm: message: %s\n", msg);
1243     
1244     if (msg) {
1245       int i = 0;
1246
1247       while (msg[i] == '<') {
1248         if (msg[i] == '<') {
1249           while (msg[i] != '>')
1250             i++;
1251           i++;
1252         }
1253       }
1254       tmpstr = msg+i;
1255
1256       faimtest_handlecmd(sess, command, userinfo, tmpstr);
1257
1258     }
1259   }
1260   /*
1261    * Channel 2: Rendevous Request
1262    */
1263   else if (channel == 2) {
1264     struct aim_userinfo_s *userinfo;
1265     unsigned short reqclass;
1266     
1267     reqclass = va_arg(ap, int);
1268     switch (reqclass) {
1269     case AIM_CAPS_VOICE: {
1270       userinfo = va_arg(ap, struct aim_userinfo_s *);
1271       va_end(ap);
1272       
1273       dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1274       dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1275       dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1276       printuserflags(userinfo->flags);
1277       dinlineprintf("\n");
1278
1279       /* we dont get membersince on chat invites! */
1280       dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1281       dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1282       
1283       break;
1284     }
1285     case AIM_CAPS_GETFILE: {
1286       char *ip, *cookie;
1287       struct aim_conn_t *newconn;
1288       struct aim_fileheader_t *fh;
1289
1290       userinfo = va_arg(ap, struct aim_userinfo_s *);
1291       ip = va_arg(ap, char *);
1292       cookie = va_arg(ap, char *);
1293       va_end(ap);
1294       
1295       dvprintf("faimtest: get file request from %s (at %s) %x\n", userinfo->sn, ip, reqclass);
1296
1297       fh = aim_getlisting(sess, listingfile);      
1298
1299       newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, cookie, ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, reqclass);
1300
1301       if( (!newconn) || (newconn->fd == -1) ) {
1302         dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n");
1303         if(newconn)
1304           aim_conn_kill(sess, &newconn);
1305         break;
1306       }
1307
1308       free(fh);
1309
1310       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1311       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
1312       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1313       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
1314
1315       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
1316
1317       dprintf("faimtest: getfile connect succeeded, handlers added.\n");
1318
1319       break;
1320     }
1321     case AIM_CAPS_SENDFILE: {
1322       dprintf("faimtest: send file!\n");
1323       break;
1324     }
1325     case AIM_CAPS_CHAT: {
1326       char *msg,*encoding,*lang;
1327       struct aim_chat_roominfo *roominfo;
1328       
1329       userinfo = va_arg(ap, struct aim_userinfo_s *);
1330       roominfo = va_arg(ap, struct aim_chat_roominfo *);
1331       msg = va_arg(ap, char *);
1332       encoding = va_arg(ap, char *);
1333       lang = va_arg(ap, char *);
1334       va_end(ap);
1335       
1336       dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1337       dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1338       dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1339       printuserflags(userinfo->flags);
1340       dinlineprintf("\n");
1341
1342       /* we dont get membersince on chat invites! */
1343       dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1344       dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1345       
1346       dvprintf("faimtest: chat invitation: message = %s\n", msg);
1347       dvprintf("faimtest: chat invitation: room name = %s\n", roominfo->name);
1348       dvprintf("faimtest: chat invitation: encoding = %s\n", encoding);
1349       dvprintf("faimtest: chat invitation: language = %s\n", lang);
1350       dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", roominfo->exchange);
1351       dvprintf("faimtest: chat invitation: instance = 0x%04x\n", roominfo->instance);
1352       dvprintf("faimtest: chat invitiation: autojoining %s...\n", roominfo->name);
1353       /*
1354        * Automatically join room...
1355        */ 
1356       aim_chat_join(sess, command->conn, 0x0004, roominfo->name);
1357       break;
1358     }   
1359     case AIM_CAPS_IMIMAGE: {
1360       struct aim_directim_priv *priv;
1361       struct aim_conn_t *newconn;
1362
1363       dprintf("faimtest: icbm: rendezvous imimage\n");
1364      
1365       userinfo = va_arg(ap, struct aim_userinfo_s *);
1366       priv = va_arg(ap, struct aim_directim_priv *);
1367       va_end(ap);
1368
1369       dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, priv->ip);
1370       
1371       newconn = aim_directim_connect(sess, command->conn, priv);
1372
1373       if ( (!newconn) || (newconn->fd == -1) ) {
1374         dprintf("faimtest: icbm: imimage: could not connect\n");
1375
1376         if (newconn)
1377           aim_conn_kill(sess, &newconn);
1378
1379         break;
1380       }
1381
1382       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1383       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1384       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1385
1386       dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn);
1387
1388       aim_send_im_direct(sess, newconn, "goodday");
1389
1390       break;
1391     }
1392     default:
1393       dvprintf("faimtest: icbm: unknown reqclass (%d)\n", reqclass);
1394     } /* switch */
1395   } else
1396     dvprintf("faimtest does not support channels > 2 (chan = %02x)\n", channel);
1397   dprintf("faimtest: icbm: done with ICBM handling\n");
1398
1399   return 1;
1400 }
1401
1402 int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1403 {
1404   va_list ap;
1405   struct aim_directim_priv *priv;
1406   struct aim_conn_t *newconn, *listenerconn;
1407
1408   va_start(ap, command);
1409   newconn = va_arg(ap, struct aim_conn_t *);
1410   listenerconn = va_arg(ap, struct aim_conn_t *);
1411   va_end(ap);
1412
1413   aim_conn_close(listenerconn);
1414   aim_conn_kill(sess, &listenerconn);
1415
1416   priv = (struct aim_directim_priv *)newconn->priv;
1417
1418   dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip);
1419   
1420   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1421   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1422   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1423
1424   aim_send_im_direct(sess, newconn, "goodday");
1425
1426   dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn);
1427
1428   return 1;
1429 }
1430
1431 int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1432 {
1433   va_list ap;
1434   struct aim_directim_priv *priv;
1435   
1436   va_start(ap, command);
1437   priv = va_arg(ap, struct aim_directim_priv *);
1438
1439   va_end(ap);
1440   
1441   dprintf("faimtest: directim_connect\n");
1442
1443   return 1;
1444 }
1445
1446 int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1447 {
1448   va_list ap;
1449   char *msg = NULL;
1450   struct aim_conn_t *conn;
1451   struct aim_directim_priv *priv;
1452
1453   va_start(ap, command);
1454   conn = va_arg(ap, struct aim_conn_t *);
1455   msg = va_arg(ap, char *);
1456   va_end(ap);
1457
1458   if(!(priv = conn->priv)) {
1459     dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd);
1460     return -1;
1461   }
1462
1463   dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg);
1464   if (!strncmp(msg, "sendmsg", 7)) {
1465     int i;
1466     i = atoi(msg+8);
1467     if (i < 10000) {
1468       char *newbuf;
1469       int z;
1470       
1471       newbuf = malloc(i+1);
1472       for (z = 0; z < i; z++) {
1473         newbuf[z] = (z % 10)+0x30;
1474       }
1475       newbuf[i] = '\0';
1476       aim_send_im_direct(sess, conn, newbuf);
1477       free(newbuf);
1478     }
1479   } else if (!strncmp(msg, "goodday", 7)) {
1480     aim_send_im_direct(sess, conn, "Good day to you, too");
1481   } else {
1482     char newmsg[1024];
1483     snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1484     aim_send_im_direct(sess, conn, newmsg);
1485   }
1486   return 1;
1487 }
1488
1489 int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1490 {
1491   va_list ap;
1492   struct aim_conn_t *conn;
1493   char *sn;
1494
1495   va_start(ap, command);
1496   conn = va_arg(ap, struct aim_conn_t *);
1497   sn = va_arg(ap, char *);
1498   va_end(ap);
1499
1500   dvprintf("faimtest: directim: disconnected from %s\n", sn);
1501
1502   aim_conn_kill(sess, &conn);
1503   return 1;
1504 }
1505
1506 int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1507 {
1508   va_list ap;
1509   struct aim_conn_t *conn;
1510   struct aim_directim_priv *priv;
1511
1512   va_start(ap, command);
1513   conn = va_arg(ap, struct aim_conn_t *);
1514   va_end(ap);
1515   
1516   if(!(priv = (struct aim_directim_priv *)conn->priv)) {
1517     dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd);
1518     return -1;
1519   }
1520
1521   dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
1522   return 1;
1523 }
1524
1525 int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1526 {
1527   unsigned short change = 0;
1528   int perms, type, length, str;
1529   char *val;
1530   va_list ap;
1531
1532   va_start(ap, command);
1533   perms = va_arg(ap, int);
1534   type = va_arg(ap, int);
1535   length = va_arg(ap, int);
1536   val = va_arg(ap, char *);
1537   str = va_arg(ap, int);
1538   va_end(ap);
1539
1540   if (aimutil_get16(command->data+2) == 0x0005)
1541     change = 1;
1542
1543   dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1544
1545   return 1;
1546 }
1547
1548 int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1549 {
1550   struct aim_userinfo_s *userinfo;
1551    
1552   va_list ap;
1553   va_start(ap, command);
1554   userinfo = va_arg(ap, struct aim_userinfo_s *);
1555   va_end(ap);
1556
1557   dvprintf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1558          time(NULL),
1559          userinfo->sn, userinfo->flags,
1560          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1561          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1562          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1563          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1564          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1565          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1566          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1567          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1568          userinfo->capabilities);
1569   return 1;
1570 }
1571
1572 int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1573 {
1574   struct aim_userinfo_s *userinfo;
1575    
1576   va_list ap;
1577   va_start(ap, command);
1578   userinfo = va_arg(ap, struct aim_userinfo_s *);
1579   va_end(ap);
1580
1581   dvprintf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1582          time(NULL),
1583          userinfo->sn, userinfo->flags,
1584          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1585          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1586          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1587          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1588          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1589          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1590          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1591          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1592          userinfo->capabilities);
1593   return 1;
1594 }
1595
1596 int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1597 {
1598   static char *codes[] = {
1599     "Unknown",
1600     "Mandatory upgrade",
1601     "Advisory upgrade",
1602     "System bulletin",
1603     "Top o' the world!"};
1604   static int codeslen = 5;
1605
1606   char *msg;
1607   unsigned short id;
1608   va_list ap;
1609   
1610   va_start(ap, command);
1611   id = va_arg(ap, int);
1612   msg = va_arg(ap, char *);
1613   va_end(ap);
1614
1615   dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, 
1616            (id < codeslen)?codes[id]:"unknown");
1617
1618   if (!connected)
1619     connected++;
1620
1621 #if 0
1622   aim_bos_reqservice(sess, command->conn, 0x0005); /* adverts */
1623   aim_bos_reqservice(sess, command->conn, 0x000f); /* user directory */
1624
1625   /* Don't know what this does... */
1626   /* XXX sess->sn should be normalized by the 0001/000f handler */
1627   aim_0002_000b(sess, command->conn, sess->sn);
1628 #endif
1629
1630   return 1;
1631 }
1632
1633 int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1634 {
1635   va_list ap;
1636   unsigned short reason;
1637
1638   va_start(ap, command);
1639   reason = va_arg(ap, int);
1640   va_end(ap);
1641
1642   dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1643   
1644   return 1;
1645 }
1646
1647 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1648 {
1649   va_list ap;
1650   char *destsn;
1651   unsigned short reason;
1652
1653   va_start(ap, command);
1654   reason = va_arg(ap, int);
1655   destsn = va_arg(ap, char *);
1656   va_end(ap);
1657
1658   dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1659   
1660   return 1;
1661 }
1662
1663 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1664 {
1665   va_list ap;
1666   char *destsn;
1667   unsigned short reason;
1668
1669   va_start(ap, command);
1670   reason = va_arg(ap, int);
1671   destsn = va_arg(ap, char *);
1672   va_end(ap);
1673
1674   dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1675   
1676   return 1;
1677 }
1678
1679 /* 
1680  * Handles callbacks for AIM_CB_MISSED_CALL.
1681  */
1682 int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1683 {
1684   static char *missedreasons[] = {
1685     "Unknown",
1686     "Message too large"};
1687   static int missedreasonslen = 2;
1688
1689   va_list ap;
1690   unsigned short chan, nummissed, reason;
1691   struct aim_userinfo_s *userinfo;
1692   
1693   va_start(ap, command);
1694   chan = va_arg(ap, int);
1695   userinfo = va_arg(ap, struct aim_userinfo_s *);
1696   nummissed = va_arg(ap, int);
1697   reason = va_arg(ap, int);
1698   va_end(ap);
1699
1700   dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1701   
1702   return 1;
1703 }
1704
1705 int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1706 {
1707   struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
1708   char *key;
1709   va_list ap;
1710   
1711   va_start(ap, command);
1712   key = va_arg(ap, char *);
1713   va_end(ap);
1714
1715   aim_send_login(sess, command->conn, screenname, password, &info, key);
1716  
1717   return 1;
1718 }
1719
1720 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1721 {
1722   va_list ap;
1723   struct aim_userinfo_s *userinfo;
1724   int count = 0, i = 0;
1725   
1726   va_start(ap, command);
1727   count = va_arg(ap, int);
1728   userinfo = va_arg(ap, struct aim_userinfo_s *);
1729   va_end(ap);
1730
1731   dvprintf("faimtest: chat: %s:  New occupants have joined:\n", (char *)command->conn->priv);
1732   while (i < count)
1733     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1734
1735   return 1;
1736 }
1737
1738 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1739 {
1740   va_list ap;
1741   struct aim_userinfo_s *userinfo;
1742   int count = 0, i = 0;
1743   
1744   va_start(ap, command);
1745   count = va_arg(ap, int);
1746   userinfo = va_arg(ap, struct aim_userinfo_s *);
1747   va_end(ap);
1748
1749   dvprintf("faimtest: chat: %s:  Some occupants have left:\n", (char *)command->conn->priv);
1750
1751   for (i = 0; i < count; )
1752     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1753
1754   return 1;
1755 }
1756
1757 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1758 {
1759   va_list ap;
1760   struct aim_userinfo_s *userinfo;
1761   struct aim_chat_roominfo *roominfo;
1762   char *roomname;
1763   int usercount,i;
1764   char *roomdesc;
1765   unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1766   unsigned long creationtime;
1767
1768   va_start(ap, command);
1769   roominfo = va_arg(ap, struct aim_chat_roominfo *);
1770   roomname = va_arg(ap, char *);
1771   usercount= va_arg(ap, int);
1772   userinfo = va_arg(ap, struct aim_userinfo_s *);
1773   roomdesc = va_arg(ap, char *);
1774   unknown_c9 = va_arg(ap, int);
1775   creationtime = va_arg(ap, unsigned long);
1776   maxmsglen = va_arg(ap, int);
1777   unknown_d2 = va_arg(ap, int);
1778   unknown_d5 = va_arg(ap, int);
1779   va_end(ap);
1780
1781   dvprintf("faimtest: chat: %s:  info update:\n", (char *)command->conn->priv);
1782   dvprintf("faimtest: chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", 
1783          (char *)command->conn->priv,
1784          roominfo->exchange,
1785          roominfo->name,
1786          roominfo->instance);
1787   dvprintf("faimtest: chat: %s:  \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1788   dvprintf("faimtest: chat: %s:  \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1789   dvprintf("faimtest: chat: %s:  \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1790   
1791   for (i = 0; i < usercount; )
1792     dvprintf("faimtest: chat: %s:  \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1793
1794   dvprintf("faimtest: chat: %s:  \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1795   dvprintf("faimtest: chat: %s:  \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1796   dvprintf("faimtest: chat: %s:  \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
1797   dvprintf("faimtest: chat: %s:  \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
1798   dvprintf("faimtest: chat: %s:  \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
1799
1800   return 1;
1801 }
1802
1803 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1804 {
1805   va_list ap;
1806   struct aim_userinfo_s *userinfo;
1807   char *msg;
1808   char tmpbuf[1152];
1809  
1810   va_start(ap, command);
1811   userinfo = va_arg(ap, struct aim_userinfo_s *);       
1812   msg = va_arg(ap, char *);
1813   va_end(ap);
1814
1815   dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
1816
1817   /*
1818    * Do an echo for testing purposes.  But not for ourselves ("oops!")
1819    */
1820   if (strcmp(userinfo->sn, sess->sn) != 0)
1821     {
1822       sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
1823       aim_chat_send_im(sess, command->conn, 0, tmpbuf, strlen(tmpbuf));
1824     }
1825
1826   return 1;
1827 }
1828
1829 int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1830 {
1831   unsigned short type;
1832   va_list ap;
1833
1834   va_start(ap, command);
1835   type = va_arg(ap, int);
1836
1837   switch(type) {
1838   case 0x0002: {
1839     int maxrooms;
1840     struct aim_chat_exchangeinfo *exchanges;
1841     int exchangecount,i = 0;
1842     
1843     maxrooms = va_arg(ap, int);
1844     exchangecount = va_arg(ap, int);
1845     exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1846     va_end(ap);
1847     
1848     dprintf("faimtest: chat info: Chat Rights:\n");
1849     dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1850     
1851     dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
1852     for (i = 0; i < exchangecount; i++) {
1853       dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", 
1854                exchanges[i].number,     
1855                exchanges[i].name,
1856                exchanges[i].charset1,
1857                exchanges[i].lang1);
1858     }
1859     
1860   }
1861   break;
1862   case 0x0008: {
1863     char *fqcn, *name, *ck;
1864     unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1865     unsigned char createperms;
1866     unsigned long createtime;
1867
1868     fqcn = va_arg(ap, char *);
1869     instance = va_arg(ap, int);
1870     exchange = va_arg(ap, int);
1871     flags = va_arg(ap, int);
1872     createtime = va_arg(ap, unsigned long);
1873     maxmsglen = va_arg(ap, int);
1874     maxoccupancy = va_arg(ap, int);
1875     createperms = va_arg(ap, int);
1876     unknown = va_arg(ap, int);
1877     name = va_arg(ap, char *);
1878     ck = va_arg(ap, char *);
1879     va_end(ap);
1880
1881     dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange);
1882   }
1883   break;
1884   default:
1885     va_end(ap);
1886     dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
1887   }
1888   return 1;
1889 }
1890
1891 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1892 {
1893   va_list ap;
1894   unsigned short code;
1895   char *msg = NULL;
1896
1897   va_start(ap, command);
1898   code = va_arg(ap, int);
1899   msg = va_arg(ap, char *);
1900   va_end(ap);
1901
1902   dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
1903   aim_conn_kill(sess, &command->conn); /* this will break the main loop */
1904
1905   connected = 0;
1906
1907   return 1;
1908 }
1909
1910 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1911 {       
1912   dprintf("faimtest: connecting to an aimdebugd!\n");
1913
1914   /* convert the authorizer connection to a BOS connection */
1915   command->conn->type = AIM_CONN_TYPE_BOS;
1916
1917   aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1918
1919   /* tell the aimddebugd we're ready */
1920   aim_debugconn_sendconnect(sess, command->conn); 
1921
1922   /* go right into main loop (don't open a BOS connection, etc) */
1923   return 1;
1924 }
1925
1926 /*
1927  * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1928  */
1929 int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1930 {
1931   va_list ap;
1932   unsigned short type;
1933   char *sn = NULL;
1934
1935   va_start(ap, command);
1936   type = va_arg(ap, int);
1937   sn = va_arg(ap, char *);
1938   va_end(ap);
1939
1940   dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1941
1942   return 1;
1943 }
1944
1945 int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
1946 {
1947   va_list ap;
1948   struct aim_conn_t *oftconn;
1949   struct aim_fileheader_t *fh;
1950   char *cookie;
1951
1952   va_start(ap, command);
1953   oftconn = va_arg(ap, struct aim_conn_t *);
1954   fh = va_arg(ap, struct aim_fileheader_t *);
1955   cookie = va_arg(ap, char *);
1956   va_end(ap);
1957
1958   dvprintf("faimtest: request for file %s.\n", fh->name);
1959
1960   return 1;
1961 }
1962
1963
1964 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1965 {
1966   va_list ap;
1967   struct aim_conn_t *oftconn;
1968   struct aim_fileheader_t *fh;
1969   char *path, *cookie;
1970   int pos, bufpos = 0, bufsize = 2048, i;
1971   char *buf;
1972
1973   FILE *file;
1974
1975   va_start(ap, command);
1976   oftconn = va_arg(ap, struct aim_conn_t *);
1977   fh = va_arg(ap, struct aim_fileheader_t *);
1978   cookie = va_arg(ap, char *);
1979   va_end(ap);
1980
1981   dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
1982
1983   if(!(buf = malloc(2048)))
1984      return -1;
1985
1986   if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
1987     dperror("calloc");
1988     dprintf("faimtest: error in calloc of path\n");
1989     return 0; /* XXX: no idea what winaim expects here =) */
1990   }
1991   
1992   snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
1993
1994
1995   if( (file = fopen(path, "r")) == NULL) {
1996     dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
1997     return 0;
1998   }
1999
2000   /* 
2001    * This is a mess. Remember that faimtest is demonstration code
2002    * only and for the sake of the gods, don't use this code in any
2003    * of your clients. --mid
2004    */
2005   for(pos = 0; pos < fh->size; pos++) {
2006     bufpos = pos % bufsize;
2007
2008     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2009       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2010         dperror("faim: getfile_send: write1");
2011         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2012         free(buf);   
2013         return -1;
2014       }
2015     }
2016     if( (buf[bufpos] = fgetc(file)) == EOF) {
2017       if(pos != fh->size) {
2018         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2019         free(buf);   
2020         return -1;
2021       }
2022     }      
2023     dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
2024   }
2025
2026   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2027     dperror("faim: getfile_send: write2");
2028     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2029     free(buf);   
2030     return -1;
2031   }
2032
2033   free(buf);
2034   free(fh);  
2035   return 1;
2036 }
2037
2038 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) 
2039 {
2040   va_list ap;
2041   struct aim_conn_t *conn;
2042   struct aim_fileheader_t *fh;
2043
2044   va_start(ap, command);
2045   conn = va_arg(ap, struct aim_conn_t *);
2046   fh = va_arg(ap, struct aim_fileheader_t *);
2047   va_end(ap);
2048
2049   dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
2050
2051   aim_conn_close(conn);
2052   aim_conn_kill(sess, &conn);
2053   return 1;
2054 }
2055
2056 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2057 {
2058   va_list ap;
2059   struct aim_conn_t *conn;
2060   char *sn;
2061
2062   va_start(ap, command);
2063   conn = va_arg(ap, struct aim_conn_t *);
2064   sn = va_arg(ap, char *);
2065   va_end(ap);
2066
2067   aim_conn_kill(sess, &conn);
2068
2069   dvprintf("faimtest: getfile: disconnected from %s\n", sn);
2070   return 1;
2071 }
2072 int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2073 {
2074   va_list ap;
2075   struct aim_conn_t *conn, *listenerconn;
2076   struct aim_filetransfer_priv *priv;
2077
2078   va_start(ap, command);
2079   conn = va_arg(ap, struct aim_conn_t *);
2080   listenerconn = va_arg(ap, struct aim_conn_t *);
2081   va_end(ap);
2082
2083   aim_conn_close(listenerconn);
2084   aim_conn_kill(sess, &listenerconn);
2085
2086   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2087   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2088   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
2089   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
2090   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2091   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2092   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2093   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
2094   
2095   priv = (struct aim_filetransfer_priv *)conn->priv;
2096
2097   dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd);
2098   return 1;
2099 }
2100
2101 int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2102 {
2103   va_list ap;
2104   struct aim_conn_t *conn;
2105   char *listing;
2106   struct aim_filetransfer_priv *ft;
2107   char *filename, *nameend, *sizec;
2108   int filesize, namelen;
2109
2110   va_start(ap, command);
2111   conn = va_arg(ap, struct aim_conn_t *);
2112   ft = va_arg(ap, struct aim_filetransfer_priv *);
2113   listing = va_arg(ap, char *);
2114   va_end(ap);
2115
2116   dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
2117
2118   nameend = strstr(listing+0x1a, "\r");
2119
2120   namelen = nameend - (listing + 0x1a);
2121
2122   filename = malloc(namelen + 1);
2123   strncpy(filename, listing+0x1a, namelen);
2124   filename[namelen] = 0x00;
2125
2126   sizec = malloc(8+1);
2127   memcpy(sizec, listing + 0x11, 8);
2128   sizec[8] = 0x00;
2129
2130   filesize =  strtol(sizec, (char **)NULL, 10);
2131
2132   dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
2133
2134   aim_oft_getfile_request(sess, conn, filename, filesize);
2135
2136   free(filename);
2137   free(sizec);
2138
2139   return 0;
2140 }
2141
2142 int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2143 {
2144   va_list ap;
2145   struct aim_conn_t *oftconn;
2146   struct aim_fileheader_t *fh;
2147   int pos, bufpos = 0, bufsize = 2048, i;
2148   char *buf;
2149
2150   va_start(ap, command);
2151   oftconn = va_arg(ap, struct aim_conn_t *);
2152   fh = va_arg(ap, struct aim_fileheader_t *);
2153   va_end(ap);
2154
2155   dvprintf("faimtest: sending listing of size %ld\n", fh->size);
2156
2157   if(!(buf = malloc(2048)))
2158     return -1;
2159
2160   for(pos = 0; pos < fh->size; pos++) {
2161     bufpos = pos % bufsize;
2162
2163     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2164       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2165         dperror("faim: getfile_send: write1");
2166         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
2167         free(buf);   
2168         return -1;
2169       }
2170     }
2171     if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
2172       if(pos != fh->size) {
2173         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
2174         free(buf);   
2175         return -1;
2176       }
2177     }      
2178   }
2179
2180   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2181     dperror("faim: getfile_send: write2");
2182     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
2183     free(buf);   
2184     return -1;
2185   }
2186
2187   dprintf("faimtest: sent listing\n");
2188   free(buf);
2189   return 0;
2190 }
2191
2192 int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2193 {
2194   va_list ap;
2195   struct aim_conn_t *conn;
2196   struct aim_filetransfer_priv *ft;
2197   unsigned char data;
2198   int pos;
2199
2200   va_start(ap, command);
2201   conn = va_arg(ap, struct aim_conn_t *);
2202   ft = va_arg(ap, struct aim_filetransfer_priv *);
2203   va_end(ap);
2204
2205   dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
2206
2207   for(pos = 0; pos < ft->fh.size; pos++) {
2208     read(conn->fd, &data, 1);
2209     printf("%c(%02x) ", data, data);
2210   }
2211    
2212   printf("\n");
2213
2214   aim_oft_getfile_end(sess, conn);
2215
2216   return 0;
2217 }
2218
2219 int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2220 {
2221   va_list ap;
2222   struct aim_conn_t *conn;
2223
2224   va_start(ap, command);
2225   conn = va_arg(ap, struct aim_conn_t *);
2226   va_end(ap);
2227
2228   aim_conn_close(conn);
2229   aim_conn_kill(sess, &conn);
2230   return 0;
2231 }
2232
2233
2234 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2235 {
2236   static char *codes[5] = {"invalid",
2237                            "change",
2238                            "warning",
2239                            "limit",
2240                            "limit cleared"};
2241   va_list ap;
2242   int code;
2243   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
2244   unsigned long currentavg, maxavg;
2245
2246   va_start(ap, command); 
2247
2248   /* See code explanations below */
2249   code = va_arg(ap, int);
2250
2251   /*
2252    * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
2253    */
2254   rateclass = va_arg(ap, unsigned long);
2255
2256   /*
2257    * Not sure what this is exactly.  I think its the temporal 
2258    * relation factor (ie, how to make the rest of the numbers
2259    * make sense in the real world). 
2260    */
2261   windowsize = va_arg(ap, unsigned long);
2262
2263   /* Explained below */
2264   clear = va_arg(ap, unsigned long);
2265   alert = va_arg(ap, unsigned long);
2266   limit = va_arg(ap, unsigned long);
2267   disconnect = va_arg(ap, unsigned long);
2268   currentavg = va_arg(ap, unsigned long);
2269   maxavg = va_arg(ap, unsigned long);
2270
2271   va_end(ap);
2272
2273
2274   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",
2275          (code < 5)?codes[code]:"invalid",
2276          rateclass,
2277          currentavg, maxavg,
2278          alert, clear,
2279          limit, disconnect,
2280          windowsize);
2281
2282   if (code == AIM_RATE_CODE_CHANGE) {
2283     /*
2284      * Not real sure when these get sent.
2285      */
2286     if (currentavg >= clear)
2287       aim_conn_setlatency(command->conn, 0);
2288
2289   } else if (code == AIM_RATE_CODE_WARNING) {
2290     /*
2291      * We start getting WARNINGs the first time we go below the 'alert'
2292      * limit (currentavg < alert) and they stop when either we pause
2293      * long enough for currentavg to go above 'clear', or until we
2294      * flood it bad enough to go below 'limit' (and start getting
2295      * LIMITs instead) or even further and go below 'disconnect' and 
2296      * get disconnected completely (and won't be able to login right
2297      * away either).
2298      */
2299     aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ 
2300
2301   } else if (code == AIM_RATE_CODE_LIMIT) {
2302     /*
2303      * When we hit LIMIT, messages will start getting dropped.
2304      */
2305     aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ 
2306
2307   } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2308     /*
2309      * The limit is cleared when curavg goes above 'clear'.
2310      */
2311     aim_conn_setlatency(command->conn, 0); 
2312   }
2313
2314   return 1;
2315 }
2316
2317 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2318 {
2319   va_list ap;
2320   int newevil;
2321   struct aim_userinfo_s *userinfo;
2322
2323   va_start(ap, command);
2324   newevil = va_arg(ap, int);
2325   userinfo = va_arg(ap, struct aim_userinfo_s *);
2326   va_end(ap);
2327
2328   /*
2329    * Evil Notifications that are lacking userinfo->sn are anon-warns
2330    * if they are an evil increases, but are not warnings at all if its
2331    * a decrease (its the natural backoff happening).
2332    *
2333    * newevil is passed as an int representing the new evil value times
2334    * ten.
2335    */
2336   dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
2337
2338   return 1;
2339 }
2340
2341 int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2342 {
2343   va_list ap;
2344   char *address, *SNs;
2345   int i, num;
2346   
2347   va_start(ap, command);
2348   address = va_arg(ap, char *);
2349   num = va_arg(ap, int);
2350   SNs = va_arg(ap, char *);
2351   va_end(ap);
2352
2353   dvprintf("faimtest: E-Mail Search Results for %s: ", address);
2354
2355   for(i = 0; i < num; i++)
2356     dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2357   dinlineprintf("\n");
2358
2359   return 1;
2360 }
2361
2362 int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2363 {
2364   va_list ap;
2365   char *address;
2366   
2367   va_start(ap, command);
2368   address = va_arg(ap, char *);
2369   va_end(ap);
2370
2371   dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2372
2373   return 1;
2374 }
This page took 0.273753 seconds and 3 git commands to generate.