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