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