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