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