]> andersk Git - libfaim.git/blob - utils/faimtest/faimtest.c
- Fri Dec 15 21:51:32 UTC 2000
[libfaim.git] / utils / faimtest / faimtest.c
1 /* 
2  *  -----------------------------------------------------------
3  *  ProtoFAIM: v1.xx.xxplxx
4  *  -----------------------------------------------------------
5  *
6  *  This is ProtoFAIM v1.xx.xxplxx!!! Its nearly completely 
7  *  different than that ugly thing called v0.  This app is
8  *  compatible with the latest version of the libfaim library.
9  *  Work is continuing. 
10  *
11  *  ProtoFAIM should only be used for two things...
12  *   1) Testing the libfaim backend.
13  *   2) For reference on the libfaim API when developing clients.
14  * 
15  *  Its very ugly.  Probably always will be.  Nothing is more
16  *  ugly than the backend itself, however.
17  *
18  *  -----------------------------------------------------------
19  *
20  *  I'm releasing this code and all it's associated linkage
21  *  under the GNU General Public License.  For more information,
22  *  please refer to http://www.fsf.org.  For any questions,
23  *  please contact me at the address below.
24  *
25  *  Most everything:
26  *  (c) 1998 Adam Fritzler, PST, afritz@iname.com
27  *
28  *  The password algorithms
29  *  (c) 1998 Brock Wilcox, awwaiid@iname.com
30  *
31  *  THERE IS NO CODE FROM AOL'S AIM IN THIS CODE, NOR
32  *  WAS THERE ANY DISASSEMBLAGE TO DEFINE PROTOCOL.  All
33  *  information was gained through painstakingly comparing
34  *  TCP dumps while the AIM Java client was running.  Nothing
35  *  more than that, except for a lot of experimenting.
36  *
37  *  -----------------------------------------------------------
38  *
39  */
40
41 /*
42   Current status:
43
44
45  */
46
47 #include <faim/aim.h> 
48
49 int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, ...);
50 int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...);
51 int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...);
52 int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...);
53 int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...);
54 int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...);
55 int faimtest_handleredirect(struct aim_session_t *, struct command_rx_struct *command, ...);
56 int faimtest_authsvrready(struct aim_session_t *, struct command_rx_struct *command, ...);
57 int faimtest_pwdchngdone(struct aim_session_t *, struct command_rx_struct *command, ...);
58 int faimtest_serverready(struct aim_session_t *, struct command_rx_struct *command, ...);
59 int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...);
60 int faimtest_parse_misses(struct aim_session_t *, struct command_rx_struct *command, ...);
61 int faimtest_parse_msgack(struct aim_session_t *, struct command_rx_struct *command, ...);
62 int faimtest_parse_motd(struct aim_session_t *, struct command_rx_struct *command, ...);
63 int faimtest_parse_login(struct aim_session_t *, struct command_rx_struct *command, ...);
64 int faimtest_chatnav_info(struct aim_session_t *, struct command_rx_struct *command, ...);
65 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...);
66 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...);
67 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...);
68 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...);
69 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
70 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
71
72 int faimtest_directim_request(struct aim_session_t *sess, struct command_rx_struct *command, ...);
73 int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...);
74 int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
75 int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...);
76 int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
77 int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...);
78 #define FILESUPPORT
79 #ifdef FILESUPPORT
80 int faimtest_getfile_filereq(struct aim_session_t *sess, struct command_rx_struct *command, ...);
81 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...);
82 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...);
83 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...);
84 #endif
85
86 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...);
87 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...);
88 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
89 int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...);
90 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...);
91
92 static char *msgerrreasons[] = {
93   "Invalid error",
94   "Invalid SNAC",
95   "Rate to host",
96   "Rate to client",
97   "Not logged on",
98   "Service unavailable",
99   "Service not defined",
100   "Obsolete SNAC",
101   "Not supported by host",
102   "Not supported by client",
103   "Refused by client",
104   "Reply too big",
105   "Responses lost",
106   "Request denied",
107   "Busted SNAC payload",
108   "Insufficient rights",
109   "In local permit/deny",
110   "Too evil (sender)",
111   "Too evil (receiver)",
112   "User temporarily unavailable",
113   "No match",
114   "List overflow",
115   "Request ambiguous",
116   "Queue full",
117   "Not while on AOL"};
118 static int msgerrreasonslen = 25;
119
120 static char *screenname,*password,*server=NULL;
121 static int connected = 0;
122
123 int faimtest_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...)
124 {
125   if (command->data) {
126     printf("aim: minimum report interval: %d (seconds?)\n", aimutil_get16(command->data+10));
127   } else
128     printf("aim: NULL minimum report interval!\n");
129   return 1;
130 }
131
132 int faimtest_flapversion(struct aim_session_t *sess, struct command_rx_struct *command, ...)
133 {
134
135   printf("faimtest: using FLAP version %u\n", aimutil_get32(command->data));
136
137 #if 0
138   /* 
139    * This is an alternate location for starting the login process.
140    */
141   /* XXX should do more checking to make sure its really the right AUTH conn */
142   if (command->conn->type == AIM_CONN_TYPE_AUTH) {
143     /* do NOT send a connack/flapversion, request_login will send it if needed */
144     aim_request_login(sess, command->conn, screenname);
145     printf("faimtest: login request sent\n");
146   }
147 #endif
148
149   return 1;
150 }
151
152 /*
153  * This is a frivilous callback. You don't need it. I only used it for
154  * debugging non-blocking connects.
155  *
156  * If packets are sent to a conn before its fully connected, they
157  * will be queued and then transmitted when the connection completes.
158  *
159  */
160 int faimtest_conncomplete(struct aim_session_t *sess, struct command_rx_struct *command, ...)
161 {
162   va_list ap;
163   struct aim_conn_t *conn;
164
165   va_start(ap, command);
166   conn = va_arg(ap, struct aim_conn_t *);
167   va_end(ap);
168   
169   if (conn)
170     printf("faimtest: connection on %d completed\n", conn->fd);
171
172   return 1;
173 }
174
175 #ifdef _WIN32
176 /*
177  * This is really all thats needed to link against libfaim on win32.
178  *
179  * Note that this particular version of faimtest has never been tested
180  * on win32, but I'm fairly sure it should.
181  */
182 int initwsa(void)
183 {
184   WORD wVersionRequested;
185   WSADATA wsaData;
186
187   wVersionRequested = MAKEWORD(2,2);
188   return WSAStartup(wVersionRequested, &wsaData);
189 }
190 #endif /* _WIN32 */
191
192 int main(void)
193 {
194   struct aim_session_t aimsess;
195   struct aim_conn_t *authconn = NULL, *waitingconn = NULL;
196   int keepgoing = 1;
197   char *proxy, *proxyusername, *proxypass;
198
199   char *listingpath;
200
201   int selstat = 0;
202
203 #ifdef FILESUPPORT
204   FILE *listingfile;
205 #endif
206
207   if ( !(screenname = getenv("SCREENNAME")) ||
208        !(password = getenv("PASSWORD")))
209     {
210       printf("Must specify SCREENAME and PASSWORD in environment.\n");
211       return -1;
212     }
213
214   server = getenv("AUTHSERVER");
215
216   proxy = getenv("SOCKSPROXY");
217   proxyusername = getenv("SOCKSNAME");
218   proxypass = getenv("SOCKSPASS");
219
220 #ifdef FILESUPPORT
221   listingpath = getenv("LISTINGPATH");
222 #endif
223
224 #ifdef _WIN32
225   if (initwsa() != 0) {
226     printf("faimtest: could not initialize windows sockets\n");
227     return -1;
228   }
229 #endif /* _WIN32 */
230
231   /* Pass zero as flags if you want blocking connects */
232   aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT);
233
234 #ifdef FILESUPPORT
235   if(listingpath) {
236     char *listingname;
237     if(!(listingname = (char *)calloc(1, strlen(listingpath)+strlen("/listing.txt")))) {
238       perror("listingname calloc.");
239       exit(-1);
240     }
241     sprintf(listingname, "%s/listing.txt", listingpath);
242     if( (listingfile = fopen(listingname, "r")) == NULL) {
243       printf("Couldn't open %s... bombing.\n", listingname);
244       exit(-1);
245     }
246
247     aim_oft_registerlisting(&aimsess, listingfile, listingpath);
248
249     free(listingname);
250   }
251 #endif
252
253   if (proxy)
254     aim_setupproxy(&aimsess, proxy, proxyusername, proxypass);
255
256   authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, server?server:FAIM_LOGIN_SERVER);
257
258   if (authconn == NULL) {
259     fprintf(stderr, "faimtest: internal connection error while in aim_login.  bailing out.\n");
260     return -1;
261   } else if (authconn->fd == -1) {
262     if (authconn->status & AIM_CONN_STATUS_RESOLVERR)
263       fprintf(stderr, "faimtest: could not resolve authorizer name\n");
264     else if (authconn->status & AIM_CONN_STATUS_CONNERR)
265       fprintf(stderr, "faimtest: could not connect to authorizer\n");
266     aim_conn_kill(&aimsess, &authconn);
267     return -1;
268   }
269
270   aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
271   aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
272   aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0);
273   aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0);    
274
275   aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0);
276
277   /* If the connection is in progress, this will just be queued */
278   aim_request_login(&aimsess, authconn, screenname);
279   printf("faimtest: login request sent\n");
280
281   while (keepgoing) {
282     waitingconn = aim_select(&aimsess, NULL, &selstat);
283
284     switch(selstat) {
285     case -1: /* error */
286       keepgoing = 0; /* fall through and hit the aim_logoff() */
287       break;
288
289     case 0: /* no events pending */
290       break;
291
292     case 1: /* outgoing data pending */
293       aim_tx_flushqueue(&aimsess);
294       break;
295
296     case 2: /* incoming data pending */
297       if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
298         if (aim_handlerendconnect(&aimsess, waitingconn) < 0) {
299           printf("connection error (rend out)\n");
300         }
301       } else {
302         if (aim_get_command(&aimsess, waitingconn) >= 0) {
303           aim_rxdispatch(&aimsess);
304         } else {
305           printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype);
306           if(waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
307             /* we should have callbacks for all these, else the library will do the conn_kill for us. */
308             printf("connection error: rendezvous connection. you forgot register a disconnect callback, right?\n");
309           }
310           else
311             aim_conn_kill(&aimsess, &waitingconn);
312           if (!aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)) {
313             printf("major connection error\n");
314             keepgoing = 0;
315           }
316         }
317       }
318       break;
319       
320     default:
321       break; /* invalid */
322     }
323   }
324
325   /* Close up */
326   printf("AIM just decided we didn't need to be here anymore, closing up...\n");
327   
328   /* close up all connections, dead or no */
329   aim_logoff(&aimsess); 
330
331   /* Get out */
332   exit(0);
333 }
334
335 int faimtest_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...)
336 {
337
338   switch(command->conn->type) {
339   case AIM_CONN_TYPE_BOS: {
340     /* this is the new buddy list */
341     char buddies[] = "Buddy1&Buddy2&ThisHereIsAName2&midendian&ewarmenhoven&";
342     /* this is the new profile */
343     char profile[] = "Hello";  
344
345     aim_bos_ackrateresp(sess, command->conn);  /* ack rate info response */
346     aim_bos_reqpersonalinfo(sess, command->conn);
347     aim_bos_reqlocaterights(sess, command->conn);
348     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);
349     aim_bos_reqbuddyrights(sess, command->conn);
350
351     /* send the buddy list and profile (required, even if empty) */
352     aim_bos_setbuddylist(sess, command->conn, buddies);
353
354     /* dont really know what this does */
355     aim_addicbmparam(sess, command->conn);
356     aim_bos_reqicbmparaminfo(sess, command->conn);  
357   
358     aim_bos_reqrights(sess, command->conn);  
359     /* set group permissions -- all user classes */
360     aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS);
361     aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE|AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
362
363     break;  
364   }
365
366   default: 
367     printf("faimtest: got rate response for unhandled connection type %04x\n", command->conn->type);
368     break;
369   }
370
371   return 1;
372 }
373
374 int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...)
375 {
376   int vercount, i;
377   unsigned char *versions;
378   va_list ap;
379
380   va_start(ap, command);
381   vercount = va_arg(ap, int); /* number of family/version pairs */
382   versions = va_arg(ap, unsigned char *);
383   va_end(ap);
384
385   printf("faimtest: SNAC versions supported by this host: ");
386   for (i = 0; i < vercount*4; i += 4)
387     printf("0x%04x:0x%04x ", 
388            aimutil_get16(versions+i),  /* SNAC family */
389            aimutil_get16(versions+i+2) /* Version number */);
390   printf("\n");
391
392   return 1;
393 }
394
395 int faimtest_serverready(struct aim_session_t *sess, struct command_rx_struct *command, ...)
396 {
397   int famcount, i;
398   unsigned short *families;
399   va_list ap;
400
401   va_start(ap, command);
402   famcount = va_arg(ap, int);
403   families = va_arg(ap, unsigned short *);
404   va_end(ap);
405
406   printf("faimtest: SNAC families supported by this host (type %d): ", command->conn->type);
407   for (i = 0; i < famcount; i++)
408     printf("0x%04x ", families[i]);
409   printf("\n");
410
411   switch (command->conn->type) {
412   case AIM_CONN_TYPE_BOS:
413
414     aim_setversions(sess, command->conn);
415     aim_bos_reqrate(sess, command->conn); /* request rate info */
416
417     fprintf(stderr, "faimtest: done with BOS ServerReady\n");
418     break;
419
420   case AIM_CONN_TYPE_CHATNAV:
421     fprintf(stderr, "faimtest: chatnav: got server ready\n");
422     aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
423     aim_bos_reqrate(sess, command->conn);
424     aim_bos_ackrateresp(sess, command->conn);
425     aim_chatnav_clientready(sess, command->conn);
426     aim_chatnav_reqrights(sess, command->conn);
427
428     break;
429
430   case AIM_CONN_TYPE_CHAT:
431     aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
432     aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
433     aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
434     aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
435     aim_bos_reqrate(sess, command->conn);
436     aim_bos_ackrateresp(sess, command->conn);
437     aim_chat_clientready(sess, command->conn);
438     break;
439
440   case AIM_CONN_TYPE_RENDEZVOUS: /* empty */
441     break;
442
443   default:
444     fprintf(stderr, "faimtest: unknown connection type on Server Ready\n");
445   }
446
447   return 1;
448 }
449
450 int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...)
451 {
452   va_list ap;
453   unsigned short maxbuddies, maxwatchers;
454
455   va_start(ap, command);
456   maxbuddies = va_arg(ap, int);
457   maxwatchers = va_arg(ap, int);
458   va_end(ap);
459
460   printf("faimtest: buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
461
462   return 1;
463 }
464
465 int faimtest_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...)
466 {
467   unsigned short maxpermits, maxdenies;
468   va_list ap;
469
470   va_start(ap, command);
471   maxpermits = va_arg(ap, int);
472   maxdenies = va_arg(ap, int);
473   va_end(ap);
474
475   printf("faimtest: BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
476
477   aim_bos_clientready(sess, command->conn);
478
479   printf("faimtest: officially connected to BOS.\n");
480
481   return 1;
482 }
483
484 /*
485   handleredirect()...
486
487   This, of course, handles Service Redirects from OSCAR.
488
489   Should get passed in the following:
490      struct command_rx_struct *command
491        the raw command data
492      int serviceid
493        the destination service ID
494      char *serverip
495        the IP address of the service's server
496      char *cookie
497        the raw auth cookie
498  */
499 int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
500 {
501   va_list ap;
502   int serviceid;
503   char *ip;
504   unsigned char *cookie;
505
506   va_start(ap, command);
507   serviceid = va_arg(ap, int);
508   ip = va_arg(ap, char *);
509   cookie = va_arg(ap, unsigned char *);
510  
511   switch(serviceid)
512     {
513     case 0x0007: /* Authorizer */
514       {
515         struct aim_conn_t *tstconn;
516         /* Open a connection to the Auth */
517         tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
518         if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR) )
519           fprintf(stderr, "faimtest: unable to reconnect with authorizer\n");
520         else {
521           aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
522           aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
523           /* Send the cookie to the Auth */
524           aim_auth_sendcookie(sess, tstconn, cookie);
525         }
526
527       }  
528       break;
529     case 0x000d: /* ChatNav */
530       {
531         struct aim_conn_t *tstconn = NULL;
532         tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip);
533         if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
534           fprintf(stderr, "faimtest: unable to connect to chatnav server\n");
535           if (tstconn) aim_conn_kill(sess, &tstconn);
536           return 1;
537         }
538 #if 0
539         aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_CTN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
540         aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
541 #endif
542         aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
543         aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
544         aim_auth_sendcookie(sess, tstconn, cookie);
545         fprintf(stderr, "\achatnav: connected\n");
546       }
547       break;
548     case 0x000e: /* Chat */
549       {
550         char *roomname = NULL;
551         int exchange;
552         struct aim_conn_t *tstconn = NULL;
553
554         roomname = va_arg(ap, char *);
555         exchange = va_arg(ap, int);
556
557         tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip);
558         if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR))
559           {
560             fprintf(stderr, "faimtest: unable to connect to chat server\n");
561             if (tstconn) aim_conn_kill(sess, &tstconn);
562             return 1;
563           }             
564         printf("faimtest: chat: connected to %s on exchange %d\n", roomname, exchange);
565
566         /*
567          * We must do this to attach the stored name to the connection!
568          */
569         aim_chat_attachname(tstconn, roomname);
570
571         aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0);
572         aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
573         aim_auth_sendcookie(sess, tstconn, cookie);
574       }
575       break;
576     default:
577       printf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
578       /* dunno */
579     }
580
581   va_end(ap);
582
583   return 1;
584 }
585
586 int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...)
587 {
588   va_list ap;
589   struct aim_conn_t *bosconn = NULL;
590   char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
591   unsigned char *cookie = NULL;
592   int errorcode = 0, regstatus = 0;
593   int latestbuild = 0, latestbetabuild = 0;
594   char *latestrelease = NULL, *latestbeta = NULL;
595   char *latestreleaseurl = NULL, *latestbetaurl = NULL;
596   char *latestreleaseinfo = NULL, *latestbetainfo = NULL;
597
598   va_start(ap, command);
599   sn = va_arg(ap, char *);
600   errorcode = va_arg(ap, int);
601   errurl = va_arg(ap, char *);
602   regstatus = va_arg(ap, int);
603   email = va_arg(ap, char *);
604   bosip = va_arg(ap, char *);
605   cookie = va_arg(ap, unsigned char *);
606
607   latestrelease = va_arg(ap, char *);
608   latestbuild = va_arg(ap, int);
609   latestreleaseurl = va_arg(ap, char *);
610   latestreleaseinfo = va_arg(ap, char *);
611
612   latestbeta = va_arg(ap, char *);
613   latestbetabuild = va_arg(ap, int);
614   latestbetaurl = va_arg(ap, char *);
615   latestbetainfo = va_arg(ap, char *);
616
617   va_end(ap);
618
619   printf("Screen name: %s\n", sn);
620
621   /*
622    * Check for error.
623    */
624   if (errorcode || !bosip || !cookie) {
625     printf("Login Error Code 0x%04x\n", errorcode);
626     printf("Error URL: %s\n", errurl);
627     aim_conn_kill(sess, &command->conn); 
628     return 1;
629   }
630
631   printf("Reg status: %2d\n", regstatus);
632   printf("Email: %s\n", email);
633   printf("BOS IP: %s\n", bosip);
634
635   if (latestbeta)
636     printf("Latest beta version: %s, build %d, at %s (more info at %s)\n", latestbeta, latestbetabuild, latestbetaurl, latestbetainfo);
637
638   if (latestrelease)
639     printf("Latest released version: %s, build %d, at %s (more info at %s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo);
640
641   printf("Closing auth connection...\n");
642   aim_conn_kill(sess, &command->conn);
643   if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
644     fprintf(stderr, "faimtest: could not connect to BOS: internal error\n");
645     return 1;
646   } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
647     fprintf(stderr, "faimtest: could not connect to BOS\n");
648     aim_conn_kill(sess, &bosconn);
649     return 1;
650   }
651
652   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
653   aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
654   aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */
655   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
656   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0);
657   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
658   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
659   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
660   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
661   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
662   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
663   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
664   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
665   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
666   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
667   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
668   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
669   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
670   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
671   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
672
673   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0);
674   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
675   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
676     
677   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
678     
679   aim_auth_sendcookie(sess, bosconn, cookie);
680
681   return 1;
682 }
683
684 static void printuserflags(unsigned short flags)
685 {
686   if (flags & AIM_FLAG_UNCONFIRMED)
687     printf("UNCONFIRMED ");
688   if (flags & AIM_FLAG_ADMINISTRATOR)
689     printf("ADMINISTRATOR ");
690   if (flags & AIM_FLAG_AOL)
691     printf("AOL ");
692   if (flags & AIM_FLAG_OSCAR_PAY)
693       printf("OSCAR_PAY ");
694   if (flags & AIM_FLAG_FREE)
695     printf("FREE ");
696   if (flags & AIM_FLAG_AWAY)
697     printf("AWAY ");
698   if (flags & AIM_FLAG_UNKNOWN40)
699     printf("ICQ? ");
700   if (flags & AIM_FLAG_UNKNOWN80)
701     printf("UNKNOWN80 ");
702   return;
703 }
704
705 int faimtest_parse_userinfo(struct aim_session_t *sess, struct command_rx_struct *command, ...)
706 {
707   struct aim_userinfo_s *userinfo;
708   char *prof_encoding = NULL;
709   char *prof = NULL;
710   unsigned short inforeq = 0;
711
712   va_list ap;
713   va_start(ap, command);
714   userinfo = va_arg(ap, struct aim_userinfo_s *);
715   prof_encoding = va_arg(ap, char *);
716   prof = va_arg(ap, char *);
717   inforeq = va_arg(ap, int);
718   va_end(ap);
719   
720   printf("faimtest: userinfo: sn: %s\n", userinfo->sn);
721   printf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
722   printf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags);
723   printuserflags(userinfo->flags);
724   printf("\n");
725   
726   printf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
727   printf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
728   printf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
729   
730   if (inforeq == AIM_GETINFO_GENERALINFO) {
731     printf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
732     printf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
733   } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
734     printf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
735     printf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]");
736   } else 
737     printf("faimtest: userinfo: unknown info request\n");
738   
739   return 1;
740 }
741
742 /*
743  * The user-level Incoming ICBM callback.
744  *
745  * Arguments:
746  *  struct command_rx_struct *  command     if you feel like doing it yourself
747  *  char *                      srcsn       the source name
748  *  char *                      msg         message
749  *  int                         warnlevel   warning/evil level
750  *  int                         flags       flags
751  *  ulong                       membersince time_t of date of signup
752  *  ulong                       onsince     time_t of date of singon
753  *  int                         idletime    min (sec?) idle
754  *  u_int                       icbmflags   sets AIM_IMFLAGS_{AWAY,ACK}
755  *
756  */
757 int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_struct *command, ...)
758 {
759   int channel;
760   va_list ap;
761
762   va_start(ap, command);
763   channel = va_arg(ap, int);
764
765   /*
766    * Channel 1: Standard Message
767    */
768   if (channel == 1) {
769     struct aim_userinfo_s *userinfo;
770     char *msg = NULL;
771     u_int icbmflags = 0;
772     char *tmpstr = NULL;
773     unsigned short flag1, flag2;
774     
775     userinfo = va_arg(ap, struct aim_userinfo_s *);
776     msg = va_arg(ap, char *);
777     icbmflags = va_arg(ap, u_int);
778     flag1 = va_arg(ap, int);
779     flag2 = va_arg(ap, int);
780     va_end(ap);
781     
782     printf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
783     printf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
784     printf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags);
785     printuserflags(userinfo->flags);
786     printf("\n");
787
788     printf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
789     printf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
790     printf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
791     printf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
792     
793     printf("faimtest: icbm: icbmflags = ");
794     if (icbmflags & AIM_IMFLAGS_AWAY)
795       printf("away ");
796     if (icbmflags & AIM_IMFLAGS_ACK)
797       printf("ackrequest ");
798     printf("\n");
799     
800     printf("faimtest: icbm: encoding flags = {%04x, %04x}\n", flag1, flag2);
801     
802     printf("faimtest: icbm: message: %s\n", msg);
803     
804     if (msg) {
805       int i = 0;
806
807       while (msg[i] == '<') {
808         if (msg[i] == '<') {
809           while (msg[i] != '>')
810             i++;
811           i++;
812         }
813       }
814       tmpstr = msg+i;
815
816       printf("tmpstr = %s\n", tmpstr);
817       
818       if ( (strlen(tmpstr) >= 10) &&
819            (!strncmp(tmpstr, "disconnect", 10)) ) {
820           aim_send_im(sess, command->conn, "midendian", 0, "ta ta...");
821           aim_logoff(sess);
822       } else if (strstr(tmpstr, "goodday")) {
823         printf("faimtest: icbm: sending response\n");
824         aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
825       } else if (strstr(tmpstr, "warnme")) {
826         printf("faimtest: icbm: sending non-anon warning\n");
827         aim_send_warning(sess, command->conn, userinfo->sn, 0);
828       } else if (strstr(tmpstr, "anonwarn")) {
829         printf("faimtest: icbm: sending anon warning\n");
830         aim_send_warning(sess, command->conn, userinfo->sn, AIM_WARN_ANON);
831       } else if (strstr(tmpstr, "setdirectoryinfo")) {
832         printf("faimtest: icbm: sending backwards profile data\n");
833         aim_setdirectoryinfo(sess, command->conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
834       } else if (strstr(tmpstr, "setinterests")) {
835         printf("faimtest: icbm: setting fun interests\n");
836         aim_setuserinterests(sess, command->conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
837       } else if (!strncmp(tmpstr, "open chatnav", 12)) {
838         aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
839         //aim_chat_join(sess, command->conn, "thishereisaname2_chat85");
840       } else if (!strncmp(tmpstr, "create", 6)) {
841         aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
842       } else if (!strncmp(tmpstr, "close chatnav", 13)) {
843         struct aim_conn_t *chatnavconn;
844         chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV);
845         aim_conn_kill(sess, &chatnavconn);
846       } else if (!strncmp(tmpstr, "join", 4)) {
847           aim_chat_join(sess, command->conn, 0x0004, "worlddomination");
848       } else if (!strncmp(tmpstr, "leave", 5))
849             aim_chat_leaveroom(sess, "worlddomination");
850       else if (!strncmp(tmpstr, "getinfo", 7)) {
851         aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
852         aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
853       } else if (!strncmp(tmpstr, "open directim", 13)) {
854         struct aim_conn_t *newconn;
855         newconn = aim_directim_initiate(sess, command->conn, NULL, userinfo->sn);
856       } else if (!strncmp(tmpstr, "openauth", 8)) {
857         aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_AUTH);
858       } else if (!strncmp(tmpstr, "auth", 4)) {
859         aim_genericreq_n(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0007, 0x0002);
860       } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
861         aim_send_im(sess, command->conn, "vaxherder", 0, "sendmsg 7900");
862       } else if (!strncmp(tmpstr, "sendmsg", 7)) {
863         int i;
864         i = atoi(tmpstr+8);
865         if (i < 10000) {
866           char *newbuf;
867           int z;
868
869           newbuf = malloc(i+1);
870           for (z = 0; z < i; z++) {
871             newbuf[z] = (z % 10)+0x30;
872           }
873           newbuf[i] = '\0';
874           aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf);
875           free(newbuf);
876         }
877       } else {
878         printf("unknown command.\n");
879         aim_add_buddy(sess, command->conn, userinfo->sn);
880       }
881       
882     }
883   }
884   /*
885    * Channel 2: Rendevous Request
886    */
887   else if (channel == 2) {
888     struct aim_userinfo_s *userinfo;
889     unsigned short reqclass;
890     
891     reqclass = va_arg(ap, int);
892     switch (reqclass) {
893     case AIM_CAPS_VOICE: {
894       userinfo = va_arg(ap, struct aim_userinfo_s *);
895       va_end(ap);
896       
897       printf("faimtest: voice invitation: source sn = %s\n", userinfo->sn);
898       printf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
899       printf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags);
900       printuserflags(userinfo->flags);
901       printf("\n");
902
903       /* we dont get membersince on chat invites! */
904       printf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
905       printf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime);
906       
907       break;
908     }
909     case AIM_CAPS_GETFILE: {
910 #ifdef FILESUPPORT
911       char *ip, *cookie;
912       struct aim_conn_t *newconn;
913
914       userinfo = va_arg(ap, struct aim_userinfo_s *);
915       ip = va_arg(ap, char *);
916       cookie = va_arg(ap, char *);
917       va_end(ap);
918       
919       printf("faimtest: get file request from %s (at %s)\n", userinfo->sn, ip);
920
921       sleep(1);
922
923       if( (newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, cookie, ip, sess->oft.listing, reqclass)) == NULL ) {
924         printf("faimtest: getfile: requestconn: apparent error in accepttransfer\n");
925         break;
926       }
927       
928       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
929       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
930       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);      
931       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);      
932
933       printf("faimtest: getfile connect succeeded, handlers added.\n");
934
935       break;
936 #endif
937     }
938     case AIM_CAPS_SENDFILE: {
939       printf("faimtest: send file!\n");
940       break;
941     }
942     case AIM_CAPS_CHAT: {
943       char *msg,*encoding,*lang;
944       struct aim_chat_roominfo *roominfo;
945       
946       userinfo = va_arg(ap, struct aim_userinfo_s *);
947       roominfo = va_arg(ap, struct aim_chat_roominfo *);
948       msg = va_arg(ap, char *);
949       encoding = va_arg(ap, char *);
950       lang = va_arg(ap, char *);
951       va_end(ap);
952       
953       printf("faimtest: chat invitation: source sn = %s\n", userinfo->sn);
954       printf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel);
955       printf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags);
956       printuserflags(userinfo->flags);
957       printf("\n");
958
959       /* we dont get membersince on chat invites! */
960       printf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince);
961       printf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime);
962       
963       printf("faimtest: chat invitation: message = %s\n", msg);
964       printf("faimtest: chat invitation: room name = %s\n", roominfo->name);
965       printf("faimtest: chat invitation: encoding = %s\n", encoding);
966       printf("faimtest: chat invitation: language = %s\n", lang);
967       printf("faimtest: chat invitation: exchange = 0x%04x\n", roominfo->exchange);
968       printf("faimtest: chat invitation: instance = 0x%04x\n", roominfo->instance);
969       printf("faimtest: chat invitiation: autojoining %s...\n", roominfo->name);
970       /*
971        * Automatically join room...
972        */ 
973       aim_chat_join(sess, command->conn, 0x0004, roominfo->name);
974       break;
975     }   
976     case AIM_CAPS_IMIMAGE: {
977       struct aim_directim_priv *priv;
978       struct aim_conn_t *newconn;
979
980       printf("faimtest: icbm: rendezvous imimage\n");
981      
982       userinfo = va_arg(ap, struct aim_userinfo_s *);
983       priv = va_arg(ap, struct aim_directim_priv *);
984       va_end(ap);
985
986       printf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, priv->ip);
987       
988       if (!(newconn = aim_directim_connect(sess, command->conn, priv))) {
989         printf("faimtest: icbm: imimage: could not connect\n");
990         break;
991       }
992       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
993       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
994       aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
995
996       printf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn);
997
998       aim_send_im_direct(sess, newconn, "goodday");
999
1000       break;
1001     }
1002     default:
1003       printf("faimtest: icbm: unknown reqclass (%d)\n", reqclass);
1004     } /* switch */
1005   } else
1006     printf("faimtest does not support channels > 2 (chan = %02x)\n", channel);
1007   printf("faimtest: icbm: done with ICBM handling\n");
1008
1009   return 1;
1010 }
1011
1012 int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1013 {
1014   va_list ap;
1015   struct aim_directim_priv *priv;
1016   struct aim_conn_t *newconn;
1017
1018   va_start(ap, command);
1019   newconn = va_arg(ap, struct aim_conn_t *);
1020   va_end(ap);
1021
1022   priv = (struct aim_directim_priv *)newconn->priv;
1023
1024   printf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip);
1025   
1026   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0);
1027   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0);
1028   aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0);
1029
1030   aim_send_im_direct(sess, newconn, "goodday");
1031
1032   printf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn);
1033
1034   return 1;
1035 }
1036
1037 int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1038 {
1039   va_list ap;
1040   struct aim_directim_priv *priv;
1041   
1042   va_start(ap, command);
1043   priv = va_arg(ap, struct aim_directim_priv *);
1044
1045   va_end(ap);
1046   
1047   printf("faimtest: directim_connect\n");
1048
1049   return 1;
1050 }
1051
1052 int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1053 {
1054   va_list ap;
1055   char *sn = NULL, *msg = NULL;
1056   struct aim_conn_t *conn;
1057
1058   va_start(ap, command);
1059   conn = va_arg(ap, struct aim_conn_t *);
1060   sn = va_arg(ap, char *);
1061   msg = va_arg(ap, char *);
1062   va_end(ap);
1063
1064   printf("faimtest: Directim from %s: %s\n", sn, msg);
1065   if (!strncmp(msg, "sendmsg", 7)) {
1066     int i;
1067     i = atoi(msg+8);
1068     if (i < 10000) {
1069       char *newbuf;
1070       int z;
1071       
1072       newbuf = malloc(i+1);
1073       for (z = 0; z < i; z++) {
1074         newbuf[z] = (z % 10)+0x30;
1075       }
1076       newbuf[i] = '\0';
1077       aim_send_im_direct(sess, conn, newbuf);
1078       free(newbuf);
1079     }
1080   } else if (!strncmp(msg, "goodday", 7)) {
1081     aim_send_im_direct(sess, conn, "Good day to you, too");
1082   } else {
1083     char newmsg[1024];
1084     snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
1085     aim_send_im_direct(sess, conn, newmsg);
1086   }
1087   return 1;
1088 }
1089
1090 int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1091 {
1092   va_list ap;
1093   struct aim_conn_t *conn;
1094   char *sn;
1095
1096   va_start(ap, command);
1097   conn = va_arg(ap, struct aim_conn_t *);
1098   sn = va_arg(ap, char *);
1099   va_end(ap);
1100
1101   printf("faimtest: directim: disconnected from %s\n", sn);
1102
1103   aim_conn_kill(sess, &conn);
1104   return 1;
1105 }
1106
1107 int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1108 {
1109   va_list ap;
1110   char *sn;
1111   
1112   va_start(ap, command);
1113   sn = va_arg(ap, char *);
1114   va_end(ap);
1115
1116   printf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn);
1117   return 1;
1118 }
1119
1120 int faimtest_authsvrready(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1121 {
1122   printf("faimtest_authsvrready: called (contype: %d)\n", command->conn->type);
1123   sleep(10);
1124   /* should just be able to tell it we're ready too... */
1125   aim_auth_clientready(sess, command->conn);
1126
1127 #if 0
1128   /*
1129    * This is where you'd really begin changing your password.
1130    *   However, this callback may get called for reasons other
1131    *   than you wanting to change your password.  You should 
1132    *   probably check that before actually doing it.
1133    */
1134   aim_auth_changepasswd(sess, command->conn, "PWD1", "PWD2");
1135 #endif
1136
1137   return 1;
1138 }
1139
1140 int faimtest_pwdchngdone(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1141 {
1142   printf("PASSWORD CHANGE SUCCESSFUL!!!\n");
1143   return 1;
1144 }
1145
1146 int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1147 {
1148   struct aim_userinfo_s *userinfo;
1149    
1150   va_list ap;
1151   va_start(ap, command);
1152   userinfo = va_arg(ap, struct aim_userinfo_s *);
1153   va_end(ap);
1154
1155   printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
1156          time(NULL),
1157          userinfo->sn, userinfo->flags,
1158          (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1159          (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1160          (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1161          (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1162          (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1163          (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1164          (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"",
1165          (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"",
1166          userinfo->capabilities);
1167   return 1;
1168 }
1169
1170 int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1171 {
1172   char *sn;
1173   va_list ap;
1174   
1175   va_start(ap, command);
1176   sn = va_arg(ap, char *);
1177   va_end(ap);
1178
1179   printf("\n%s has left\n", sn);
1180
1181   return 1;
1182 }
1183
1184 int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1185 {
1186   static char *codes[] = {
1187     "Unknown",
1188     "Mandatory upgrade",
1189     "Advisory upgrade",
1190     "System bulletin",
1191     "Top o' the world!"};
1192   static int codeslen = 5;
1193
1194   char *msg;
1195   unsigned short id;
1196   va_list ap;
1197   
1198   va_start(ap, command);
1199   id = va_arg(ap, int);
1200   msg = va_arg(ap, char *);
1201   va_end(ap);
1202
1203   printf("faimtest: motd: %s (%d / %s)\n", msg, id, 
1204          (id < codeslen)?codes[id]:"unknown");
1205
1206   if (!connected)
1207     connected++;
1208
1209   return 1;
1210 }
1211
1212 int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1213 {
1214   va_list ap;
1215   char *destsn;
1216   unsigned short reason;
1217
1218   va_start(ap, command);
1219   destsn = va_arg(ap, char *);
1220   reason = va_arg(ap, int);
1221   va_end(ap);
1222
1223   printf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1224   
1225   return 1;
1226 }
1227
1228 int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1229 {
1230   va_list ap;
1231   char *destsn;
1232   unsigned short reason;
1233
1234   va_start(ap, command);
1235   destsn = va_arg(ap, char *);
1236   reason = va_arg(ap, int);
1237   va_end(ap);
1238
1239   printf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
1240   
1241   return 1;
1242 }
1243
1244 /* 
1245  * Handles callbacks for AIM_CB_MISSED_CALL.
1246  */
1247 int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1248 {
1249   static char *missedreasons[] = {
1250     "Unknown",
1251     "Message too large"};
1252   static int missedreasonslen = 2;
1253
1254   va_list ap;
1255   unsigned short chan, nummissed, reason;
1256   struct aim_userinfo_s *userinfo;
1257   
1258   va_start(ap, command);
1259   chan = va_arg(ap, int);
1260   userinfo = va_arg(ap, struct aim_userinfo_s *);
1261   nummissed = va_arg(ap, int);
1262   reason = va_arg(ap, int);
1263   va_end(ap);
1264
1265   printf("faimtest: missed %d messages from %s (reason %d: %s)\n", nummissed, userinfo->sn, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1266   
1267   return 1;
1268 }
1269
1270 int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1271 {
1272   struct client_info_s info = {"faimtest (with SNAC login)", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x0000004b}; /* 4.1.2010 */
1273   char *key;
1274   va_list ap;
1275   
1276   va_start(ap, command);
1277   key = va_arg(ap, char *);
1278   va_end(ap);
1279
1280   aim_send_login(sess, command->conn, screenname, password, &info, key);
1281  
1282   return 1;
1283 }
1284
1285 int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1286 {
1287   va_list ap;
1288   struct aim_userinfo_s *userinfo;
1289   int count = 0, i = 0;
1290   
1291   va_start(ap, command);
1292   count = va_arg(ap, int);
1293   userinfo = va_arg(ap, struct aim_userinfo_s *);
1294   va_end(ap);
1295
1296   printf("faimtest: chat: %s:  New occupants have joined:\n", (char *)command->conn->priv);
1297   while (i < count)
1298     printf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1299
1300   return 1;
1301 }
1302
1303 int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1304 {
1305   va_list ap;
1306   struct aim_userinfo_s *userinfo;
1307   int count = 0, i = 0;
1308   
1309   va_start(ap, command);
1310   count = va_arg(ap, int);
1311   userinfo = va_arg(ap, struct aim_userinfo_s *);
1312   va_end(ap);
1313
1314   printf("faimtest: chat: %s:  Some occupants have left:\n", (char *)command->conn->priv);
1315   while (i < count)
1316     printf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1317
1318   return 1;
1319 }
1320
1321 int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1322 {
1323   va_list ap;
1324   struct aim_userinfo_s *userinfo;
1325   struct aim_chat_roominfo *roominfo;
1326   char *roomname;
1327   int usercount,i;
1328   char *roomdesc;
1329   unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen;
1330   unsigned long creationtime;
1331
1332   va_start(ap, command);
1333   roominfo = va_arg(ap, struct aim_chat_roominfo *);
1334   roomname = va_arg(ap, char *);
1335   usercount= va_arg(ap, int);
1336   userinfo = va_arg(ap, struct aim_userinfo_s *);
1337   roomdesc = va_arg(ap, char *);
1338   unknown_c9 = va_arg(ap, int);
1339   creationtime = va_arg(ap, unsigned long);
1340   maxmsglen = va_arg(ap, int);
1341   unknown_d2 = va_arg(ap, int);
1342   unknown_d5 = va_arg(ap, int);
1343   va_end(ap);
1344
1345   printf("faimtest: chat: %s:  info update:\n", (char *)command->conn->priv);
1346   printf("faimtest: chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", 
1347          (char *)command->conn->priv,
1348          roominfo->exchange,
1349          roominfo->name,
1350          roominfo->instance);
1351   printf("faimtest: chat: %s:  \tRoomname: %s\n", (char *)command->conn->priv, roomname);
1352   printf("faimtest: chat: %s:  \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc);
1353   printf("faimtest: chat: %s:  \tOccupants: (%d)\n", (char *)command->conn->priv, usercount);
1354   
1355   i = 0;
1356   while (i < usercount)
1357     printf("faimtest: chat: %s:  \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
1358
1359   printf("faimtest: chat: %s:  \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9);
1360   printf("faimtest: chat: %s:  \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime);
1361   printf("faimtest: chat: %s:  \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
1362   printf("faimtest: chat: %s:  \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2);
1363   printf("faimtest: chat: %s:  \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5);
1364
1365   return 1;
1366 }
1367
1368 int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1369 {
1370   va_list ap;
1371   struct aim_userinfo_s *userinfo;
1372   char *msg;
1373   char tmpbuf[1152];
1374  
1375   va_start(ap, command);
1376   userinfo = va_arg(ap, struct aim_userinfo_s *);       
1377   msg = va_arg(ap, char *);
1378   va_end(ap);
1379
1380   printf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg);
1381
1382   /*
1383    * Do an echo for testing purposes.  But not for ourselves ("oops!")
1384    */
1385   if (strcmp(userinfo->sn, sess->sn) != 0)
1386     {
1387       sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg);
1388       aim_chat_send_im(sess, command->conn, tmpbuf);
1389     }
1390
1391   return 1;
1392 }
1393
1394 int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1395 {
1396   unsigned short type;
1397   va_list ap;
1398
1399   va_start(ap, command);
1400   type = va_arg(ap, int);
1401
1402   switch(type) {
1403   case 0x0002: {
1404     int maxrooms;
1405     struct aim_chat_exchangeinfo *exchanges;
1406     int exchangecount,i = 0;
1407     
1408     maxrooms = va_arg(ap, int);
1409     exchangecount = va_arg(ap, int);
1410     exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1411     va_end(ap);
1412     
1413     printf("faimtest: chat info: Chat Rights:\n");
1414     printf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1415     
1416     printf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount);
1417     while (i < exchangecount) {
1418       printf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", 
1419              exchanges[i].number,       
1420              exchanges[i].name,
1421              exchanges[i].charset1,
1422              exchanges[i].lang1);
1423       i++;
1424     }
1425     
1426   }
1427   break;
1428   case 0x0008: {
1429     char *fqcn, *name, *ck;
1430     unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1431     unsigned char createperms;
1432     unsigned long createtime;
1433
1434     fqcn = va_arg(ap, char *);
1435     instance = va_arg(ap, int);
1436     exchange = va_arg(ap, int);
1437     flags = va_arg(ap, int);
1438     createtime = va_arg(ap, unsigned long);
1439     maxmsglen = va_arg(ap, int);
1440     maxoccupancy = va_arg(ap, int);
1441     createperms = va_arg(ap, int);
1442     unknown = va_arg(ap, int);
1443     name = va_arg(ap, char *);
1444     ck = va_arg(ap, char *);
1445     va_end(ap);
1446
1447     printf("faimtest: recieved room create reply for %s/0x%04x\n", fqcn, exchange);
1448   }
1449   break;
1450   default:
1451     va_end(ap);
1452     printf("faimtest: chatnav info: unknown type (%04x)\n", type);
1453   }
1454   return 1;
1455 }
1456
1457 int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1458 {
1459   va_list ap;
1460   unsigned short code;
1461   char *msg = NULL;
1462
1463   va_start(ap, command);
1464   code = va_arg(ap, int);
1465   msg = va_arg(ap, char *);
1466   va_end(ap);
1467
1468   printf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
1469   aim_conn_kill(sess, &command->conn); /* this will break the main loop */
1470
1471   return 1;
1472 }
1473
1474 int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1475 {       
1476   printf("faimtest: connecting to an aimdebugd!\n");
1477
1478   /* convert the authorizer connection to a BOS connection */
1479   command->conn->type = AIM_CONN_TYPE_BOS;
1480
1481   aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
1482
1483   /* tell the aimddebugd we're ready */
1484   aim_debugconn_sendconnect(sess, command->conn); 
1485
1486   /* go right into main loop (don't open a BOS connection, etc) */
1487   return 1;
1488 }
1489
1490 /*
1491  * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
1492  */
1493 int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1494 {
1495   va_list ap;
1496   unsigned short type;
1497   char *sn = NULL;
1498
1499   va_start(ap, command);
1500   type = va_arg(ap, int);
1501   sn = va_arg(ap, char *);
1502   va_end(ap);
1503
1504   printf("faimtest: msgack: 0x%04x / %s\n", type, sn);
1505
1506   return 1;
1507 }
1508
1509 #ifdef FILESUPPORT
1510 int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
1511 {
1512   va_list ap;
1513   struct aim_conn_t *oftconn;
1514   struct aim_fileheader_t *fh;
1515   char *cookie;
1516
1517   va_start(ap, command);
1518   oftconn = va_arg(ap, struct aim_conn_t *);
1519   fh = va_arg(ap, struct aim_fileheader_t *);
1520   cookie = va_arg(ap, char *);
1521   va_end(ap);
1522
1523   printf("faimtest: request for file %s.\n", fh->name);
1524
1525   return 1;
1526 }
1527
1528
1529 int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1530 {
1531   va_list ap;
1532   struct aim_conn_t *oftconn;
1533   struct aim_fileheader_t *fh;
1534   char *path, *cookie;
1535
1536   FILE *file;
1537
1538   va_start(ap, command);
1539   oftconn = va_arg(ap, struct aim_conn_t *);
1540   fh = va_arg(ap, struct aim_fileheader_t *);
1541   cookie = va_arg(ap, char *);
1542   va_end(ap);
1543
1544   printf("faimtest: sending file %s.\n", fh->name);
1545
1546   if( (path = (char *)calloc(1, strlen(sess->oft.listingdir) +strlen(fh->name)+2)) == NULL) {
1547     perror("calloc:");
1548     printf("faimtest: error in calloc of path\n");
1549     return 0; /* XXX: no idea what winaim expects here =) */
1550   }
1551   
1552   snprintf(path, strlen(sess->oft.listingdir)+strlen(fh->name)+2, "%s/%s", sess->oft.listingdir, fh->name);
1553
1554
1555   if( (file = fopen(path, "r")) == NULL) {
1556     printf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
1557     return 0;
1558   }
1559
1560   if (aim_getfile_send(oftconn, file, fh) == -1) {
1561     printf("faimtest: getfile_send failed. damn.\n");
1562   } else {
1563     printf("faimtest: looks like getfile went clean\n");
1564   }
1565
1566   free(fh);  
1567   return 1;
1568 }
1569
1570 int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) 
1571 {
1572   va_list ap;
1573   struct aim_conn_t *conn;
1574   struct aim_fileheader_t *fh;
1575
1576   va_start(ap, command);
1577   conn = va_arg(ap, struct aim_conn_t *);
1578   fh = va_arg(ap, struct aim_fileheader_t *);
1579   va_end(ap);
1580
1581   printf("faimtest: completed file transfer for %s.\n", fh->name);
1582
1583   /*  aim_conn_kill(sess, &conn); */ /* we'll let winaim close the conn */
1584   return 1;
1585 }
1586
1587 int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1588 {
1589   va_list ap;
1590   struct aim_conn_t *conn;
1591   char *sn;
1592
1593   va_start(ap, command);
1594   conn = va_arg(ap, struct aim_conn_t *);
1595   sn = va_arg(ap, char *);
1596   va_end(ap);
1597
1598   aim_conn_kill(sess, &conn);
1599
1600   printf("faimtest: getfile: disconnected from %s\n", sn);
1601   return 1;
1602 }
1603 #endif
1604
1605 int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1606 {
1607   static char *codes[5] = {"invalid",
1608                            "change",
1609                            "warning",
1610                            "limit",
1611                            "limit cleared"};
1612   va_list ap;
1613   int code;
1614   unsigned long parmid, windowsize, clear, alert, limit, disconnect;
1615   unsigned long currentavg, maxavg;
1616
1617   va_start(ap, command); 
1618
1619   /* See code explanations below */
1620   code = va_arg(ap, int);
1621
1622   /*
1623    * Known parameter ID's...
1624    *   0x0001  Warnings
1625    *   0x0003  BOS (normal ICBMs, userinfo requests, etc)
1626    *   0x0005  Chat messages
1627    */
1628   parmid = va_arg(ap, unsigned long);
1629
1630   /*
1631    * Not sure what this is exactly.  I think its the temporal 
1632    * relation factor (ie, how to make the rest of the numbers
1633    * make sense in the real world). 
1634    */
1635   windowsize = va_arg(ap, unsigned long);
1636
1637   /* Explained below */
1638   clear = va_arg(ap, unsigned long);
1639   alert = va_arg(ap, unsigned long);
1640   limit = va_arg(ap, unsigned long);
1641   disconnect = va_arg(ap, unsigned long);
1642   currentavg = va_arg(ap, unsigned long);
1643   maxavg = va_arg(ap, unsigned long);
1644
1645   va_end(ap);
1646
1647
1648   printf("faimtest: rate %s (paramid 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1649          (code < 5)?codes[code]:"invalid",
1650          parmid,
1651          currentavg, maxavg,
1652          alert, clear,
1653          limit, disconnect,
1654          windowsize);
1655
1656   if (code == AIM_RATE_CODE_CHANGE) {
1657     /*
1658      * Not real sure when these get sent.
1659      */
1660     if (currentavg >= clear)
1661       aim_conn_setlatency(command->conn, 0);
1662
1663   } else if (code == AIM_RATE_CODE_WARNING) {
1664     /*
1665      * We start getting WARNINGs the first time we go below the 'alert'
1666      * limit (currentavg < alert) and they stop when either we pause
1667      * long enough for currentavg to go above 'clear', or until we
1668      * flood it bad enough to go below 'limit' (and start getting
1669      * LIMITs instead) or even further and go below 'disconnect' and 
1670      * get disconnected completely (and won't be able to login right
1671      * away either).
1672      */
1673     aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ 
1674
1675   } else if (code == AIM_RATE_CODE_LIMIT) {
1676     /*
1677      * When we hit LIMIT, messages will start getting dropped.
1678      */
1679     aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ 
1680
1681   } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
1682     /*
1683      * The limit is cleared when curavg goes above 'clear'.
1684      */
1685     aim_conn_setlatency(command->conn, 0); 
1686   }
1687
1688   return 1;
1689 }
1690
1691 int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
1692 {
1693   va_list ap;
1694   int newevil;
1695   struct aim_userinfo_s *userinfo;
1696
1697   va_start(ap, command);
1698   newevil = va_arg(ap, int);
1699   userinfo = va_arg(ap, struct aim_userinfo_s *);
1700   va_end(ap);
1701
1702   /*
1703    * Evil Notifications that are lacking userinfo->sn are anon-warns
1704    * if they are an evil increases, but are not warnings at all if its
1705    * a decrease (its the natural backoff happening).
1706    *
1707    * newevil is passed as an int representing the new evil value times
1708    * ten.
1709    */
1710   printf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1711
1712   return 1;
1713 }
This page took 0.170982 seconds and 5 git commands to generate.