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