]> andersk Git - libfaim.git/blob - utils/faimtest/faimtest.c
454018f58592b0a7c1c7c7a6146afc171715029a
[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 *msg = NULL;
1249   struct aim_conn_t *conn;
1250   struct aim_directim_priv *priv;
1251
1252   va_start(ap, command);
1253   conn = va_arg(ap, struct aim_conn_t *);
1254   msg = va_arg(ap, char *);
1255   va_end(ap);
1256
1257   if(!(priv = conn->priv)) {
1258     dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd);
1259     return -1;
1260   }
1261
1262   dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg);
1263   if (!strncmp(msg, "sendmsg", 7)) {
1264     int i;
1265     i = atoi(msg+8);
1266     if (i < 10000) {
1267       char *newbuf;
1268       int z;
1269       
1270       newbuf = malloc(i+1);
1271       for (z = 0; z < i; z++) {
1272         newbuf[z] = (z % 10)+0x30;
1273       }
1274       newbuf[i] = '\0';
1275       aim_send_im_direct(sess, conn, newbuf);
1276       free(newbuf);
1277     }
1278   } else if (!strncmp(msg, "goodday", 7)) {
1279     aim_send_im_direct(sess, conn, "Good day to you, too");
1280   } else {
1281     char newmsg[1024];
1282     snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1283     aim_send_im_direct(sess, conn, newmsg);
1284   }
1285   return 1;
1286 }
1287
1288 int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1289 {
1290   va_list ap;
1291   struct aim_conn_t *conn;
1292   char *sn;
1293
1294   va_start(ap, command);
1295   conn = va_arg(ap, struct aim_conn_t *);
1296   sn = va_arg(ap, char *);
1297   va_end(ap);
1298
1299   dvprintf("faimtest: directim: disconnected from %s\n", sn);
1300
1301   aim_conn_kill(sess, &conn);
1302   return 1;
1303 }
1304
1305 int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1306 {
1307   va_list ap;
1308   struct aim_conn_t *conn;
1309   struct aim_directim_priv *priv;
1310
1311   va_start(ap, command);
1312   conn = va_arg(ap, struct aim_conn_t *);
1313   va_end(ap);
1314   
1315   if(!(priv = (struct aim_directim_priv *)conn->priv)) {
1316     dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd);
1317     return -1;
1318   }
1319
1320   dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
1321   return 1;
1322 }
1323
1324 int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1325 {
1326   unsigned short change = 0;
1327   int perms, type, length, str;
1328   char *val;
1329   va_list ap;
1330
1331   va_start(ap, command);
1332   perms = va_arg(ap, int);
1333   type = va_arg(ap, int);
1334   length = va_arg(ap, int);
1335   val = va_arg(ap, char *);
1336   str = va_arg(ap, int);
1337   va_end(ap);
1338
1339   if (aimutil_get16(command->data+2) == 0x0005)
1340     change = 1;
1341
1342   dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1343
1344   return 1;
1345 }
1346
1347 int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1348 {
1349   struct aim_userinfo_s *userinfo;
1350    
1351   va_list ap;
1352   va_start(ap, command);
1353   userinfo = va_arg(ap, struct aim_userinfo_s *);
1354   va_end(ap);
1355
1356   dvprintf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1357          time(NULL),
1358          userinfo->sn, userinfo->flags,
1359          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1360          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1361          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1362          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1363          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1364          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1365          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1366          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1367          userinfo->capabilities);
1368   return 1;
1369 }
1370
1371 int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1372 {
1373   char *sn;
1374   va_list ap;
1375   
1376   va_start(ap, command);
1377   sn = va_arg(ap, char *);
1378   va_end(ap);
1379
1380   dvprintf("\n%s has left\n", sn);
1381
1382   return 1;
1383 }
1384
1385 int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1386 {
1387   static char *codes[] = {
1388     "Unknown",
1389     "Mandatory upgrade",
1390     "Advisory upgrade",
1391     "System bulletin",
1392     "Top o' the world!"};
1393   static int codeslen = 5;
1394
1395   char *msg;
1396   unsigned short id;
1397   va_list ap;
1398   
1399   va_start(ap, command);
1400   id = va_arg(ap, int);
1401   msg = va_arg(ap, char *);
1402   va_end(ap);
1403
1404   dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, 
1405            (id < codeslen)?codes[id]:"unknown");
1406
1407   if (!connected)
1408     connected++;
1409
1410   return 1;
1411 }
1412
1413 int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1414 {
1415   va_list ap;
1416   unsigned short reason;
1417
1418   va_start(ap, command);
1419   reason = va_arg(ap, int);
1420   va_end(ap);
1421
1422   dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1423   
1424   return 1;
1425 }
1426
1427 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1428 {
1429   va_list ap;
1430   char *destsn;
1431   unsigned short reason;
1432
1433   va_start(ap, command);
1434   destsn = va_arg(ap, char *);
1435   reason = va_arg(ap, int);
1436   va_end(ap);
1437
1438   dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1439   
1440   return 1;
1441 }
1442
1443 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1444 {
1445   va_list ap;
1446   char *destsn;
1447   unsigned short reason;
1448
1449   va_start(ap, command);
1450   destsn = va_arg(ap, char *);
1451   reason = va_arg(ap, int);
1452   va_end(ap);
1453
1454   dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1455   
1456   return 1;
1457 }
1458
1459 /* 
1460  * Handles callbacks for AIM_CB_MISSED_CALL.
1461  */
1462 int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1463 {
1464   static char *missedreasons[] = {
1465     "Unknown",
1466     "Message too large"};
1467   static int missedreasonslen = 2;
1468
1469   va_list ap;
1470   unsigned short chan, nummissed, reason;
1471   struct aim_userinfo_s *userinfo;
1472   
1473   va_start(ap, command);
1474   chan = va_arg(ap, int);
1475   userinfo = va_arg(ap, struct aim_userinfo_s *);
1476   nummissed = va_arg(ap, int);
1477   reason = va_arg(ap, int);
1478   va_end(ap);
1479
1480   dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1481   
1482   return 1;
1483 }
1484
1485 int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1486 {
1487   struct client_info_s info = {"faimtest (with SNAC login)", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x0000004b}; /* 4.1.2010 */
1488   char *key;
1489   va_list ap;
1490   
1491   va_start(ap, command);
1492   key = va_arg(ap, char *);
1493   va_end(ap);
1494
1495   aim_send_login(sess, command->conn, screenname, password, &info, key);
1496  
1497   return 1;
1498 }
1499
1500 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1501 {
1502   va_list ap;
1503   struct aim_userinfo_s *userinfo;
1504   int count = 0, i = 0;
1505   
1506   va_start(ap, command);
1507   count = va_arg(ap, int);
1508   userinfo = va_arg(ap, struct aim_userinfo_s *);
1509   va_end(ap);
1510
1511   dvprintf("faimtest: chat: %s:  New occupants have joined:\n", (char *)command->conn->priv);
1512   while (i < count)
1513     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1514
1515   return 1;
1516 }
1517
1518 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1519 {
1520   va_list ap;
1521   struct aim_userinfo_s *userinfo;
1522   int count = 0, i = 0;
1523   
1524   va_start(ap, command);
1525   count = va_arg(ap, int);
1526   userinfo = va_arg(ap, struct aim_userinfo_s *);
1527   va_end(ap);
1528
1529   dvprintf("faimtest: chat: %s:  Some occupants have left:\n", (char *)command->conn->priv);
1530
1531   for (i = 0; i < count; )
1532     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1533
1534   return 1;
1535 }
1536
1537 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1538 {
1539   va_list ap;
1540   struct aim_userinfo_s *userinfo;
1541   struct aim_chat_roominfo *roominfo;
1542   char *roomname;
1543   int usercount,i;
1544   char *roomdesc;
1545   unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1546   unsigned long creationtime;
1547
1548   va_start(ap, command);
1549   roominfo = va_arg(ap, struct aim_chat_roominfo *);
1550   roomname = va_arg(ap, char *);
1551   usercount= va_arg(ap, int);
1552   userinfo = va_arg(ap, struct aim_userinfo_s *);
1553   roomdesc = va_arg(ap, char *);
1554   unknown_c9 = va_arg(ap, int);
1555   creationtime = va_arg(ap, unsigned long);
1556   maxmsglen = va_arg(ap, int);
1557   unknown_d2 = va_arg(ap, int);
1558   unknown_d5 = va_arg(ap, int);
1559   va_end(ap);
1560
1561   dvprintf("faimtest: chat: %s:  info update:\n", (char *)command->conn->priv);
1562   dvprintf("faimtest: chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", 
1563          (char *)command->conn->priv,
1564          roominfo->exchange,
1565          roominfo->name,
1566          roominfo->instance);
1567   dvprintf("faimtest: chat: %s:  \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1568   dvprintf("faimtest: chat: %s:  \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1569   dvprintf("faimtest: chat: %s:  \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1570   
1571   for (i = 0; i < usercount; )
1572     dvprintf("faimtest: chat: %s:  \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1573
1574   dvprintf("faimtest: chat: %s:  \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1575   dvprintf("faimtest: chat: %s:  \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1576   dvprintf("faimtest: chat: %s:  \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
1577   dvprintf("faimtest: chat: %s:  \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
1578   dvprintf("faimtest: chat: %s:  \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
1579
1580   return 1;
1581 }
1582
1583 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1584 {
1585   va_list ap;
1586   struct aim_userinfo_s *userinfo;
1587   char *msg;
1588   char tmpbuf[1152];
1589  
1590   va_start(ap, command);
1591   userinfo = va_arg(ap, struct aim_userinfo_s *);       
1592   msg = va_arg(ap, char *);
1593   va_end(ap);
1594
1595   dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
1596
1597   /*
1598    * Do an echo for testing purposes.  But not for ourselves ("oops!")
1599    */
1600   if (strcmp(userinfo->sn, sess->sn) != 0)
1601     {
1602       sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
1603       aim_chat_send_im(sess, command->conn, tmpbuf);
1604     }
1605
1606   return 1;
1607 }
1608
1609 int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1610 {
1611   unsigned short type;
1612   va_list ap;
1613
1614   va_start(ap, command);
1615   type = va_arg(ap, int);
1616
1617   switch(type) {
1618   case 0x0002: {
1619     int maxrooms;
1620     struct aim_chat_exchangeinfo *exchanges;
1621     int exchangecount,i = 0;
1622     
1623     maxrooms = va_arg(ap, int);
1624     exchangecount = va_arg(ap, int);
1625     exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1626     va_end(ap);
1627     
1628     dprintf("faimtest: chat info: Chat Rights:\n");
1629     dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1630     
1631     dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
1632     for (i = 0; i < exchangecount; i++) {
1633       dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", 
1634                exchanges[i].number,     
1635                exchanges[i].name,
1636                exchanges[i].charset1,
1637                exchanges[i].lang1);
1638     }
1639     
1640   }
1641   break;
1642   case 0x0008: {
1643     char *fqcn, *name, *ck;
1644     unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1645     unsigned char createperms;
1646     unsigned long createtime;
1647
1648     fqcn = va_arg(ap, char *);
1649     instance = va_arg(ap, int);
1650     exchange = va_arg(ap, int);
1651     flags = va_arg(ap, int);
1652     createtime = va_arg(ap, unsigned long);
1653     maxmsglen = va_arg(ap, int);
1654     maxoccupancy = va_arg(ap, int);
1655     createperms = va_arg(ap, int);
1656     unknown = va_arg(ap, int);
1657     name = va_arg(ap, char *);
1658     ck = va_arg(ap, char *);
1659     va_end(ap);
1660
1661     dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange);
1662   }
1663   break;
1664   default:
1665     va_end(ap);
1666     dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
1667   }
1668   return 1;
1669 }
1670
1671 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1672 {
1673   va_list ap;
1674   unsigned short code;
1675   char *msg = NULL;
1676
1677   va_start(ap, command);
1678   code = va_arg(ap, int);
1679   msg = va_arg(ap, char *);
1680   va_end(ap);
1681
1682   dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
1683   aim_conn_kill(sess, &command->conn); /* this will break the main loop */
1684
1685   return 1;
1686 }
1687
1688 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1689 {       
1690   dprintf("faimtest: connecting to an aimdebugd!\n");
1691
1692   /* convert the authorizer connection to a BOS connection */
1693   command->conn->type = AIM_CONN_TYPE_BOS;
1694
1695   aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1696
1697   /* tell the aimddebugd we're ready */
1698   aim_debugconn_sendconnect(sess, command->conn); 
1699
1700   /* go right into main loop (don't open a BOS connection, etc) */
1701   return 1;
1702 }
1703
1704 /*
1705  * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1706  */
1707 int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1708 {
1709   va_list ap;
1710   unsigned short type;
1711   char *sn = NULL;
1712
1713   va_start(ap, command);
1714   type = va_arg(ap, int);
1715   sn = va_arg(ap, char *);
1716   va_end(ap);
1717
1718   dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1719
1720   return 1;
1721 }
1722
1723 int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
1724 {
1725   va_list ap;
1726   struct aim_conn_t *oftconn;
1727   struct aim_fileheader_t *fh;
1728   char *cookie;
1729
1730   va_start(ap, command);
1731   oftconn = va_arg(ap, struct aim_conn_t *);
1732   fh = va_arg(ap, struct aim_fileheader_t *);
1733   cookie = va_arg(ap, char *);
1734   va_end(ap);
1735
1736   dvprintf("faimtest: request for file %s.\n", fh->name);
1737
1738   return 1;
1739 }
1740
1741
1742 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1743 {
1744   va_list ap;
1745   struct aim_conn_t *oftconn;
1746   struct aim_fileheader_t *fh;
1747   char *path, *cookie;
1748   int pos, bufpos = 0, bufsize = 2048, i;
1749   char *buf;
1750
1751   FILE *file;
1752
1753   va_start(ap, command);
1754   oftconn = va_arg(ap, struct aim_conn_t *);
1755   fh = va_arg(ap, struct aim_fileheader_t *);
1756   cookie = va_arg(ap, char *);
1757   va_end(ap);
1758
1759   dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
1760
1761   if(!(buf = malloc(2048)))
1762      return -1;
1763
1764   if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
1765     dperror("calloc");
1766     dprintf("faimtest: error in calloc of path\n");
1767     return 0; /* XXX: no idea what winaim expects here =) */
1768   }
1769   
1770   snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
1771
1772
1773   if( (file = fopen(path, "r")) == NULL) {
1774     dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
1775     return 0;
1776   }
1777
1778   /* 
1779    * This is a mess. Remember that faimtest is demonstration code
1780    * only and for the sake of the gods, don't use this code in any
1781    * of your clients. --mid
1782    */
1783   for(pos = 0; pos < fh->size; pos++) {
1784     bufpos = pos % bufsize;
1785
1786     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1787       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
1788         dperror("faim: getfile_send: write1");
1789         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
1790         free(buf);   
1791         return -1;
1792       }
1793     }
1794     if( (buf[bufpos] = fgetc(file)) == EOF) {
1795       if(pos != fh->size) {
1796         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1797         free(buf);   
1798         return -1;
1799       }
1800     }      
1801     dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
1802   }
1803
1804   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
1805     dperror("faim: getfile_send: write2");
1806     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1807     free(buf);   
1808     return -1;
1809   }
1810
1811   free(buf);
1812   free(fh);  
1813   return 1;
1814 }
1815
1816 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) 
1817 {
1818   va_list ap;
1819   struct aim_conn_t *conn;
1820   struct aim_fileheader_t *fh;
1821
1822   va_start(ap, command);
1823   conn = va_arg(ap, struct aim_conn_t *);
1824   fh = va_arg(ap, struct aim_fileheader_t *);
1825   va_end(ap);
1826
1827   dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
1828
1829   aim_conn_close(conn);
1830   aim_conn_kill(sess, &conn);
1831   return 1;
1832 }
1833
1834 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1835 {
1836   va_list ap;
1837   struct aim_conn_t *conn;
1838   char *sn;
1839
1840   va_start(ap, command);
1841   conn = va_arg(ap, struct aim_conn_t *);
1842   sn = va_arg(ap, char *);
1843   va_end(ap);
1844
1845   aim_conn_kill(sess, &conn);
1846
1847   dvprintf("faimtest: getfile: disconnected from %s\n", sn);
1848   return 1;
1849 }
1850 int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1851 {
1852   va_list ap;
1853   struct aim_conn_t *conn, *listenerconn;
1854   struct aim_filetransfer_priv *priv;
1855
1856   va_start(ap, command);
1857   conn = va_arg(ap, struct aim_conn_t *);
1858   listenerconn = va_arg(ap, struct aim_conn_t *);
1859   va_end(ap);
1860
1861   aim_conn_close(listenerconn);
1862   aim_conn_kill(sess, &listenerconn);
1863
1864   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
1865   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1866   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
1867   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
1868   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
1869   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1870   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
1871   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
1872   
1873   priv = (struct aim_filetransfer_priv *)conn->priv;
1874
1875   dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd);
1876   return 1;
1877 }
1878
1879 int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1880 {
1881   va_list ap;
1882   struct aim_conn_t *conn;
1883   char *listing;
1884   struct aim_filetransfer_priv *ft;
1885   char *filename, *nameend, *sizec;
1886   int filesize, namelen;
1887
1888   va_start(ap, command);
1889   conn = va_arg(ap, struct aim_conn_t *);
1890   ft = va_arg(ap, struct aim_filetransfer_priv *);
1891   listing = va_arg(ap, char *);
1892   va_end(ap);
1893
1894   dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
1895
1896   nameend = strstr(listing+0x1a, "\r");
1897
1898   namelen = nameend - (listing + 0x1a);
1899
1900   filename = malloc(namelen + 1);
1901   strncpy(filename, listing+0x1a, namelen);
1902   filename[namelen] = 0x00;
1903
1904   sizec = malloc(8+1);
1905   memcpy(sizec, listing + 0x11, 8);
1906   sizec[8] = 0x00;
1907
1908   filesize =  strtol(sizec, (char **)NULL, 10);
1909
1910   dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
1911
1912   aim_oft_getfile_request(sess, conn, filename, filesize);
1913
1914   free(filename);
1915   free(sizec);
1916
1917   return 0;
1918 }
1919
1920 int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1921 {
1922   va_list ap;
1923   struct aim_conn_t *oftconn;
1924   struct aim_fileheader_t *fh;
1925   int pos, bufpos = 0, bufsize = 2048, i;
1926   char *buf;
1927
1928   va_start(ap, command);
1929   oftconn = va_arg(ap, struct aim_conn_t *);
1930   fh = va_arg(ap, struct aim_fileheader_t *);
1931   va_end(ap);
1932
1933   dvprintf("faimtest: sending listing of size %ld\n", fh->size);
1934
1935   if(!(buf = malloc(2048)))
1936     return -1;
1937
1938   for(pos = 0; pos < fh->size; pos++) {
1939     bufpos = pos % bufsize;
1940
1941     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1942       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
1943         dperror("faim: getfile_send: write1");
1944         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
1945         free(buf);   
1946         return -1;
1947       }
1948     }
1949     if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
1950       if(pos != fh->size) {
1951         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1952         free(buf);   
1953         return -1;
1954       }
1955     }      
1956   }
1957
1958   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
1959     dperror("faim: getfile_send: write2");
1960     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1961     free(buf);   
1962     return -1;
1963   }
1964
1965   dprintf("faimtest: sent listing\n");
1966   free(buf);
1967   return 0;
1968 }
1969
1970 int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1971 {
1972   va_list ap;
1973   struct aim_conn_t *conn;
1974   struct aim_filetransfer_priv *ft;
1975   unsigned char data;
1976   int pos;
1977
1978   va_start(ap, command);
1979   conn = va_arg(ap, struct aim_conn_t *);
1980   ft = va_arg(ap, struct aim_filetransfer_priv *);
1981   va_end(ap);
1982
1983   dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
1984
1985   for(pos = 0; pos < ft->fh.size; pos++) {
1986     read(conn->fd, &data, 1);
1987     printf("%c(%02x) ", data, data);
1988   }
1989    
1990   printf("\n");
1991
1992   aim_oft_getfile_end(sess, conn);
1993
1994   return 0;
1995 }
1996
1997 int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1998 {
1999   va_list ap;
2000   struct aim_conn_t *conn;
2001
2002   va_start(ap, command);
2003   conn = va_arg(ap, struct aim_conn_t *);
2004   va_end(ap);
2005
2006   aim_conn_close(conn);
2007   aim_conn_kill(sess, &conn);
2008   return 0;
2009 }
2010
2011
2012 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2013 {
2014   static char *codes[5] = {"invalid",
2015                            "change",
2016                            "warning",
2017                            "limit",
2018                            "limit cleared"};
2019   va_list ap;
2020   int code;
2021   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
2022   unsigned long currentavg, maxavg;
2023
2024   va_start(ap, command); 
2025
2026   /* See code explanations below */
2027   code = va_arg(ap, int);
2028
2029   /*
2030    * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
2031    */
2032   rateclass = va_arg(ap, unsigned long);
2033
2034   /*
2035    * Not sure what this is exactly.  I think its the temporal 
2036    * relation factor (ie, how to make the rest of the numbers
2037    * make sense in the real world). 
2038    */
2039   windowsize = va_arg(ap, unsigned long);
2040
2041   /* Explained below */
2042   clear = va_arg(ap, unsigned long);
2043   alert = va_arg(ap, unsigned long);
2044   limit = va_arg(ap, unsigned long);
2045   disconnect = va_arg(ap, unsigned long);
2046   currentavg = va_arg(ap, unsigned long);
2047   maxavg = va_arg(ap, unsigned long);
2048
2049   va_end(ap);
2050
2051
2052   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",
2053          (code < 5)?codes[code]:"invalid",
2054          rateclass,
2055          currentavg, maxavg,
2056          alert, clear,
2057          limit, disconnect,
2058          windowsize);
2059
2060   if (code == AIM_RATE_CODE_CHANGE) {
2061     /*
2062      * Not real sure when these get sent.
2063      */
2064     if (currentavg >= clear)
2065       aim_conn_setlatency(command->conn, 0);
2066
2067   } else if (code == AIM_RATE_CODE_WARNING) {
2068     /*
2069      * We start getting WARNINGs the first time we go below the 'alert'
2070      * limit (currentavg < alert) and they stop when either we pause
2071      * long enough for currentavg to go above 'clear', or until we
2072      * flood it bad enough to go below 'limit' (and start getting
2073      * LIMITs instead) or even further and go below 'disconnect' and 
2074      * get disconnected completely (and won't be able to login right
2075      * away either).
2076      */
2077     aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ 
2078
2079   } else if (code == AIM_RATE_CODE_LIMIT) {
2080     /*
2081      * When we hit LIMIT, messages will start getting dropped.
2082      */
2083     aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ 
2084
2085   } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2086     /*
2087      * The limit is cleared when curavg goes above 'clear'.
2088      */
2089     aim_conn_setlatency(command->conn, 0); 
2090   }
2091
2092   return 1;
2093 }
2094
2095 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2096 {
2097   va_list ap;
2098   int newevil;
2099   struct aim_userinfo_s *userinfo;
2100
2101   va_start(ap, command);
2102   newevil = va_arg(ap, int);
2103   userinfo = va_arg(ap, struct aim_userinfo_s *);
2104   va_end(ap);
2105
2106   /*
2107    * Evil Notifications that are lacking userinfo->sn are anon-warns
2108    * if they are an evil increases, but are not warnings at all if its
2109    * a decrease (its the natural backoff happening).
2110    *
2111    * newevil is passed as an int representing the new evil value times
2112    * ten.
2113    */
2114   dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
2115
2116   return 1;
2117 }
2118
2119 int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2120 {
2121   va_list ap;
2122   char *address, *SNs;
2123   int i, num;
2124   
2125   va_start(ap, command);
2126   address = va_arg(ap, char *);
2127   num = va_arg(ap, int);
2128   SNs = va_arg(ap, char *);
2129   va_end(ap);
2130
2131   dvprintf("faimtest: E-Mail Search Results for %s: ", address);
2132
2133   for(i = 0; i < num; i++)
2134     dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2135   dinlineprintf("\n");
2136
2137   return 1;
2138 }
2139
2140 int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2141 {
2142   va_list ap;
2143   char *address;
2144   
2145   va_start(ap, command);
2146   address = va_arg(ap, char *);
2147   va_end(ap);
2148
2149   dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2150
2151   return 1;
2152 }
This page took 0.837494 seconds and 3 git commands to generate.