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