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