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