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