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