]> andersk Git - libfaim.git/blob - utils/faimtest/faimtest.c
Rearrange.
[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     
918     userinfo = va_arg(ap, struct aim_userinfo_s *);
919     msg = va_arg(ap, char *);
920     icbmflags = va_arg(ap, u_int);
921     flag1 = va_arg(ap, int);
922     flag2 = va_arg(ap, int);
923     va_end(ap);
924     
925     dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
926     dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
927     dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
928     printuserflags(userinfo->flags);
929     dinlineprintf("\n");
930
931     dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
932     dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
933     dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
934     dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
935     
936     dprintf("faimtest: icbm: icbmflags = ");
937     if (icbmflags & AIM_IMFLAGS_AWAY)
938       dinlineprintf("away ");
939     if (icbmflags & AIM_IMFLAGS_ACK)
940       dinlineprintf("ackrequest ");
941     dinlineprintf("\n");
942     
943     dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", flag1, flag2);
944     
945     dvprintf("faimtest: icbm: message: %s\n", msg);
946     
947     if (msg) {
948       int i = 0;
949
950       while (msg[i] == '<') {
951         if (msg[i] == '<') {
952           while (msg[i] != '>')
953             i++;
954           i++;
955         }
956       }
957       tmpstr = msg+i;
958
959       dvprintf("tmpstr = %s\n", tmpstr);
960       
961       if ( (strlen(tmpstr) >= 10) &&
962            (!strncmp(tmpstr, "disconnect", 10)) ) {
963         if (ohcaptainmycaptain)
964           aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "ta ta...");
965         aim_logoff(sess);
966       } else if (strstr(tmpstr, "goodday")) {
967         dprintf("faimtest: icbm: sending response\n");
968         aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
969       } else if (strstr(tmpstr, "warnme")) {
970         dprintf("faimtest: icbm: sending non-anon warning\n");
971         aim_send_warning(sess, command->conn, userinfo->sn, 0);
972       } else if (strstr(tmpstr, "anonwarn")) {
973         dprintf("faimtest: icbm: sending anon warning\n");
974         aim_send_warning(sess, command->conn, userinfo->sn, AIM_WARN_ANON);
975       } else if (strstr(tmpstr, "setdirectoryinfo")) {
976         dprintf("faimtest: icbm: sending backwards profile data\n");
977         aim_setdirectoryinfo(sess, command->conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
978       } else if (strstr(tmpstr, "setinterests")) {
979         dprintf("faimtest: icbm: setting fun interests\n");
980         aim_setuserinterests(sess, command->conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
981       } else if (!strncmp(tmpstr, "getfile", 7)) {
982         if (!ohcaptainmycaptain) {
983           aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
984         } else {
985           struct aim_conn_t *newconn;
986           newconn = aim_getfile_initiate(sess, command->conn, (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
987           dvprintf("faimtest: getting file listing from %s\n", (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8);
988           aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
989         }
990       } else if (!strncmp(tmpstr, "open chatnav", 12)) {
991         aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
992       } else if (!strncmp(tmpstr, "create", 6)) {
993         aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
994       } else if (!strncmp(tmpstr, "close chatnav", 13)) {
995         struct aim_conn_t *chatnavconn;
996         chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV);
997         aim_conn_kill(sess, &chatnavconn);
998       } else if (!strncmp(tmpstr, "join", 4)) {
999           aim_chat_join(sess, command->conn, 0x0004, "worlddomination");
1000       } else if (!strncmp(tmpstr, "leave", 5))
1001             aim_chat_leaveroom(sess, "worlddomination");
1002       else if (!strncmp(tmpstr, "getinfo", 7)) {
1003         aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
1004         aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
1005       } else if (!strncmp(tmpstr, "open directim", 13)) {
1006         struct aim_conn_t *newconn;
1007         newconn = aim_directim_initiate(sess, command->conn, NULL, userinfo->sn);
1008       } else if(!(strncmp(tmpstr, "lookup", 6))) {
1009         aim_usersearch_address(sess, command->conn, tmpstr+7);
1010       } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1011         aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900");
1012       } else if (!strncmp(tmpstr, "reqauth", 7)) {
1013         aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_AUTH);
1014       } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1015         aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1016       } else if (!strncmp(tmpstr, "reqemail", 8)) {
1017         aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1018       } else if (!strncmp(tmpstr, "changepass", 8)) {
1019         aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1020       } else if (!strncmp(tmpstr, "setemail", 8)) {
1021         aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1022       } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1023         int i;
1024         i = atoi(tmpstr+8);
1025         if (i < 10000) {
1026           char *newbuf;
1027           int z;
1028
1029           newbuf = malloc(i+1);
1030           for (z = 0; z < i; z++) {
1031             newbuf[z] = (z % 10)+0x30;
1032           }
1033           newbuf[i] = '\0';
1034           aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf);
1035           free(newbuf);
1036         }
1037       } else {
1038         dprintf("unknown command.\n");
1039         aim_add_buddy(sess, command->conn, userinfo->sn);
1040       }
1041       
1042     }
1043   }
1044   /*
1045    * Channel 2: Rendevous Request
1046    */
1047   else if (channel == 2) {
1048     struct aim_userinfo_s *userinfo;
1049     unsigned short reqclass;
1050     
1051     reqclass = va_arg(ap, int);
1052     switch (reqclass) {
1053     case AIM_CAPS_VOICE: {
1054       userinfo = va_arg(ap, struct aim_userinfo_s *);
1055       va_end(ap);
1056       
1057       dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
1058       dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1059       dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
1060       printuserflags(userinfo->flags);
1061       dinlineprintf("\n");
1062
1063       /* we dont get membersince on chat invites! */
1064       dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1065       dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1066       
1067       break;
1068     }
1069     case AIM_CAPS_GETFILE: {
1070 #ifdef FILESUPPORT
1071       char *ip, *cookie;
1072       struct aim_conn_t *newconn;
1073       struct aim_fileheader_t *fh;
1074
1075       userinfo = va_arg(ap, struct aim_userinfo_s *);
1076       ip = va_arg(ap, char *);
1077       cookie = va_arg(ap, char *);
1078       va_end(ap);
1079       
1080       dvprintf("faimtest: get file request from %s (at %s)\n", userinfo->sn, ip);
1081
1082       fh = aim_getlisting(listingfile);      
1083
1084       if( (newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, cookie, ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, reqclass)) == NULL ) {
1085         dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n");
1086         break;
1087       }
1088
1089       free(fh);
1090
1091       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1092       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
1093       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1094       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
1095
1096       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
1097
1098       dprintf("faimtest: getfile connect succeeded, handlers added.\n");
1099
1100       break;
1101 #endif
1102     }
1103     case AIM_CAPS_SENDFILE: {
1104       dprintf("faimtest: send file!\n");
1105       break;
1106     }
1107     case AIM_CAPS_CHAT: {
1108       char *msg,*encoding,*lang;
1109       struct aim_chat_roominfo *roominfo;
1110       
1111       userinfo = va_arg(ap, struct aim_userinfo_s *);
1112       roominfo = va_arg(ap, struct aim_chat_roominfo *);
1113       msg = va_arg(ap, char *);
1114       encoding = va_arg(ap, char *);
1115       lang = va_arg(ap, char *);
1116       va_end(ap);
1117       
1118       dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
1119       dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
1120       dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
1121       printuserflags(userinfo->flags);
1122       dinlineprintf("\n");
1123
1124       /* we dont get membersince on chat invites! */
1125       dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
1126       dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
1127       
1128       dvprintf("faimtest: chat invitation: message = %s\n", msg);
1129       dvprintf("faimtest: chat invitation: room name = %s\n", roominfo->name);
1130       dvprintf("faimtest: chat invitation: encoding = %s\n", encoding);
1131       dvprintf("faimtest: chat invitation: language = %s\n", lang);
1132       dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", roominfo->exchange);
1133       dvprintf("faimtest: chat invitation: instance = 0x%04x\n", roominfo->instance);
1134       dvprintf("faimtest: chat invitiation: autojoining %s...\n", roominfo->name);
1135       /*
1136        * Automatically join room...
1137        */ 
1138       aim_chat_join(sess, command->conn, 0x0004, roominfo->name);
1139       break;
1140     }   
1141     case AIM_CAPS_IMIMAGE: {
1142       struct aim_directim_priv *priv;
1143       struct aim_conn_t *newconn;
1144
1145       dprintf("faimtest: icbm: rendezvous imimage\n");
1146      
1147       userinfo = va_arg(ap, struct aim_userinfo_s *);
1148       priv = va_arg(ap, struct aim_directim_priv *);
1149       va_end(ap);
1150
1151       dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, priv->ip);
1152       
1153       if (!(newconn = aim_directim_connect(sess, command->conn, priv))) {
1154         dprintf("faimtest: icbm: imimage: could not connect\n");
1155         break;
1156       }
1157       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1158       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1159       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1160
1161       dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn);
1162
1163       aim_send_im_direct(sess, newconn, "goodday");
1164
1165       break;
1166     }
1167     default:
1168       dvprintf("faimtest: icbm: unknown reqclass (%d)\n", reqclass);
1169     } /* switch */
1170   } else
1171     dvprintf("faimtest does not support channels > 2 (chan = %02x)\n", channel);
1172   dprintf("faimtest: icbm: done with ICBM handling\n");
1173
1174   return 1;
1175 }
1176
1177 int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1178 {
1179   va_list ap;
1180   struct aim_directim_priv *priv;
1181   struct aim_conn_t *newconn;
1182
1183   va_start(ap, command);
1184   newconn = va_arg(ap, struct aim_conn_t *);
1185   va_end(ap);
1186
1187   priv = (struct aim_directim_priv *)newconn->priv;
1188
1189   dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip);
1190   
1191   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1192   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1193   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1194
1195   aim_send_im_direct(sess, newconn, "goodday");
1196
1197   dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn);
1198
1199   return 1;
1200 }
1201
1202 int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1203 {
1204   va_list ap;
1205   struct aim_directim_priv *priv;
1206   
1207   va_start(ap, command);
1208   priv = va_arg(ap, struct aim_directim_priv *);
1209
1210   va_end(ap);
1211   
1212   dprintf("faimtest: directim_connect\n");
1213
1214   return 1;
1215 }
1216
1217 int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1218 {
1219   va_list ap;
1220   char *sn = NULL, *msg = NULL;
1221   struct aim_conn_t *conn;
1222
1223   va_start(ap, command);
1224   conn = va_arg(ap, struct aim_conn_t *);
1225   sn = va_arg(ap, char *);
1226   msg = va_arg(ap, char *);
1227   va_end(ap);
1228
1229   dvprintf("faimtest: Directim from %s: %s\n", sn, msg);
1230   if (!strncmp(msg, "sendmsg", 7)) {
1231     int i;
1232     i = atoi(msg+8);
1233     if (i < 10000) {
1234       char *newbuf;
1235       int z;
1236       
1237       newbuf = malloc(i+1);
1238       for (z = 0; z < i; z++) {
1239         newbuf[z] = (z % 10)+0x30;
1240       }
1241       newbuf[i] = '\0';
1242       aim_send_im_direct(sess, conn, newbuf);
1243       free(newbuf);
1244     }
1245   } else if (!strncmp(msg, "goodday", 7)) {
1246     aim_send_im_direct(sess, conn, "Good day to you, too");
1247   } else {
1248     char newmsg[1024];
1249     snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1250     aim_send_im_direct(sess, conn, newmsg);
1251   }
1252   return 1;
1253 }
1254
1255 int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1256 {
1257   va_list ap;
1258   struct aim_conn_t *conn;
1259   char *sn;
1260
1261   va_start(ap, command);
1262   conn = va_arg(ap, struct aim_conn_t *);
1263   sn = va_arg(ap, char *);
1264   va_end(ap);
1265
1266   dvprintf("faimtest: directim: disconnected from %s\n", sn);
1267
1268   aim_conn_kill(sess, &conn);
1269   return 1;
1270 }
1271
1272 int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1273 {
1274   va_list ap;
1275   char *sn;
1276   
1277   va_start(ap, command);
1278   sn = va_arg(ap, char *);
1279   va_end(ap);
1280
1281   dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn);
1282   return 1;
1283 }
1284
1285 int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1286 {
1287   unsigned short change = 0;
1288   int perms, type, length, str;
1289   char *val;
1290   va_list ap;
1291
1292   va_start(ap, command);
1293   perms = va_arg(ap, int);
1294   type = va_arg(ap, int);
1295   length = va_arg(ap, int);
1296   val = va_arg(ap, char *);
1297   str = va_arg(ap, int);
1298   va_end(ap);
1299
1300   if (aimutil_get16(command->data+2) == 0x0005)
1301     change = 1;
1302
1303   dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)");
1304
1305   return 1;
1306 }
1307
1308 int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1309 {
1310   struct aim_userinfo_s *userinfo;
1311    
1312   va_list ap;
1313   va_start(ap, command);
1314   userinfo = va_arg(ap, struct aim_userinfo_s *);
1315   va_end(ap);
1316
1317   dvprintf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1318          time(NULL),
1319          userinfo->sn, userinfo->flags,
1320          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1321          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1322          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1323          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1324          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1325          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1326          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1327          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1328          userinfo->capabilities);
1329   return 1;
1330 }
1331
1332 int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1333 {
1334   char *sn;
1335   va_list ap;
1336   
1337   va_start(ap, command);
1338   sn = va_arg(ap, char *);
1339   va_end(ap);
1340
1341   dvprintf("\n%s has left\n", sn);
1342
1343   return 1;
1344 }
1345
1346 int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1347 {
1348   static char *codes[] = {
1349     "Unknown",
1350     "Mandatory upgrade",
1351     "Advisory upgrade",
1352     "System bulletin",
1353     "Top o' the world!"};
1354   static int codeslen = 5;
1355
1356   char *msg;
1357   unsigned short id;
1358   va_list ap;
1359   
1360   va_start(ap, command);
1361   id = va_arg(ap, int);
1362   msg = va_arg(ap, char *);
1363   va_end(ap);
1364
1365   dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, 
1366            (id < codeslen)?codes[id]:"unknown");
1367
1368   if (!connected)
1369     connected++;
1370
1371   return 1;
1372 }
1373
1374 int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1375 {
1376   va_list ap;
1377   unsigned short reason;
1378
1379   va_start(ap, command);
1380   reason = va_arg(ap, int);
1381   va_end(ap);
1382
1383   dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1384   
1385   return 1;
1386 }
1387
1388 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1389 {
1390   va_list ap;
1391   char *destsn;
1392   unsigned short reason;
1393
1394   va_start(ap, command);
1395   destsn = va_arg(ap, char *);
1396   reason = va_arg(ap, int);
1397   va_end(ap);
1398
1399   dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1400   
1401   return 1;
1402 }
1403
1404 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1405 {
1406   va_list ap;
1407   char *destsn;
1408   unsigned short reason;
1409
1410   va_start(ap, command);
1411   destsn = va_arg(ap, char *);
1412   reason = va_arg(ap, int);
1413   va_end(ap);
1414
1415   dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1416   
1417   return 1;
1418 }
1419
1420 /* 
1421  * Handles callbacks for AIM_CB_MISSED_CALL.
1422  */
1423 int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1424 {
1425   static char *missedreasons[] = {
1426     "Unknown",
1427     "Message too large"};
1428   static int missedreasonslen = 2;
1429
1430   va_list ap;
1431   unsigned short chan, nummissed, reason;
1432   struct aim_userinfo_s *userinfo;
1433   
1434   va_start(ap, command);
1435   chan = va_arg(ap, int);
1436   userinfo = va_arg(ap, struct aim_userinfo_s *);
1437   nummissed = va_arg(ap, int);
1438   reason = va_arg(ap, int);
1439   va_end(ap);
1440
1441   dvprintf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1442   
1443   return 1;
1444 }
1445
1446 int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1447 {
1448   struct client_info_s info = {"faimtest (with SNAC login)", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x0000004b}; /* 4.1.2010 */
1449   char *key;
1450   va_list ap;
1451   
1452   va_start(ap, command);
1453   key = va_arg(ap, char *);
1454   va_end(ap);
1455
1456   aim_send_login(sess, command->conn, screenname, password, &info, key);
1457  
1458   return 1;
1459 }
1460
1461 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1462 {
1463   va_list ap;
1464   struct aim_userinfo_s *userinfo;
1465   int count = 0, i = 0;
1466   
1467   va_start(ap, command);
1468   count = va_arg(ap, int);
1469   userinfo = va_arg(ap, struct aim_userinfo_s *);
1470   va_end(ap);
1471
1472   dvprintf("faimtest: chat: %s:  New occupants have joined:\n", (char *)command->conn->priv);
1473   while (i < count)
1474     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1475
1476   return 1;
1477 }
1478
1479 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1480 {
1481   va_list ap;
1482   struct aim_userinfo_s *userinfo;
1483   int count = 0, i = 0;
1484   
1485   va_start(ap, command);
1486   count = va_arg(ap, int);
1487   userinfo = va_arg(ap, struct aim_userinfo_s *);
1488   va_end(ap);
1489
1490   dvprintf("faimtest: chat: %s:  Some occupants have left:\n", (char *)command->conn->priv);
1491
1492   for (i = 0; i < count; )
1493     dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1494
1495   return 1;
1496 }
1497
1498 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1499 {
1500   va_list ap;
1501   struct aim_userinfo_s *userinfo;
1502   struct aim_chat_roominfo *roominfo;
1503   char *roomname;
1504   int usercount,i;
1505   char *roomdesc;
1506   unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1507   unsigned long creationtime;
1508
1509   va_start(ap, command);
1510   roominfo = va_arg(ap, struct aim_chat_roominfo *);
1511   roomname = va_arg(ap, char *);
1512   usercount= va_arg(ap, int);
1513   userinfo = va_arg(ap, struct aim_userinfo_s *);
1514   roomdesc = va_arg(ap, char *);
1515   unknown_c9 = va_arg(ap, int);
1516   creationtime = va_arg(ap, unsigned long);
1517   maxmsglen = va_arg(ap, int);
1518   unknown_d2 = va_arg(ap, int);
1519   unknown_d5 = va_arg(ap, int);
1520   va_end(ap);
1521
1522   dvprintf("faimtest: chat: %s:  info update:\n", (char *)command->conn->priv);
1523   dvprintf("faimtest: chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", 
1524          (char *)command->conn->priv,
1525          roominfo->exchange,
1526          roominfo->name,
1527          roominfo->instance);
1528   dvprintf("faimtest: chat: %s:  \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1529   dvprintf("faimtest: chat: %s:  \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1530   dvprintf("faimtest: chat: %s:  \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1531   
1532   for (i = 0; i < usercount; )
1533     dvprintf("faimtest: chat: %s:  \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1534
1535   dvprintf("faimtest: chat: %s:  \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1536   dvprintf("faimtest: chat: %s:  \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1537   dvprintf("faimtest: chat: %s:  \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
1538   dvprintf("faimtest: chat: %s:  \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
1539   dvprintf("faimtest: chat: %s:  \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
1540
1541   return 1;
1542 }
1543
1544 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1545 {
1546   va_list ap;
1547   struct aim_userinfo_s *userinfo;
1548   char *msg;
1549   char tmpbuf[1152];
1550  
1551   va_start(ap, command);
1552   userinfo = va_arg(ap, struct aim_userinfo_s *);       
1553   msg = va_arg(ap, char *);
1554   va_end(ap);
1555
1556   dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
1557
1558   /*
1559    * Do an echo for testing purposes.  But not for ourselves ("oops!")
1560    */
1561   if (strcmp(userinfo->sn, sess->sn) != 0)
1562     {
1563       sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
1564       aim_chat_send_im(sess, command->conn, tmpbuf);
1565     }
1566
1567   return 1;
1568 }
1569
1570 int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1571 {
1572   unsigned short type;
1573   va_list ap;
1574
1575   va_start(ap, command);
1576   type = va_arg(ap, int);
1577
1578   switch(type) {
1579   case 0x0002: {
1580     int maxrooms;
1581     struct aim_chat_exchangeinfo *exchanges;
1582     int exchangecount,i = 0;
1583     
1584     maxrooms = va_arg(ap, int);
1585     exchangecount = va_arg(ap, int);
1586     exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1587     va_end(ap);
1588     
1589     dprintf("faimtest: chat info: Chat Rights:\n");
1590     dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1591     
1592     dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
1593     for (i = 0; i < exchangecount; i++) {
1594       dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", 
1595                exchanges[i].number,     
1596                exchanges[i].name,
1597                exchanges[i].charset1,
1598                exchanges[i].lang1);
1599     }
1600     
1601   }
1602   break;
1603   case 0x0008: {
1604     char *fqcn, *name, *ck;
1605     unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1606     unsigned char createperms;
1607     unsigned long createtime;
1608
1609     fqcn = va_arg(ap, char *);
1610     instance = va_arg(ap, int);
1611     exchange = va_arg(ap, int);
1612     flags = va_arg(ap, int);
1613     createtime = va_arg(ap, unsigned long);
1614     maxmsglen = va_arg(ap, int);
1615     maxoccupancy = va_arg(ap, int);
1616     createperms = va_arg(ap, int);
1617     unknown = va_arg(ap, int);
1618     name = va_arg(ap, char *);
1619     ck = va_arg(ap, char *);
1620     va_end(ap);
1621
1622     dvprintf("faimtest: recieved room create reply for %s/0x%04x\n", fqcn, exchange);
1623   }
1624   break;
1625   default:
1626     va_end(ap);
1627     dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
1628   }
1629   return 1;
1630 }
1631
1632 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1633 {
1634   va_list ap;
1635   unsigned short code;
1636   char *msg = NULL;
1637
1638   va_start(ap, command);
1639   code = va_arg(ap, int);
1640   msg = va_arg(ap, char *);
1641   va_end(ap);
1642
1643   dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
1644   aim_conn_kill(sess, &command->conn); /* this will break the main loop */
1645
1646   return 1;
1647 }
1648
1649 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1650 {       
1651   dprintf("faimtest: connecting to an aimdebugd!\n");
1652
1653   /* convert the authorizer connection to a BOS connection */
1654   command->conn->type = AIM_CONN_TYPE_BOS;
1655
1656   aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1657
1658   /* tell the aimddebugd we're ready */
1659   aim_debugconn_sendconnect(sess, command->conn); 
1660
1661   /* go right into main loop (don't open a BOS connection, etc) */
1662   return 1;
1663 }
1664
1665 /*
1666  * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
1667  */
1668 int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1669 {
1670   va_list ap;
1671   unsigned short type;
1672   char *sn = NULL;
1673
1674   va_start(ap, command);
1675   type = va_arg(ap, int);
1676   sn = va_arg(ap, char *);
1677   va_end(ap);
1678
1679   dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1680
1681   return 1;
1682 }
1683
1684 #ifdef FILESUPPORT
1685 int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
1686 {
1687   va_list ap;
1688   struct aim_conn_t *oftconn;
1689   struct aim_fileheader_t *fh;
1690   char *cookie;
1691
1692   va_start(ap, command);
1693   oftconn = va_arg(ap, struct aim_conn_t *);
1694   fh = va_arg(ap, struct aim_fileheader_t *);
1695   cookie = va_arg(ap, char *);
1696   va_end(ap);
1697
1698   dvprintf("faimtest: request for file %s.\n", fh->name);
1699
1700   return 1;
1701 }
1702
1703
1704 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1705 {
1706   va_list ap;
1707   struct aim_conn_t *oftconn;
1708   struct aim_fileheader_t *fh;
1709   char *path, *cookie;
1710   int pos, bufpos, bufsize = 2048, i;
1711   char buf[2048];
1712
1713   FILE *file;
1714
1715   va_start(ap, command);
1716   oftconn = va_arg(ap, struct aim_conn_t *);
1717   fh = va_arg(ap, struct aim_fileheader_t *);
1718   cookie = va_arg(ap, char *);
1719   va_end(ap);
1720
1721   dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size);
1722
1723   if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) {
1724     dperror("calloc");
1725     dprintf("faimtest: error in calloc of path\n");
1726     return 0; /* XXX: no idea what winaim expects here =) */
1727   }
1728   
1729   snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name);
1730
1731
1732   if( (file = fopen(path, "r")) == NULL) {
1733     dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
1734     return 0;
1735   }
1736   
1737   for(pos = 0; pos < fh->size; pos++) {
1738     bufpos = pos % bufsize;
1739
1740     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1741       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
1742         dperror("faim: getfile_send: write1");
1743         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
1744         free(buf);   
1745         return -1;
1746       }
1747     }
1748     if( (buf[bufpos] = fgetc(file)) == EOF) {
1749       if(pos != fh->size) {
1750         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1751         free(buf);   
1752         return -1;
1753       }
1754     }      
1755     dvprintf("%c(0x%02x) ", buf[pos], buf[pos]);
1756   }
1757
1758   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
1759     dperror("faim: getfile_send: write2");
1760     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1761     free(buf);   
1762     return -1;
1763   }
1764
1765
1766   free(fh);  
1767   return 1;
1768 }
1769
1770 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) 
1771 {
1772   va_list ap;
1773   struct aim_conn_t *conn;
1774   struct aim_fileheader_t *fh;
1775
1776   va_start(ap, command);
1777   conn = va_arg(ap, struct aim_conn_t *);
1778   fh = va_arg(ap, struct aim_fileheader_t *);
1779   va_end(ap);
1780
1781   dvprintf("faimtest: completed file transfer for %s.\n", fh->name);
1782
1783   aim_conn_close(conn);
1784   aim_conn_kill(sess, &conn);
1785   return 1;
1786 }
1787
1788 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1789 {
1790   va_list ap;
1791   struct aim_conn_t *conn;
1792   char *sn;
1793
1794   va_start(ap, command);
1795   conn = va_arg(ap, struct aim_conn_t *);
1796   sn = va_arg(ap, char *);
1797   va_end(ap);
1798
1799   aim_conn_kill(sess, &conn);
1800
1801   dvprintf("faimtest: getfile: disconnected from %s\n", sn);
1802   return 1;
1803 }
1804 int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1805 {
1806   va_list ap;
1807   struct aim_conn_t *conn;
1808   char *sn;
1809   struct aim_filetransfer_priv *priv;
1810
1811   va_start(ap, command);
1812   conn = va_arg(ap, struct aim_conn_t *);
1813   sn = va_arg(ap, char *);
1814   va_end(ap);
1815
1816   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
1817   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
1818   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
1819   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
1820   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
1821   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
1822   aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECIEVE, faimtest_getfile_recieve, 0);
1823   
1824   priv = (struct aim_filetransfer_priv *)conn->priv;
1825
1826   dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", sn, priv->ip, conn->fd);
1827   return 1;
1828 }
1829
1830 int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1831 {
1832   va_list ap;
1833   struct aim_conn_t *conn;
1834   char *listing;
1835   struct aim_filetransfer_priv *ft;
1836   char *filename, *nameend, *sizec;
1837   int filesize, namelen;
1838
1839   va_start(ap, command);
1840   conn = va_arg(ap, struct aim_conn_t *);
1841   ft = va_arg(ap, struct aim_filetransfer_priv *);
1842   listing = va_arg(ap, char *);
1843   va_end(ap);
1844
1845   dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing);
1846
1847   nameend = strstr(listing+0x1a, "\r");
1848
1849   namelen = nameend - (listing + 0x1a);
1850
1851   filename = malloc(namelen + 1);
1852   strncpy(filename, listing+0x1a, namelen);
1853   filename[namelen] = 0x00;
1854
1855   sizec = malloc(8+1);
1856   memcpy(sizec, listing + 0x11, 8);
1857   sizec[8] = 0x00;
1858
1859   filesize =  strtol(sizec, (char **)NULL, 10);
1860
1861   dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize);
1862
1863   aim_oft_getfile_request(sess, conn, filename, filesize);
1864
1865   free(filename);
1866   free(sizec);
1867
1868   return 0;
1869 }
1870
1871 int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1872 {
1873   va_list ap;
1874   struct aim_conn_t *oftconn;
1875   struct aim_fileheader_t *fh;
1876   int pos, bufpos, bufsize = 2048, i;
1877   char buf[2048];
1878
1879
1880   va_start(ap, command);
1881   oftconn = va_arg(ap, struct aim_conn_t *);
1882   fh = va_arg(ap, struct aim_fileheader_t *);
1883   va_end(ap);
1884
1885   dvprintf("faimtest: sending listing of size %ld\n", fh->size);
1886
1887   for(pos = 0; pos < fh->size; pos++) {
1888     bufpos = pos % bufsize;
1889
1890     if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
1891       if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
1892         dperror("faim: getfile_send: write1");
1893         dprintf("faim: getfile_send: whoopsy, didn't write it all...\n");
1894         free(buf);   
1895         return -1;
1896       }
1897     }
1898     if( (buf[bufpos] = fgetc(listingfile)) == EOF) {
1899       if(pos != fh->size) {
1900         dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size);
1901         free(buf);   
1902         return -1;
1903       }
1904     }      
1905   }
1906
1907   if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
1908     dperror("faim: getfile_send: write2");
1909     dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n");
1910     free(buf);   
1911     return -1;
1912   }
1913
1914   dprintf("faimtest: sent listing\n");
1915   return 0;
1916 }
1917
1918 int faimtest_getfile_recieve(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1919 {
1920   va_list ap;
1921   struct aim_conn_t *conn;
1922   struct aim_filetransfer_priv *ft;
1923   unsigned char data;
1924   int pos;
1925
1926   va_start(ap, command);
1927   conn = va_arg(ap, struct aim_conn_t *);
1928   ft = va_arg(ap, struct aim_filetransfer_priv *);
1929   va_end(ap);
1930
1931   dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name);
1932
1933   for(pos = 0; pos < ft->fh.size; pos++) {
1934     read(conn->fd, &data, 1);
1935     dvprintf("%c(%02x) ", data, data);
1936   }
1937    
1938   dprintf("\n");
1939
1940   aim_oft_getfile_ack(sess, conn);
1941   aim_oft_getfile_end(sess, conn);
1942
1943   return 0;
1944 }
1945 #endif
1946 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1947 {
1948   static char *codes[5] = {"invalid",
1949                            "change",
1950                            "warning",
1951                            "limit",
1952                            "limit cleared"};
1953   va_list ap;
1954   int code;
1955   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
1956   unsigned long currentavg, maxavg;
1957
1958   va_start(ap, command); 
1959
1960   /* See code explanations below */
1961   code = va_arg(ap, int);
1962
1963   /*
1964    * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1965    */
1966   rateclass = va_arg(ap, unsigned long);
1967
1968   /*
1969    * Not sure what this is exactly.  I think its the temporal 
1970    * relation factor (ie, how to make the rest of the numbers
1971    * make sense in the real world). 
1972    */
1973   windowsize = va_arg(ap, unsigned long);
1974
1975   /* Explained below */
1976   clear = va_arg(ap, unsigned long);
1977   alert = va_arg(ap, unsigned long);
1978   limit = va_arg(ap, unsigned long);
1979   disconnect = va_arg(ap, unsigned long);
1980   currentavg = va_arg(ap, unsigned long);
1981   maxavg = va_arg(ap, unsigned long);
1982
1983   va_end(ap);
1984
1985
1986   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",
1987          (code < 5)?codes[code]:"invalid",
1988          rateclass,
1989          currentavg, maxavg,
1990          alert, clear,
1991          limit, disconnect,
1992          windowsize);
1993
1994   if (code == AIM_RATE_CODE_CHANGE) {
1995     /*
1996      * Not real sure when these get sent.
1997      */
1998     if (currentavg >= clear)
1999       aim_conn_setlatency(command->conn, 0);
2000
2001   } else if (code == AIM_RATE_CODE_WARNING) {
2002     /*
2003      * We start getting WARNINGs the first time we go below the 'alert'
2004      * limit (currentavg < alert) and they stop when either we pause
2005      * long enough for currentavg to go above 'clear', or until we
2006      * flood it bad enough to go below 'limit' (and start getting
2007      * LIMITs instead) or even further and go below 'disconnect' and 
2008      * get disconnected completely (and won't be able to login right
2009      * away either).
2010      */
2011     aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ 
2012
2013   } else if (code == AIM_RATE_CODE_LIMIT) {
2014     /*
2015      * When we hit LIMIT, messages will start getting dropped.
2016      */
2017     aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ 
2018
2019   } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2020     /*
2021      * The limit is cleared when curavg goes above 'clear'.
2022      */
2023     aim_conn_setlatency(command->conn, 0); 
2024   }
2025
2026   return 1;
2027 }
2028
2029 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2030 {
2031   va_list ap;
2032   int newevil;
2033   struct aim_userinfo_s *userinfo;
2034
2035   va_start(ap, command);
2036   newevil = va_arg(ap, int);
2037   userinfo = va_arg(ap, struct aim_userinfo_s *);
2038   va_end(ap);
2039
2040   /*
2041    * Evil Notifications that are lacking userinfo->sn are anon-warns
2042    * if they are an evil increases, but are not warnings at all if its
2043    * a decrease (its the natural backoff happening).
2044    *
2045    * newevil is passed as an int representing the new evil value times
2046    * ten.
2047    */
2048   dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
2049
2050   return 1;
2051 }
2052
2053 int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2054 {
2055   va_list ap;
2056   char *address, *SNs;
2057   int i, num;
2058   
2059   va_start(ap, command);
2060   address = va_arg(ap, char *);
2061   num = va_arg(ap, int);
2062   SNs = va_arg(ap, char *);
2063   va_end(ap);
2064
2065   dvprintf("faimtest: E-Mail Search Results for %s: ", address);
2066
2067   for(i = 0; i < num; i++)
2068     dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
2069   dinlineprintf("\n");
2070
2071   return 1;
2072 }
2073
2074 int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
2075 {
2076   va_list ap;
2077   char *address;
2078   
2079   va_start(ap, command);
2080   address = va_arg(ap, char *);
2081   va_end(ap);
2082
2083   dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
2084
2085   return 1;
2086 }
This page took 0.303271 seconds and 5 git commands to generate.