source: aim.c @ 440ce01

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 440ce01 was 440ce01, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
added owl_prototypes.h to repository fix outgoing aim message to send the real text display sender and recipient of owl messages
  • Property mode set to 100644
File size: 78.6 KB
Line 
1#include <stdio.h>
2#include <stdio.h>
3#include <sys/stat.h>
4#include "owl.h"
5
6/**********************************************************************/
7
8struct owlfaim_priv {
9  char *aimbinarypath;
10  char *screenname;
11  char *password;
12  char *server;
13  char *proxy;
14  char *proxyusername;
15  char *proxypass;
16  char *ohcaptainmycaptain;
17  int connected;
18
19  FILE *listingfile;
20  char *listingpath;
21
22  fu8_t *buddyicon;
23  int buddyiconlen;
24  time_t buddyiconstamp;
25  fu16_t buddyiconsum;
26};
27
28static char *msgerrreasons[] = {
29        "Invalid error",
30        "Invalid SNAC",
31        "Rate to host",
32        "Rate to client",
33        "Not logged on",
34        "Service unavailable",
35        "Service not defined",
36        "Obsolete SNAC",
37        "Not supported by host",
38        "Not supported by client",
39        "Refused by client",
40        "Reply too big",
41        "Responses lost",
42        "Request denied",
43        "Busted SNAC payload",
44        "Insufficient rights",
45        "In local permit/deny",
46        "Too evil (sender)",
47        "Too evil (receiver)",
48        "User temporarily unavailable",
49        "No match",
50        "List overflow",
51        "Request ambiguous",
52        "Queue full",
53        "Not while on AOL",
54};
55static int msgerrreasonslen = 25;
56
57static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
58static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
60int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
61int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
62void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
63static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
64int login(aim_session_t *sess, const char *sn, const char *passwd);
65static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
66int logout(aim_session_t *sess);
67
68static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...);
69static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...);
70static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...);
71static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...);
72static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...);
73static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...);
74static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...);
75static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...);
76static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...);
77static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...);
78static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname);
79static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...);
80static void printuserflags(fu16_t flags);
81static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...);
82static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr);
83static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args);
84static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
85static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...);
86static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...);
87static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...);
88int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...);
89static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...);
90static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...);
91static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...);
92static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...);
93static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...);
94static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...);
95static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...);
96static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...);
97static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...);
98static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...);
99static int migrate(aim_session_t *sess, aim_frame_t *fr, ...);
100static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...);
101static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...);
102static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...);
103static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...);
104static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...);
105
106static int directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...);
107static int directim_typing(aim_session_t *sess, aim_frame_t *fr, ...);
108static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...);
109static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...);
110static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...);
111static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...);
112static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...);
113static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...);
114static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...);
115static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...);
116static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...);
117static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...);
118void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn);
119void getfile_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
120void directim_start(aim_session_t *sess, const char *sn);
121void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
122
123void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
124void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
125
126/*****************************************************************/
127
128void owl_aim_init(void)
129{
130  aim_session_init(owl_global_get_aimsess(&g), AIM_SESS_FLAGS_NONBLOCKCONNECT, 1);
131  aim_setdebuggingcb(owl_global_get_aimsess(&g), faimtest_debugcb);
132}
133
134int owl_aim_login(char *screenname, char *password)
135{
136  int ret;
137  struct owlfaim_priv *priv;
138
139  /* this will leak, I know and just don't care right now */
140  priv=owl_malloc(sizeof(struct owlfaim_priv));
141  memset(priv, 0, sizeof(struct owlfaim_priv));
142
143  priv->screenname = owl_strdup(screenname);
144  priv->password = owl_strdup(password);
145  priv->server = "login.oscar.aol.com";
146  owl_global_get_aimsess(&g)->aux_data = priv;
147
148 
149  /* login */
150  ret=login(owl_global_get_aimsess(&g), priv->screenname, priv->password);
151  if (ret) {
152    owl_global_set_aimnologgedin(&g);
153    /* printf("login returned %i\n"); */
154    return(-1);
155  }
156  owl_global_set_aimloggedin(&g, screenname);
157  return(0);
158}
159
160void owl_aim_logout(void)
161{
162  /* need to check if it's connected first, I think */
163  aim_session_kill(owl_global_get_aimsess(&g));
164  owl_global_set_aimnologgedin(&g);
165}
166
167int owl_aim_send_im(char *to, char *msg)
168{
169  aim_send_im(owl_global_get_aimsess(&g), to, AIM_IMFLAGS_ACK, msg);
170}
171
172void owl_aim_chat_join(char *chatroom)
173{
174}
175
176void owl_aim_chat_leave(char *chatroom)
177{
178}
179
180int owl_aim_chat_sendmsg(char *chatroom, char *msg)
181{
182}
183
184int owl_aim_process_events() {
185  int ret;
186  aim_session_t *aimsess;
187  aim_conn_t *waitingconn = NULL;
188  struct timeval tv;
189  int selstat = 0;
190  struct owlfaim_priv *priv;
191
192  aimsess=owl_global_get_aimsess(&g);
193  priv = (struct owlfaim_priv *) &(aimsess->aux_data);
194
195  /* do a select without blocking */
196  tv.tv_sec = 0;
197  tv.tv_usec = 0;
198  waitingconn = aim_select(aimsess, &tv, &selstat);
199
200  if (owl_global_is_aimnop_time(&g)) {
201    aim_flap_nop(aimsess, aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS));
202    owl_global_aimnop_sent(&g);
203  }
204
205  if (selstat == -1) { /* error */
206    /* keepgoing = 0; */ /* fall through */
207  } else if (selstat == 0) { /* no events pending */
208    /* printf("selstat == 0\n"); */
209  } else if (selstat == 1) { /* outgoing data pending */
210    /* printf("selstat == 1\n"); */
211    aim_tx_flushqueue(aimsess);
212  } else if (selstat == 2) { /* incoming data pending */
213    /* printf("selstat == 2\n"); */
214    if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
215      if (aim_handlerendconnect(aimsess, waitingconn) < 0) {
216        /* printf("connection error (rend out)\n"); */
217        aim_conn_kill(aimsess, &waitingconn);
218      }
219    } else {
220      if (aim_get_command(aimsess, waitingconn) >= 0) {
221        aim_rxdispatch(aimsess);
222      } else {
223        /* printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype); */
224        /* we should have callbacks for all these, else the library will do the conn_kill for us. */
225        if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
226          if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
227            /* printf("disconnected from %s\n", aim_directim_getsn(waitingconn)); */
228            aim_conn_kill(aimsess, &waitingconn);
229          }
230        } else {
231          aim_conn_kill(aimsess, &waitingconn);
232        }
233        if (!aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS)) {
234          /* printf("major connection error\n"); */
235          /* break; */
236          /* we should probably kill the session */
237        }
238      }
239    }
240  }
241  /* free(priv->buddyicon); */
242  /* exit(0); */
243}
244
245static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
246{
247  return;
248}
249
250
251static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
252{
253  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
254  struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
255  char *key;
256  va_list ap;
257
258  va_start(ap, fr);
259  key = va_arg(ap, char *);
260  va_end(ap);
261
262  aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key);
263
264  return 1;
265}
266
267
268static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...)
269{
270  va_list ap;
271  struct aim_authresp_info *info;
272  aim_conn_t *bosconn;
273
274  va_start(ap, fr);
275  info = va_arg(ap, struct aim_authresp_info *);
276  va_end(ap);
277
278  /* printf("Screen name: %s\n", info->sn); */
279
280  /*
281   * Check for error.
282   */
283  if (info->errorcode || !info->bosip || !info->cookie) {
284    /*
285    printf("Login Error Code 0x%04x\n", info->errorcode);
286    printf("Error URL: %s\n", info->errorurl);
287    */
288    aim_conn_kill(sess, &fr->conn);
289    return 1;
290  }
291
292  /*
293  printf("Reg status: %d\n", info->regstatus);
294  printf("Email: %s\n", info->email);
295  printf("BOS IP: %s\n", info->bosip);
296  */
297
298  /* printf("Closing auth connection...\n"); */
299  aim_conn_kill(sess, &fr->conn);
300  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, info->bosip))) {
301    /* printf("could not connect to BOS: internal error\n"); */
302    return 1;
303  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
304    /* printf("could not connect to BOS\n"); */
305    aim_conn_kill(sess, &bosconn);
306    return 1;
307  }
308  addcb_bos(sess, bosconn);
309  aim_sendcookie(sess, bosconn, info->cookie);
310  return 1;
311}
312
313int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
314{
315#if 0
316  /* XXX fix libfaim to support this */
317  printf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
318
319  /*
320   * This is an alternate location for starting the login process.
321   */
322  /* XXX should do more checking to make sure its really the right AUTH conn */
323  if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
324    /* do NOT send a flapversion, request_login will send it if needed */
325    aim_request_login(sess, fr->conn, priv->screenname);
326    /* printf("faimtest: login request sent\n"); */
327  }
328#endif
329
330  return 1;
331}
332
333
334int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
335{
336  return 1;
337}
338
339void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
340{
341
342  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
343  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
344
345  aim_conn_addhandler(sess, bosconn, 0x0013, 0x0003, ssirights, 0);
346  aim_conn_addhandler(sess, bosconn, 0x0013, 0x0006, ssidata, 0);
347  aim_conn_addhandler(sess, bosconn, 0x0013, 0x000f, ssidatanochange, 0);
348  aim_conn_addhandler(sess, bosconn, 0x0008, 0x0002, handlepopup, 0);
349  aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
350  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
351  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
352  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
353  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
354  aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
355  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
356  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
357  aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
358  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
359  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
360  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
361  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
362  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
363  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
364  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
365  aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
366  aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
367  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
368  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
369  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
370
371  aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
372  aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
373  aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
374  aim_conn_addhandler(sess, bosconn, 0x0001, 0x000b, serverpause, 0);
375  aim_conn_addhandler(sess, bosconn, 0x0001, 0x0012, migrate, 0);
376  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, offlinemsg, 0);
377  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
378
379  #ifdef MID_REWROTE_ALL_THE_CRAP
380  aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
381  #endif
382
383  return;
384}
385
386static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
387{
388  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
389  char buddies[128]; /* this is the new buddy list */
390  char profile[256]; /* this is the new profile */
391  char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
392
393  /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
394  /*  snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah");
395  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
396on them.", priv->ohcaptainmycaptain);
397  */
398
399  /*
400  snprintf(buddies, sizeof(buddies), "jagworks&jkretch76&");
401  snprintf(profile, sizeof(profile), "Hello.<br>This is a test");
402  */
403
404  aim_reqpersonalinfo(sess, fr->conn);
405  aim_bos_reqlocaterights(sess, fr->conn);
406
407  /*aim_bos_setprofile(sess, fr->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE | AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS | AIM_CAPS_SENDBUDDYLIST | AIM_CAPS_ICQ | AIM_CAPS_ICQUNKNOWN | AIM_CAPS_ICQRTF | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_TRILLIANCRYPT); */
408  aim_bos_setprofile(sess, fr->conn, profile, awaymsg, AIM_CAPS_SENDBUDDYLIST | AIM_CAPS_CHAT | AIM_CAPS_ICQ | AIM_CAPS_ICQUNKNOWN | AIM_CAPS_ICQRTF | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_TRILLIANCRYPT);
409  aim_bos_reqbuddyrights(sess, fr->conn);
410
411  /* send the buddy list and profile (required, even if empty) */
412  aim_bos_setbuddylist(sess, fr->conn, buddies);
413
414  aim_reqicbmparams(sess);
415
416  aim_bos_reqrights(sess, fr->conn);
417  /* set group permissions -- all user classes */
418  aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
419  aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE);
420
421  return 1;
422}
423
424int login(aim_session_t *sess, const char *sn, const char *passwd)
425{
426  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
427  aim_conn_t *authconn;
428
429  if (sn) priv->screenname = strdup(sn);
430  if (passwd) priv->password = strdup(passwd);
431  if (priv->proxy) aim_setupproxy(sess, priv->proxy, priv->proxyusername, priv->proxypass);
432
433  if (!priv->screenname || !priv->password) {
434    /* printf("need SN and password\n"); */
435    return -1;
436  }
437
438  if (!(authconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, priv->server ? priv->server : FAIM_LOGIN_SERVER))) {
439    /* printf("internal connection error during login\n"); */
440    return (-1);
441  } else if (authconn->fd == -1) {
442    if (authconn->status & AIM_CONN_STATUS_RESOLVERR) {
443      /* printf("could not resolve authorizer name\n");*/
444    } else if (authconn->status & AIM_CONN_STATUS_CONNERR) {
445      /* printf("could not connect to authorizer\n"); */
446    }
447    aim_conn_kill(sess, &authconn);
448
449    return (-1);
450  }
451
452  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
453  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
454  aim_conn_addhandler(sess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0);
455  aim_conn_addhandler(sess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0);
456
457  /* If the connection is in progress, this will just be queued */
458  aim_request_login(sess, authconn, priv->screenname);
459
460  /* printf("login request sent\n"); */
461
462  return(0);
463}
464
465
466static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
467{
468  aim_clientready(sess, fr->conn);
469  /* printf("initialization done for admin connection\n"); */
470  return(1);
471}
472
473int logout(aim_session_t *sess)
474{
475  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
476
477  aim_session_kill(sess);
478
479  /* kretch
480  if (faimtest_init() == -1)
481    printf("faimtest_init failed\n");
482  */
483
484  return(0);
485}
486
487/**************************************************************************************************/
488
489static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
490{
491  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
492  va_list ap;
493  fu16_t code;
494  char *msg;
495 
496  va_start(ap, fr);
497  code = va_arg(ap, int);
498  msg = va_arg(ap, char *);
499  va_end(ap);
500 
501  /* printf("connerr: Code 0x%04x: %s\n", code, msg); */
502  aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
503 
504  priv->connected = 0;
505 
506  return 1;
507}
508
509static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
510{
511  int status;
512  va_list ap;
513 
514  va_start(ap, fr);
515  status = va_arg(ap, int); /* status code of confirmation request */
516  va_end(ap);
517 
518  /* printf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown"); */
519 
520  return 1;
521}
522
523static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
524{
525  fu16_t change = 0, perms, type;
526  int length, str;
527  char *val;
528  va_list ap;
529 
530  va_start(ap, fr);
531  change = va_arg(ap, int);
532  perms = (fu16_t)va_arg(ap, unsigned int);
533  type = (fu16_t)va_arg(ap, unsigned int);
534  length = va_arg(ap, int);
535  val = va_arg(ap, char *);
536  str = va_arg(ap, int);
537  va_end(ap);
538 
539  /* printf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)"); */
540 
541  return 1;
542}
543
544
545static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
546{
547  va_list ap;
548  struct aim_redirect_data *redir;
549 
550  va_start(ap, fr);
551  redir = va_arg(ap, struct aim_redirect_data *);
552 
553  if (redir->group == 0x0005) {  /* Adverts */
554   
555  } else if (redir->group == 0x0007) {  /* Authorizer */
556    aim_conn_t *tstconn;
557   
558    tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, redir->ip);
559    if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
560      /* printf("unable to reconnect with authorizer\n"); */
561    } else {
562      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
563      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
564      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
565      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
566      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
567      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
568      /* Send the cookie to the Auth */
569      aim_sendcookie(sess, tstconn, redir->cookie);
570      /* printf("sent cookie to authorizer host\n"); */
571    }
572  } else if (redir->group == 0x000d) {  /* ChatNav */
573    chatnav_redirect(sess, redir);
574  } else if (redir->group == 0x000e) { /* Chat */
575    chat_redirect(sess, redir);
576  } else {
577    /* printf("uh oh... got redirect for unknown service 0x%04x!!\n", redir->group); */
578  }
579  va_end(ap);
580  return 1;
581}
582
583static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
584{
585  struct aim_icbmparameters *params;
586  va_list ap;
587 
588  va_start(ap, fr);
589  params = va_arg(ap, struct aim_icbmparameters *);
590  va_end(ap);
591 
592  /* printf("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", params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval); */
593     
594  /*
595  * Set these to your taste, or client medium.  Setting minmsginterval
596  * higher is good for keeping yourself from getting flooded (esp
597  * if you're on a slow connection or something where that would be
598  * useful).
599  */
600  params->maxmsglen = 8000;
601  params->minmsginterval = 0; /* in milliseconds */
602  aim_seticbmparam(sess, params);
603 
604  return 1;
605}
606
607static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
608{
609  va_list ap;
610  fu16_t maxbuddies, maxwatchers;
611 
612  va_start(ap, fr);
613  maxbuddies = va_arg(ap, int);
614  maxwatchers = va_arg(ap, int);
615  va_end(ap);
616 
617  /* printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); */
618 
619  aim_ssi_reqrights(sess, fr->conn);
620 
621  return 1;
622}
623
624static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
625{
626  va_list ap;
627  fu16_t maxpermits, maxdenies;
628 
629  va_start(ap, fr);
630  maxpermits = va_arg(ap, int);
631  maxdenies = va_arg(ap, int);
632  va_end(ap);
633 
634  /* printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); */
635  aim_clientready(sess, fr->conn);
636  /* printf("officially connected to BOS.\n"); */
637  aim_icq_reqofflinemsgs(sess);
638  return 1;
639}
640
641static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
642{
643  va_list ap;
644  fu16_t maxsiglen;
645 
646  va_start(ap, fr);
647  maxsiglen = va_arg(ap, int);
648  va_end(ap);
649 
650  /* printf("locate rights: max signature length = %d\n", maxsiglen); */
651 
652  return 1;
653}
654
655static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
656{
657  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
658  va_list ap;
659  fu16_t interval;
660 
661  va_start(ap, fr);
662  interval = va_arg(ap, int);
663  va_end(ap);
664 
665  /* printf("minimum report interval: %d (seconds?)\n", interval); */
666 
667  if (!priv->connected) {
668    priv->connected++;
669  }
670  aim_reqicbmparams(sess);
671  return 1;
672}
673
674static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
675{
676  static char *codes[] = {
677    "Unknown",
678    "Mandatory upgrade",
679    "Advisory upgrade",
680    "System bulletin",
681    "Top o' the world!"
682  };
683  static int codeslen = 5;
684  char *msg;
685  fu16_t id;
686  va_list ap;
687 
688  return 1;
689 
690  va_start(ap, fr);
691  id = va_arg(ap, int);
692  msg = va_arg(ap, char *);
693  va_end(ap);
694 
695  /* printf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown"); */
696 
697  return 1;
698}
699
700/*
701 * This is a little more complicated than it looks.  The module
702 * name (proto, boscore, etc) may or may not be given.  If it is
703 * not given, then use aim.exe.  If it is given, put ".ocm" on the
704 * end of it.
705 *
706 * Now, if the offset or length requested would cause a read past
707 * the end of the file, then the request is considered invalid.  Invalid
708 * requests are processed specially.  The value hashed is the
709 * the request, put into little-endian (eight bytes: offset followed
710 * by length). 
711 *
712 * Additionally, if the request is valid, the length is mod 4096.  It is
713 * important that the length is checked for validity first before doing
714 * the mod.
715 *
716 * Note to Bosco's Brigade: if you'd like to break this, put the
717 * module name on an invalid request.
718 *
719 */
720static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
721{
722  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
723  FILE *f;
724  static const char defaultmod[] = "aim.exe";
725  char *filename = NULL;
726  struct stat st;
727  unsigned char *buf;
728  int invalid = 0;
729 
730  if (!bufret || !buflenret)
731    return -1;
732 
733  if (modname) {
734    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
735      /* perror("memrequest: malloc"); */
736      return -1;
737    }
738    sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
739  } else {
740    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
741      /* perror("memrequest: malloc"); */
742      return -1;
743    }
744    sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
745  }
746 
747  if (stat(filename, &st) == -1) {
748    if (!modname) {
749      /* perror("memrequest: stat"); */
750      free(filename);
751      return -1;
752    }
753    invalid = 1;
754  }
755 
756  if (!invalid) {
757    if ((offset > st.st_size) || (len > st.st_size))
758      invalid = 1;
759    else if ((st.st_size - offset) < len)
760      len = st.st_size - offset;
761    else if ((st.st_size - len) < len)
762      len = st.st_size - len;
763  }
764 
765  if (!invalid && len) {
766    len %= 4096;
767  }
768 
769  if (invalid) {
770    int i;
771   
772    free(filename); /* not needed */
773    printf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
774    i = 8;
775    if (modname) {
776      i+=strlen(modname);
777    }
778   
779    if (!(buf = malloc(i))) {
780      return -1;
781    }
782   
783    i=0;
784   
785    if (modname) {
786      memcpy(buf, modname, strlen(modname));
787      i+=strlen(modname);
788    }
789   
790    /* Damn endianness. This must be little (LSB first) endian. */
791    buf[i++] = offset & 0xff;
792    buf[i++] = (offset >> 8) & 0xff;
793    buf[i++] = (offset >> 16) & 0xff;
794    buf[i++] = (offset >> 24) & 0xff;
795    buf[i++] = len & 0xff;
796    buf[i++] = (len >> 8) & 0xff;
797    buf[i++] = (len >> 16) & 0xff;
798    buf[i++] = (len >> 24) & 0xff;
799   
800    *bufret = buf;
801    *buflenret = i;
802  } else {
803    if (!(buf = malloc(len))) {
804      free(filename);
805      return -1;
806    }
807    /* printf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); */
808    if (!(f = fopen(filename, "r"))) {
809      /* perror("memrequest: fopen"); */
810      free(filename);
811      free(buf);
812      return -1;
813    }
814   
815    free(filename);
816   
817    if (fseek(f, offset, SEEK_SET) == -1) {
818      /* perror("memrequest: fseek"); */
819      fclose(f);
820      free(buf);
821      return -1;
822    }
823   
824    if (fread(buf, len, 1, f) != 1) {
825      /* perror("memrequest: fread"); */
826      fclose(f);
827      free(buf);
828      return -1;
829    }
830   
831    fclose(f);
832    *bufret = buf;
833    *buflenret = len;
834  }
835  return 0; /* success! */
836}
837
838/*
839 * This will get an offset and a length.  The client should read this
840 * data out of whatever AIM.EXE binary the user has provided (hopefully
841 * it matches the client information thats sent at login) and pass a
842 * buffer back to libfaim so it can hash the data and send it to AOL for
843 * inspection by the client police.
844 */
845static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
846{
847  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
848  va_list ap;
849  fu32_t offset, len;
850  char *modname;
851  unsigned char *buf;
852  int buflen;
853 
854  va_start(ap, fr);
855  offset = va_arg(ap, fu32_t);
856  len = va_arg(ap, fu32_t);
857  modname = va_arg(ap, char *);
858  va_end(ap);
859 
860  if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
861    aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
862    free(buf);
863  } else {
864    /* printf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname); */
865    aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
866  }
867  return 1;
868}
869
870static void printuserflags(fu16_t flags)
871{
872
873  if (flags & AIM_FLAG_UNCONFIRMED)
874    printf("UNCONFIRMED ");
875  if (flags & AIM_FLAG_ADMINISTRATOR)
876    printf("ADMINISTRATOR ");
877  if (flags & AIM_FLAG_AOL)
878    printf("AOL ");
879  if (flags & AIM_FLAG_OSCAR_PAY)
880    printf("OSCAR_PAY ");
881  if (flags & AIM_FLAG_FREE)
882    printf("FREE ");
883  if (flags & AIM_FLAG_AWAY)
884    printf("AWAY ");
885  if (flags & AIM_FLAG_ICQ)
886    printf("ICQ ");
887  if (flags & AIM_FLAG_WIRELESS)
888    printf("WIRELESS ");
889  if (flags & AIM_FLAG_ACTIVEBUDDY)
890    printf("ACTIVEBUDDY ");
891 
892  return;
893}
894
895static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
896{
897  aim_userinfo_t *userinfo;
898  char *prof_encoding = NULL;
899  char *prof = NULL;
900  fu16_t inforeq = 0;
901
902  va_list ap;
903  va_start(ap, fr);
904  userinfo = va_arg(ap, aim_userinfo_t *);
905  inforeq = (fu16_t)va_arg(ap, unsigned int);
906  prof_encoding = va_arg(ap, char *);
907  prof = va_arg(ap, char *);
908  va_end(ap);
909
910  return (1);
911
912  printf("userinfo: sn: %s\n", userinfo->sn);
913  printf("userinfo: warnlevel: %f\n", aim_userinfo_warnlevel(userinfo));
914  printf("userinfo: flags: 0x%04x = ", userinfo->flags);
915  printuserflags(userinfo->flags);
916  printf("\n");
917 
918  printf("userinfo: membersince: %lu\n", userinfo->membersince);
919  printf("userinfo: onlinesince: %lu\n", userinfo->onlinesince);
920  printf("userinfo: idletime: 0x%04x\n", userinfo->idletime);
921  printf("userinfo: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
922 
923 
924  if (inforeq == AIM_GETINFO_GENERALINFO) {
925    printf("userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
926    printf("userinfo: prof: %s\n", prof ? prof : "[none]");
927  } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
928    printf("userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
929    printf("userinfo: awaymsg: %s\n", prof ? prof : "[none]");
930  } else if (inforeq == AIM_GETINFO_CAPABILITIES) {
931    printf("userinfo: capabilities: see above\n");
932  } else {
933    printf("userinfo: unknown info request\n");
934  }
935 
936  return 1;
937}
938
939static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr)
940{
941  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
942 
943  if (!strncmp(tmpstr, "disconnect", 10)) {
944    logout(sess);
945  } else if (strstr(tmpstr, "goodday")) {
946    aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
947  } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
948    struct aim_sendimext_args args;
949    static const char iconmsg[] = {"I have an icon"};
950   
951    args.destsn = userinfo->sn;
952    args.flags = AIM_IMFLAGS_HASICON;
953    args.msg = iconmsg;
954    args.msglen = strlen(iconmsg);
955    args.iconlen = priv->buddyiconlen;
956    args.iconstamp = priv->buddyiconstamp;
957    args.iconsum = priv->buddyiconsum;
958   
959    aim_send_im_ext(sess, &args);
960   
961  } else if (strstr(tmpstr, "sendbin")) {
962    struct aim_sendimext_args args;
963    static const unsigned char data[] = {
964      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
965      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
966      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
967      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
968      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
969      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
970    };
971   
972    /*
973     * I put this here as a demonstration of how to send
974     * arbitrary binary data via OSCAR ICBM's without the need
975     * for escape or baseN encoding of any sort. 
976     *
977     * Apparently if you set the charset to something WinAIM
978     * doesn't recognize, it will completly ignore the message.
979     * That is, it will not display anything in the conversation
980     * window for the user that recieved it.
981     *
982     * HOWEVER, if they do not have a conversation window open
983     * for you, a new one will be created, but it will not have
984     * any messages in it.  Therefore sending these things could
985     * be a great way to seemingly subliminally convince people
986     * to talk to you...
987     *
988     */
989    args.destsn = userinfo->sn;
990    args.flags = AIM_IMFLAGS_CUSTOMCHARSET;
991    args.charset = args.charsubset = 0x4242;
992    args.msg = data;
993    args.msglen = sizeof(data);
994    aim_send_im_ext(sess, &args);
995   } else if (strstr(tmpstr, "sendmulti")) {
996    struct aim_sendimext_args args;
997    aim_mpmsg_t mpm;
998    static const fu16_t unidata[] = { /* "UNICODE." */
999      0x0055, 0x004e, 0x0049, 0x0043,
1000      0x004f, 0x0044, 0x0045, 0x002e,
1001    };
1002    static const int unidatalen = 8;
1003   
1004    /*
1005     * This is how multipart messages should be sent.
1006     *
1007     * This should render as:
1008     *        "Part 1, ASCII.  UNICODE.Part 3, ASCII.  "
1009     */
1010   
1011    aim_mpmsg_init(sess, &mpm);
1012    aim_mpmsg_addascii(sess, &mpm, "Part 1, ASCII.  ");
1013    aim_mpmsg_addunicode(sess, &mpm, unidata, unidatalen);
1014    aim_mpmsg_addascii(sess, &mpm, "Part 3, ASCII.  ");
1015   
1016    args.destsn = userinfo->sn;
1017    args.flags = AIM_IMFLAGS_MULTIPART;
1018    args.mpmsg = &mpm;
1019   
1020    aim_send_im_ext(sess, &args);
1021   
1022    aim_mpmsg_free(sess, &mpm);
1023   
1024  } else if (strstr(tmpstr, "sendprebin")) {
1025    static const unsigned char data[] = {
1026      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1027      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1028      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1029      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1030      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1031      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1032    };
1033    struct aim_sendimext_args args;
1034    aim_mpmsg_t mpm;
1035   
1036    /*
1037     * This demonstrates sending a human-readable preamble,
1038     * and then arbitrary binary data.
1039     *
1040     * This means that you can very inconspicuously send binary
1041     * attachments to other users.  In WinAIM, this appears as
1042     * though it only had the ASCII portion.
1043     *
1044     */
1045   
1046    aim_mpmsg_init(sess, &mpm);
1047    aim_mpmsg_addascii(sess, &mpm, "This message has binary data.");
1048    aim_mpmsg_addraw(sess, &mpm, 0x4242, 0x4242, data, sizeof(data));
1049   
1050    args.destsn = userinfo->sn;
1051    args.flags = AIM_IMFLAGS_MULTIPART;
1052    args.mpmsg = &mpm;
1053   
1054    aim_send_im_ext(sess, &args);
1055    aim_mpmsg_free(sess, &mpm);
1056   
1057  } else if (strstr(tmpstr, "havefeat")) {
1058    struct aim_sendimext_args args;
1059    static const char featmsg[] = {"I have nifty features."};
1060    fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
1061   
1062    args.destsn = userinfo->sn;
1063    args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
1064    args.msg = featmsg;
1065    args.msglen = strlen(featmsg);
1066    args.features = features;
1067    args.featureslen = sizeof(features);
1068   
1069    aim_send_im_ext(sess, &args);
1070  } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
1071    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1072  } else if (strstr(tmpstr, "warnme")) {
1073    /* printf("icbm: sending non-anon warning\n"); */
1074    aim_send_warning(sess, conn, userinfo->sn, 0);
1075  } else if (strstr(tmpstr, "anonwarn")) {
1076    /* printf("icbm: sending anon warning\n"); */
1077    aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
1078  } else if (strstr(tmpstr, "setdirectoryinfo")) {
1079    /* printf("icbm: sending backwards profile data\n"); */
1080    aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1081  } else if (strstr(tmpstr, "setinterests")) {
1082    /* printf("icbm: setting fun interests\n"); */
1083    aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1084  } else if (!strncmp(tmpstr, "getfile", 7)) {
1085    if (!priv->ohcaptainmycaptain) {
1086      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1087    } else {
1088      getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1089    }
1090  } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1091    aim_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1092  } else if (!strncmp(tmpstr, "create", 6)) {
1093    aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1094  } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1095    aim_conn_t *chatnavconn;
1096    if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1097      aim_conn_kill(sess, &chatnavconn);
1098  } else if (!strncmp(tmpstr, "join", 4)) {
1099    aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1100  } else if (!strncmp(tmpstr, "leave", 5)) {
1101    aim_chat_leaveroom(sess, "worlddomination");
1102  } else if (!strncmp(tmpstr, "getinfo", 7)) {
1103    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1104    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1105    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_CAPABILITIES);
1106  } else if (strstr(tmpstr, "open directim")) {
1107    directim_start(sess, userinfo->sn);
1108  } else if(strstr(tmpstr, "lookup")) {
1109    aim_usersearch_address(sess, conn, "mid@auk.cx");
1110  } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1111    aim_send_im(sess, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1112  } else if (!strncmp(tmpstr, "reqadmin", 8)) {
1113    aim_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1114  } else if (!strncmp(tmpstr, "changenick", 10)) {
1115    aim_admin_setnick(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "diputs8  1");
1116  } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1117    aim_admin_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1118  } else if (!strncmp(tmpstr, "reqemail", 8)) {
1119    aim_admin_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1120  } else if (!strncmp(tmpstr, "changepass", 8)) {
1121    aim_admin_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1122  } else if (!strncmp(tmpstr, "setemail", 8)) {
1123    aim_admin_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1124  } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1125    int i;
1126   
1127    i = atoi(tmpstr+8);
1128    if (i < 10000) {
1129      char *newbuf;
1130      int z;
1131     
1132      newbuf = malloc(i+1);
1133      for (z = 0; z < i; z++)
1134        newbuf[z] = (z % 10)+0x30;
1135      newbuf[i] = '\0';
1136      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK | AIM_IMFLAGS_AWAY, newbuf);
1137      free(newbuf);
1138    }
1139  } else if (strstr(tmpstr, "seticqstatus")) {
1140    aim_setextstatus(sess, conn, AIM_ICQ_STATE_DND);
1141  } else if (strstr(tmpstr, "rtfmsg")) {
1142    static const char rtfmsg[] = {"{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\froman\\fprq2\\fcharset0 Georgia;}{\\f2\\fmodern\\fprq1\\fcharset0 MS Mincho;}{\\f3\\froman\\fprq2\\fcharset2 Symbol;}}\\viewkind4\\uc1\\pard\\f0\\fs20 Test\\f1 test\\f2\fs44 test\\f3\\fs20 test\\f0\\par}"};
1143    struct aim_sendrtfmsg_args rtfargs;
1144   
1145    memset(&rtfargs, 0, sizeof(rtfargs));
1146    rtfargs.destsn = userinfo->sn;
1147    rtfargs.fgcolor = 0xffffffff;
1148    rtfargs.bgcolor = 0x00000000;
1149    rtfargs.rtfmsg = rtfmsg;
1150    aim_send_rtfmsg(sess, &rtfargs);
1151  } else {
1152    /* printf("unknown command.\n"); */
1153    aim_add_buddy(sess, conn, userinfo->sn);
1154  } 
1155 
1156  return 0;
1157}
1158
1159/*
1160 * Channel 1: Standard Message
1161 */
1162static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1163{
1164  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1165  char *tmpstr;
1166  int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1167  owl_message *m;
1168  char realmsg[8192+1] = {""};
1169  clienttype = aim_fingerprintclient(args->features, args->featureslen);
1170
1171  /*
1172  printf("icbm: sn = \"%s\"\n", userinfo->sn);
1173  printf("icbm: probable client type: %d\n", clienttype);
1174  printf("icbm: warnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1175  printf("icbm: flags = 0x%04x = ", userinfo->flags);
1176  printuserflags(userinfo->flags);
1177  printf("\n");
1178  */
1179
1180  /*
1181  printf("icbm: membersince = %lu\n", userinfo->membersince);
1182  printf("icbm: onlinesince = %lu\n", userinfo->onlinesince);
1183  printf("icbm: idletime = 0x%04x\n", userinfo->idletime);
1184  printf("icbm: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1185  */
1186
1187  /*
1188  printf("icbm: icbmflags = ");
1189  if (args->icbmflags & AIM_IMFLAGS_AWAY) printf("away ");
1190  if (args->icbmflags & AIM_IMFLAGS_ACK) printf("ackrequest ");
1191  if (args->icbmflags & AIM_IMFLAGS_OFFLINE) printf("offline ");
1192  if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) printf("buddyreq ");
1193  if (args->icbmflags & AIM_IMFLAGS_HASICON) printf("hasicon ");
1194  printf("\n");
1195  */
1196
1197  if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET) {
1198    /* printf("icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset); */
1199  }
1200 
1201  /*
1202   * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1203   * characters with their equivelent HTML entity.
1204   */
1205  if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1206    int i;
1207   
1208    for (i = 0; i < args->msglen; i += 2) {
1209      fu16_t uni;
1210
1211      uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1212      if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1213        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1214      } else { /* something else, do UNICODE entity */
1215        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1216      }
1217    }
1218  } else {
1219    /*
1220     * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1221     * no need to do anything special here.  Most
1222     * terminals/whatever will be able to display such characters
1223     * unmodified.
1224     *
1225     * Beware that PC-ASCII 128 through 159 are _not_ actually
1226     * defined in ASCII or ISO 8859-1, and you should send them as
1227     * UNICODE.  WinAIM will send these characters in a UNICODE
1228     * message, so you need to do so as well.
1229     *
1230     * You may not think it necessary to handle UNICODE messages. 
1231     * You're probably wrong.  For one thing, Microsoft "Smart
1232     * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1233     * but real UNICODE). If you don't parse UNICODE at all, your
1234     * users will get a blank message instead of the message
1235     * containing Smart Quotes.
1236     *
1237     */
1238    strncpy(realmsg, args->msg, sizeof(realmsg));
1239  }
1240
1241  /* create a message, and put it on the message queue */
1242  m=owl_malloc(sizeof(owl_message));
1243  owl_message_create_aim(m, userinfo->sn, owl_global_get_aim_screenname(&g), realmsg);
1244  owl_message_set_direction_in(m);
1245  owl_global_messagequeue_addmsg(&g, m);
1246 
1247  /* printf("icbm: message: %s\n", realmsg); */
1248 
1249  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1250    aim_mpmsg_section_t *sec;
1251    int z;
1252
1253    /* printf("icbm: multipart: this message has %d parts\n", args->mpmsg.numparts); */
1254   
1255    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1256      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1257        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data); */
1258      } else {
1259        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset); */
1260      }
1261    }
1262  }
1263 
1264  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1265    aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1266    /* printf("icbm: their icon: iconstamp = %ld, iconlen = 0x%08lx, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum); */
1267  }
1268 
1269  if (realmsg) {
1270    int i = 0;
1271    while (realmsg[i] == '<') {
1272      if (realmsg[i] == '<') {
1273        while (realmsg[i] != '>')
1274          i++;
1275        i++;
1276      }
1277    }
1278    tmpstr = realmsg+i;
1279    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1280  }
1281 
1282  if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
1283    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1284  }
1285 
1286  return 1;
1287}
1288
1289/*
1290 * Channel 2: Rendevous Request
1291 */
1292static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1293{
1294  /*
1295  printf("rendezvous: source sn = %s\n", userinfo->sn);
1296  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1297  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1298  printuserflags(userinfo->flags);
1299  printf("\n");
1300 
1301  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1302  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1303 
1304  printf("rendezvous: message/description = %s\n", args->msg);
1305  printf("rendezvous: encoding = %s\n", args->encoding);
1306  printf("rendezvous: language = %s\n", args->language);
1307  */
1308 
1309  if (args->reqclass == AIM_CAPS_GETFILE) {
1310    getfile_requested(sess, conn, userinfo, args);
1311  } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1312    /* printf("send file!\n"); */
1313  } else if (args->reqclass == AIM_CAPS_CHAT) {
1314    /*
1315    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1316    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1317    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1318    */
1319    /* Automatically join room... */
1320    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1321    aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
1322  } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1323    directim_requested(sess, conn, userinfo, args);
1324  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1325    /* printf("Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length); */
1326  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1327    /* printf("RTF message from %s: (fgcolor = 0x%08lx, bgcolor = 0x%08lx) %s\n", userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg); */
1328  } else {
1329    /* printf("icbm: unknown reqclass (%d)\n", args->reqclass); */
1330  }
1331  return 1;
1332}
1333
1334static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1335{
1336  fu16_t channel;
1337  aim_userinfo_t *userinfo;
1338  va_list ap;
1339  int ret = 0;
1340 
1341  va_start(ap, fr);
1342  channel = (fu16_t)va_arg(ap, unsigned int);
1343  userinfo = va_arg(ap, aim_userinfo_t *);
1344 
1345  if (channel == 1) {
1346    struct aim_incomingim_ch1_args *args;
1347    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1348    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1349  } else if (channel == 2) {
1350    struct aim_incomingim_ch2_args *args;
1351    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1352    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1353  } else {
1354    /* printf("unsupported channel 0x%04x\n", channel); */
1355  }
1356  va_end(ap);
1357  /* printf("icbm: done with ICBM handling (ret = %d)\n", ret); */
1358  return 1;
1359}
1360
1361static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1362{
1363  aim_userinfo_t *userinfo;
1364 
1365  va_list ap;
1366  va_start(ap, fr);
1367  userinfo = va_arg(ap, aim_userinfo_t *);
1368  va_end(ap);
1369  /*
1370    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1371    time(NULL),
1372    userinfo->sn, userinfo->flags,
1373    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1374    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1375    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1376    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1377    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1378    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1379    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1380    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1381    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1382    userinfo->capabilities);
1383  */
1384  return 1;
1385}
1386
1387static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1388{
1389  aim_userinfo_t *userinfo;
1390  va_list ap;
1391 
1392  va_start(ap, fr);
1393  userinfo = va_arg(ap, aim_userinfo_t *);
1394  va_end(ap);
1395
1396  /*
1397  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1398         time(NULL),
1399         userinfo->sn, userinfo->flags,
1400         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1401         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1402         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1403         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1404         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1405         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1406         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1407         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1408         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1409         userinfo->capabilities);
1410  */
1411 
1412  return 1;
1413}
1414
1415/* Used by chat as well. */
1416int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1417{
1418  va_list ap;
1419  fu16_t reason;
1420 
1421  va_start(ap, fr);
1422  reason = (fu16_t)va_arg(ap, unsigned int);
1423  va_end(ap);
1424 
1425  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1426 
1427  return 1;
1428}
1429
1430static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1431{
1432  va_list ap;
1433  char *destsn;
1434  fu16_t reason;
1435 
1436  va_start(ap, fr);
1437  reason = (fu16_t)va_arg(ap, unsigned int);
1438  destsn = va_arg(ap, char *);
1439  va_end(ap);
1440 
1441  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1442 
1443  return 1;
1444}
1445
1446static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1447{
1448  va_list ap;
1449  char *destsn;
1450  fu16_t reason;
1451 
1452  va_start(ap, fr);
1453  reason = (fu16_t)va_arg(ap, unsigned int);
1454  destsn = va_arg(ap, char *);
1455  va_end(ap);
1456 
1457  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1458 
1459  return 1;
1460}
1461
1462static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1463{
1464  static char *missedreasons[] = {
1465    "Invalid (0)",
1466    "Message too large",
1467    "Rate exceeded",
1468    "Evil Sender",
1469    "Evil Receiver"
1470  };
1471  static int missedreasonslen = 5;
1472 
1473  va_list ap;
1474  fu16_t chan, nummissed, reason;
1475  aim_userinfo_t *userinfo;
1476 
1477  va_start(ap, fr);
1478  chan = (fu16_t)va_arg(ap, unsigned int);
1479  userinfo = va_arg(ap, aim_userinfo_t *);
1480  nummissed = (fu16_t)va_arg(ap, unsigned int);
1481  reason = (fu16_t)va_arg(ap, unsigned int);
1482  va_end(ap);
1483 
1484  /* printf("missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown"); */
1485 
1486  return 1;
1487}
1488
1489/*
1490 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1491 */
1492static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1493{
1494  va_list ap;
1495  fu16_t type;
1496  char *sn = NULL;
1497 
1498  va_start(ap, fr);
1499  type = (fu16_t)va_arg(ap, unsigned int);
1500  sn = va_arg(ap, char *);
1501  va_end(ap);
1502 
1503  /* printf("msgack: 0x%04x / %s\n", type, sn); */
1504 
1505  return 1;
1506}
1507
1508static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1509{
1510  static char *codes[5] = {
1511    "invalid",
1512    "change",
1513    "warning",
1514    "limit",
1515    "limit cleared"
1516  };
1517  va_list ap;
1518  fu16_t code, rateclass;
1519  fu32_t windowsize, clear, alert, limit, disconnect;
1520  fu32_t currentavg, maxavg;
1521 
1522  va_start(ap, fr); 
1523 
1524  /* See code explanations below */
1525  code = (fu16_t)va_arg(ap, unsigned int);
1526 
1527  /*
1528   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1529   */
1530  rateclass = (fu16_t)va_arg(ap, unsigned int);
1531 
1532  /*
1533   * Not sure what this is exactly.  I think its the temporal
1534   * relation factor (ie, how to make the rest of the numbers
1535   * make sense in the real world).
1536   */
1537  windowsize = va_arg(ap, fu32_t);
1538 
1539  /* Explained below */
1540  clear = va_arg(ap, fu32_t);
1541  alert = va_arg(ap, fu32_t);
1542  limit = va_arg(ap, fu32_t);
1543  disconnect = va_arg(ap, fu32_t);
1544  currentavg = va_arg(ap, fu32_t);
1545  maxavg = va_arg(ap, fu32_t);
1546 
1547  va_end(ap);
1548 
1549  /*
1550  printf("rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1551         (code < 5)?codes[code]:"invalid",
1552         rateclass,
1553         currentavg, maxavg,
1554         alert, clear,
1555         limit, disconnect,
1556         windowsize);
1557  */
1558  return 1;
1559}
1560
1561static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1562{
1563  va_list ap;
1564  fu16_t newevil;
1565  aim_userinfo_t *userinfo;
1566 
1567  va_start(ap, fr);
1568  newevil = (fu16_t)va_arg(ap, unsigned int);
1569  userinfo = va_arg(ap, aim_userinfo_t *);
1570  va_end(ap);
1571 
1572  /*
1573   * Evil Notifications that are lacking userinfo->sn are anon-warns
1574   * if they are an evil increases, but are not warnings at all if its
1575   * a decrease (its the natural backoff happening).
1576   *
1577   * newevil is passed as an int representing the new evil value times
1578   * ten.
1579   */
1580  /* printf("evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous"); */
1581 
1582  return 1;
1583}
1584
1585static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1586{
1587  va_list ap;
1588  char *address, *SNs;
1589  int i, num;
1590 
1591  va_start(ap, fr);
1592  address = va_arg(ap, char *);
1593  num = va_arg(ap, int);
1594  SNs = va_arg(ap, char *);
1595  va_end(ap);
1596 
1597  /* printf("E-Mail Search Results for %s: ", address);
1598 
1599  for(i = 0; i < num; i++)
1600    printf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1601  printf("\n");
1602  */
1603 
1604  return 1;
1605}
1606
1607static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1608{
1609  va_list ap;
1610  char *address;
1611 
1612  va_start(ap, fr);
1613  address = va_arg(ap, char *);
1614  va_end(ap);
1615 
1616  /* printf("E-Mail Search Results for %s: No Results or Invalid Email\n", address); */
1617 
1618  return 1;
1619}
1620
1621static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1622{
1623  va_list ap;
1624  char *msg, *url;
1625  fu16_t width, height, delay;
1626 
1627  va_start(ap, fr);
1628  msg = va_arg(ap, char *);
1629  url = va_arg(ap, char *);
1630  width = va_arg(ap, unsigned int);
1631  height = va_arg(ap, unsigned int);
1632  delay = va_arg(ap, unsigned int);
1633  va_end(ap);
1634 
1635  /* printf("popup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url); */
1636 
1637  return 1;
1638}
1639
1640static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1641{
1642  aim_sendpauseack(sess, fr->conn);
1643  return 1;
1644}
1645
1646static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1647{
1648  va_list ap;
1649  aim_conn_t *bosconn;
1650  char *bosip;
1651  fu8_t *cookie;
1652 
1653  va_start(ap, fr);
1654  bosip = va_arg(ap, char *);
1655  cookie = va_arg(ap, fu8_t *);
1656  va_end(ap);
1657 
1658  /* printf("migration in progress -- new BOS is %s -- disconnecting\n", bosip); */
1659  aim_conn_kill(sess, &fr->conn);
1660 
1661  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1662    /* printf("migrate: could not connect to BOS: internal error\n"); */
1663    return 1;
1664  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1665    /* printf("migrate: could not connect to BOS\n"); */
1666    aim_conn_kill(sess, &bosconn);
1667    return 1;
1668  }
1669 
1670  /* Login will happen all over again. */
1671  addcb_bos(sess, bosconn);
1672  aim_sendcookie(sess, bosconn, cookie);
1673  return 1;
1674}
1675
1676static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1677{
1678 
1679  /* printf("got SSI rights, requesting data\n"); */
1680  aim_ssi_reqdata(sess, fr->conn, 0, 0x0000);
1681 
1682  return 1;
1683}
1684
1685static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1686{
1687  va_list ap;
1688  fu8_t fmtver;
1689  fu16_t itemcount;
1690  fu32_t stamp;
1691  struct aim_ssi_item *list, *l;
1692 
1693  va_start(ap, fr);
1694  fmtver = va_arg(ap, unsigned int);
1695  itemcount = va_arg(ap, unsigned int);
1696  stamp = va_arg(ap, fu32_t);
1697  list = va_arg(ap, struct aim_ssi_item *);
1698  va_end(ap);
1699 
1700  /* printf("got SSI data: (0x%02x, %d items, %ld)\n", fmtver, itemcount, stamp); */
1701  for (l = list; l; l = l->next) {
1702    /* printf("\t0x%04x (%s) - 0x%04x/0x%04x\n", l->type, l->name, l->gid, l->bid); */
1703    /* printf("I would have printed data here!\n"); */
1704  }
1705 
1706  aim_ssi_enable(sess, fr->conn);
1707 
1708  return 1;
1709}
1710
1711static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1712{
1713  /* printf("server says we have the latest SSI data already\n"); */
1714  aim_ssi_enable(sess, fr->conn);
1715  return 1;
1716}
1717
1718static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1719{
1720  va_list ap;
1721  struct aim_icq_offlinemsg *msg;
1722 
1723  va_start(ap, fr);
1724  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1725  va_end(ap);
1726 
1727  if (msg->type == 0x0001) {
1728    /* printf("offline message from %ld at %d/%d/%d %02d:%02d : %s\n", msg->sender, msg->year, msg->month, msg->day, msg->hour, msg->minute, msg->msg); */
1729  } else {
1730    /* printf("unknown offline message type 0x%04x\n", msg->type); */
1731  }
1732  return 1;
1733}
1734
1735static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1736{
1737  /* Tell the server to delete them. */
1738  aim_icq_ackofflinemsgs(sess);
1739  return 1;
1740}
1741
1742
1743/******************** chat.c **************************/
1744
1745
1746static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1747{
1748  va_list ap;
1749  aim_userinfo_t *userinfo;
1750  int count, i;
1751 
1752  va_start(ap, fr);
1753  count = va_arg(ap, int);
1754  userinfo = va_arg(ap, aim_userinfo_t *);
1755  va_end(ap);
1756
1757  /*
1758  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1759  for (i = 0; i < count; i++)
1760    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1761  */
1762  return 1;
1763}
1764
1765static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1766{
1767  va_list ap;
1768  aim_userinfo_t *userinfo;
1769  int count , i;
1770 
1771  va_start(ap, fr);
1772  count = va_arg(ap, int);
1773  userinfo = va_arg(ap, aim_userinfo_t *);
1774  va_end(ap);
1775 
1776  /*
1777    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1778   
1779    for (i = 0; i < count; i++)
1780    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1781  */
1782  return 1;
1783}
1784
1785static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1786{
1787  va_list ap;
1788  aim_userinfo_t *userinfo;
1789  struct aim_chat_roominfo *roominfo;
1790  char *roomname;
1791  int usercount, i;
1792  char *roomdesc;
1793  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1794  fu32_t creationtime;
1795  const char *croomname;
1796 
1797  croomname = aim_chat_getname(fr->conn);
1798 
1799  va_start(ap, fr);
1800  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1801  roomname = va_arg(ap, char *);
1802  usercount = va_arg(ap, int);
1803  userinfo = va_arg(ap, aim_userinfo_t *);
1804  roomdesc = va_arg(ap, char *);
1805  flags = (fu16_t)va_arg(ap, unsigned int);
1806  creationtime = va_arg(ap, fu32_t);
1807  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1808  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1809  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1810  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1811  va_end(ap);
1812
1813  /*
1814  printf("chat: %s:  info update:\n", croomname);
1815  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1816  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1817  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1818  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1819
1820  for (i = 0; i < usercount; i++)
1821    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1822 
1823  printf("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1824         croomname, flags,
1825         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1826         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1827         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1828         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1829  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1830  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1831  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1832  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1833  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1834  */
1835 
1836  return 1;
1837}
1838
1839static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1840{
1841  va_list ap;
1842  aim_userinfo_t *userinfo;
1843  char *msg;
1844  char tmpbuf[1152];
1845 
1846  va_start(ap, fr);
1847  userinfo = va_arg(ap, aim_userinfo_t *);     
1848  msg = va_arg(ap, char *);
1849  va_end(ap);
1850
1851  /*
1852  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1853  */
1854 
1855  /*
1856   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1857   */
1858  if (strcmp(userinfo->sn, sess->sn) != 0) {
1859    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1860    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1861  }
1862 
1863  return 1;
1864}
1865
1866static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
1867{
1868  fu16_t type;
1869  va_list ap;
1870 
1871  va_start(ap, fr);
1872  type = (fu16_t)va_arg(ap, unsigned int);
1873 
1874  if (type == 0x0002) {
1875    int maxrooms;
1876    struct aim_chat_exchangeinfo *exchanges;
1877    int exchangecount, i;
1878   
1879    maxrooms = va_arg(ap, int);
1880    exchangecount = va_arg(ap, int);
1881    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1882    va_end(ap);
1883
1884    /*
1885    printf("chat info: Chat Rights:\n");
1886    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1887    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
1888    for (i = 0; i < exchangecount; i++) {
1889      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
1890             exchanges[i].number,
1891             exchanges[i].name,
1892             exchanges[i].charset1,
1893             exchanges[i].lang1,
1894             exchanges[i].flags,
1895             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1896             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1897             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1898             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1899    }
1900    */
1901  } else if (type == 0x0008) {
1902    char *fqcn, *name, *ck;
1903    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1904    fu8_t createperms;
1905    fu32_t createtime;
1906   
1907    fqcn = va_arg(ap, char *);
1908    instance = (fu16_t)va_arg(ap, unsigned int);
1909    exchange = (fu16_t)va_arg(ap, unsigned int);
1910    flags = (fu16_t)va_arg(ap, unsigned int);
1911    createtime = va_arg(ap, fu32_t);
1912    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1913    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
1914    createperms = (fu8_t)va_arg(ap, unsigned int);
1915    unknown = (fu16_t)va_arg(ap, unsigned int);
1916    name = va_arg(ap, char *);
1917    ck = va_arg(ap, char *);
1918    va_end(ap);
1919   
1920    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
1921   
1922  } else {
1923    va_end(ap);
1924    /* printf("chatnav info: unknown type (%04x)\n", type); */
1925  }
1926 
1927  return 1;
1928}
1929
1930static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1931{
1932
1933  aim_clientready(sess, fr->conn);
1934 
1935  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
1936    /* printf("chatnav ready\n"); */
1937    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
1938    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
1939    aim_chatnav_reqrights(sess, fr->conn);
1940  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
1941    /* printf("chat ready\n"); */
1942    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1943    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1944    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1945    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1946    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1947  }
1948  return 1;
1949}
1950
1951void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1952{
1953  aim_conn_t *tstconn;
1954 
1955  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1956  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1957    /* printf("unable to connect to chat(nav) server\n"); */
1958    if (tstconn)
1959      aim_conn_kill(sess, &tstconn);
1960    return;
1961  }
1962 
1963  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1964  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1965  aim_sendcookie(sess, tstconn, redir->cookie);
1966  /* printf("chatnav: connected\n"); */
1967  return;
1968}
1969
1970/* XXX this needs instance too */
1971void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1972{
1973  aim_conn_t *tstconn;
1974 
1975  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
1976  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1977    /* printf("unable to connect to chat server\n"); */
1978    if (tstconn) aim_conn_kill(sess, &tstconn);
1979    return; 
1980  }             
1981  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
1982 
1983  /*
1984   * We must do this to attach the stored name to the connection!
1985   */
1986  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
1987  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1988  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1989  aim_sendcookie(sess, tstconn, redir->cookie);
1990  return;       
1991}
1992
1993
1994
1995
1996/******************************************* ft.c ******************************************/
1997
1998
1999static int directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...)
2000{
2001  va_list ap;
2002  char *sn, *msg;
2003 
2004  va_start(ap, fr);
2005  sn = va_arg(ap, char *);
2006  msg = va_arg(ap, char *);
2007  va_end(ap);
2008 
2009  /* printf("Directim from %s: %s\n", sn, msg); */
2010  if (strstr(msg, "sendmsg")) {
2011    int i;
2012   
2013    i = atoi(strstr(msg, "sendmsg")+8);
2014    if (i < 10000) {
2015      char *newbuf;
2016      int z;
2017     
2018      newbuf = malloc(i+1);
2019      for (z = 0; z < i; z++)
2020        newbuf[z] = (z % 10)+0x30;
2021      newbuf[i] = '\0';
2022      aim_send_im_direct(sess, fr->conn, newbuf);
2023      free(newbuf);
2024    }
2025  } else if (strstr(msg, "goodday")) {
2026    aim_send_im_direct(sess, fr->conn, "Good day to you, too");
2027  } else {
2028    char newmsg[1024];
2029    snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
2030    aim_send_im_direct(sess, fr->conn, newmsg);
2031  }
2032
2033  return 1;
2034}
2035
2036static int directim_typing(aim_session_t *sess, aim_frame_t *fr, ...)
2037{
2038  va_list ap;
2039  char *sn;
2040 
2041  va_start(ap, fr);
2042  sn = va_arg(ap, char *);
2043  va_end(ap);
2044  /* printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); */
2045  return 1;
2046}
2047
2048static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2049{
2050  va_list ap;
2051  aim_conn_t *newconn, *listenerconn;
2052 
2053  va_start(ap, fr);
2054  newconn = va_arg(ap, aim_conn_t *);
2055  listenerconn = va_arg(ap, aim_conn_t *);
2056  va_end(ap);
2057 
2058  aim_conn_close(listenerconn);
2059  aim_conn_kill(sess, &listenerconn);
2060 
2061  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2062  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2063 
2064  aim_send_im_direct(sess, newconn, "goodday");
2065 
2066  /* printf("OFT: DirectIM: connected to %s\n", aim_directim_getsn(newconn)); */
2067 
2068  return 1;
2069}
2070
2071static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...)
2072{
2073  va_list ap;
2074  aim_conn_t *oftconn;
2075  struct aim_fileheader_t *fh;
2076  fu8_t *cookie;
2077 
2078  va_start(ap, fr);
2079  oftconn = va_arg(ap, aim_conn_t *);
2080  fh = va_arg(ap, struct aim_fileheader_t *);
2081  cookie = va_arg(ap, fu8_t *);
2082  va_end(ap);
2083 
2084  /* printf("request for file %s.\n", fh->name); */
2085 
2086  return 1;
2087}
2088
2089static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...)
2090{
2091  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2092  va_list ap;
2093  aim_conn_t *oftconn;
2094  struct aim_fileheader_t *fh;
2095  char *path;
2096  fu8_t *cookie;
2097  int pos, bufpos = 0, bufsize = 2048, i;
2098  char *buf;
2099  FILE *file;
2100 
2101  va_start(ap, fr);
2102  oftconn = va_arg(ap, aim_conn_t *);
2103  fh = va_arg(ap, struct aim_fileheader_t *);
2104  cookie = va_arg(ap, fu8_t *);
2105  va_end(ap);
2106 
2107  /* printf("sending file %s(%ld).\n", fh->name, fh->size); */
2108
2109  if (!(buf = malloc(2048)))
2110    return -1;
2111 
2112  if (!(path = (char *)calloc(1, strlen(priv->listingpath) +strlen(fh->name)+2))) {
2113    /* perror("calloc"); */
2114    /* printf("error in calloc of path\n"); */
2115   
2116    return 0; /* XXX: no idea what winaim expects here =) */
2117  }
2118
2119  snprintf(path, strlen(priv->listingpath)+strlen(fh->name)+2, "%s/%s", priv->listingpath, fh->name);
2120 
2121  if (!(file = fopen(path, "r"))) {
2122    /* printf("getfile_send fopen failed for %s. damn.\n", path); */
2123    return 0;
2124  }
2125 
2126  /*
2127   * This is a mess. Remember that faimtest is demonstration code
2128   * only and for the sake of the gods, don't use this code in any
2129   * of your clients. --mid
2130   */
2131  for(pos = 0; pos < fh->size; pos++) {
2132   
2133    bufpos = pos % bufsize;
2134   
2135    if (bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2136      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2137        /* perror("faim: getfile_send: write1"); */
2138        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2139        free(buf);   
2140        return 0;
2141      }
2142    }
2143   
2144    if( (buf[bufpos] = fgetc(file)) == EOF) {
2145      if(pos != fh->size) {
2146        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2147        free(buf);   
2148        return 0;
2149      }
2150    }     
2151    /* printf("%c(0x%02x) ", buf[pos], buf[pos]); */
2152  }
2153 
2154  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2155    /* perror("faim: getfile_send: write2"); */
2156    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2157    free(buf);   
2158    return 0;
2159  }
2160 
2161  free(buf);
2162  free(fh);
2163 
2164  return 1;
2165}
2166
2167static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...) 
2168{
2169  va_list ap;
2170  aim_conn_t *conn;
2171  struct aim_fileheader_t *fh;
2172 
2173  va_start(ap, fr);
2174  conn = va_arg(ap, aim_conn_t *);
2175  fh = va_arg(ap, struct aim_fileheader_t *);
2176  va_end(ap);
2177 
2178  /* printf("completed file transfer for %s.\n", fh->name); */
2179 
2180  aim_conn_close(conn);
2181  aim_conn_kill(sess, &conn);
2182 
2183  return 1;
2184}
2185
2186static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...)
2187{
2188  va_list ap;
2189  aim_conn_t *conn;
2190  char *sn;
2191 
2192  va_start(ap, fr);
2193  conn = va_arg(ap, aim_conn_t *);
2194  sn = va_arg(ap, char *);
2195  va_end(ap);
2196 
2197  aim_conn_kill(sess, &conn);
2198 
2199  /* printf("getfile: disconnected from %s\n", sn); */
2200 
2201  return 1;
2202}
2203
2204static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...)
2205{
2206  va_list ap;
2207  aim_conn_t *conn;
2208  char *listing;
2209  struct aim_filetransfer_priv *ft;
2210  char *filename, *nameend, *sizec;
2211  int filesize, namelen;
2212 
2213  va_start(ap, fr);
2214  conn = va_arg(ap, aim_conn_t *);
2215  ft = va_arg(ap, struct aim_filetransfer_priv *);
2216  listing = va_arg(ap, char *);
2217  va_end(ap);
2218 
2219  /* printf("listing on %d==================\n%s\n===========\n", conn->fd, listing); */
2220 
2221  nameend = strstr(listing+0x1a, "\r");
2222  namelen = nameend - (listing + 0x1a);
2223 
2224  filename = malloc(namelen + 1);
2225  strncpy(filename, listing+0x1a, namelen);
2226  filename[namelen] = 0x00;
2227 
2228  sizec = malloc(8+1);
2229  memcpy(sizec, listing + 0x11, 8);
2230  sizec[8] = 0x00;
2231 
2232  filesize =  strtol(sizec, (char **)NULL, 10);
2233 
2234  /* printf("requesting %d %s(%d long)\n", namelen, filename, filesize); */
2235 
2236  aim_oft_getfile_request(sess, conn, filename, filesize);
2237 
2238  free(filename);
2239  free(sizec);
2240 
2241  return 0;
2242}
2243
2244static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...)
2245{
2246  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2247  va_list ap;
2248  aim_conn_t *oftconn;
2249  struct aim_fileheader_t *fh;
2250  int pos, bufpos = 0, bufsize = 2048, i;
2251  char *buf;
2252 
2253  va_start(ap, fr);
2254  oftconn = va_arg(ap, aim_conn_t *);
2255  fh = va_arg(ap, struct aim_fileheader_t *);
2256  va_end(ap);
2257 
2258  /* printf("sending listing of size %ld\n", fh->size); */
2259
2260  if(!(buf = malloc(2048))) return -1;
2261 
2262  for(pos = 0; pos < fh->size; pos++) {
2263    bufpos = pos % bufsize;
2264    if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2265      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2266        /* perror("faim: getfile_send: write1"); */
2267        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2268        free(buf);   
2269        return 0;
2270      }
2271    }
2272    if( (buf[bufpos] = fgetc(priv->listingfile)) == EOF) {
2273      if(pos != fh->size) {
2274        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2275        free(buf);   
2276        return 0;
2277      }
2278    }     
2279  }
2280 
2281  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2282    /* perror("faim: getfile_send: write2"); */
2283    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2284    free(buf);   
2285    return 0;
2286  }
2287 
2288  /* printf("sent listing\n"); */
2289  free(buf);
2290 
2291  return 0;
2292}
2293
2294static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...)
2295{
2296  va_list ap;
2297  aim_conn_t *conn;
2298  struct aim_filetransfer_priv *ft;
2299  unsigned char data;
2300  int pos;
2301 
2302  va_start(ap, fr);
2303  conn = va_arg(ap, aim_conn_t *);
2304  ft = va_arg(ap, struct aim_filetransfer_priv *);
2305  va_end(ap);
2306
2307  /* printf("receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name); */
2308
2309  for(pos = 0; pos < ft->fh.size; pos++) {
2310    read(conn->fd, &data, 1);
2311    /* printf("%c(%02x) ", data, data); */
2312  }
2313
2314  /* printf("\n"); */
2315
2316  aim_oft_getfile_end(sess, conn);
2317  return 0;
2318}
2319
2320static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...)
2321{
2322  va_list ap;
2323  aim_conn_t *conn;
2324 
2325  va_start(ap, fr);
2326  conn = va_arg(ap, aim_conn_t *);
2327  va_end(ap);
2328 
2329  aim_conn_close(conn);
2330  aim_conn_kill(sess, &conn);
2331 
2332  return 0;
2333}
2334
2335static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2336{
2337  va_list ap;
2338  aim_conn_t *conn, *listenerconn;
2339  struct aim_filetransfer_priv *priv;
2340 
2341  va_start(ap, fr);
2342  conn = va_arg(ap, aim_conn_t *);
2343  listenerconn = va_arg(ap, aim_conn_t *);
2344  va_end(ap);
2345 
2346  aim_conn_close(listenerconn);
2347  aim_conn_kill(sess, &listenerconn);
2348 
2349  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2350  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2351  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2352  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2353  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2354  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2355  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2356  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
2357 
2358  priv = (struct aim_filetransfer_priv *)conn->priv;
2359 
2360  /* printf("getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd); */
2361 
2362  return 1;
2363}
2364
2365void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn)
2366{
2367  aim_conn_t *newconn;
2368 
2369  newconn = aim_getfile_initiate(sess, conn, sn);
2370  /* printf("getting file listing from %s\n", sn); */
2371  aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
2372 
2373  return;
2374}
2375
2376void getfile_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2377{
2378  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2379  aim_conn_t *newconn;
2380  struct aim_fileheader_t *fh;
2381 
2382  printf("get file request from %s (at %s/%s/%s) %x\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip, args->reqclass);
2383  fh = aim_getlisting(sess, priv->listingfile);
2384  newconn = aim_accepttransfer(sess, conn, userinfo->sn, args->cookie, args->clientip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass);
2385  free(fh);
2386
2387  if ( (!newconn) || (newconn->fd == -1) ) {
2388    printf("getfile: requestconn: apparent error in accepttransfer\n");
2389    if (newconn) aim_conn_kill(sess, &newconn);
2390    return;
2391  }
2392 
2393  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2394  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2395  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2396  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2397  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2398 
2399  /* printf("getfile connect succeeded, handlers added.\n"); */
2400 
2401  return;
2402}
2403
2404void directim_start(aim_session_t *sess, const char *sn)
2405{
2406  aim_conn_t *newconn;
2407 
2408  /* printf("opening directim to %s\n", sn); */
2409  newconn = aim_directim_initiate(sess, sn);
2410  if (!newconn || (newconn->fd == -1)) {
2411    /* printf("connection failed!\n"); */
2412    if (newconn) aim_conn_kill(sess, &newconn);
2413  } else {
2414    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate, 0);
2415  }
2416  return;
2417}
2418
2419void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2420{
2421  aim_conn_t *newconn;
2422 
2423  /* printf("OFT: DirectIM: request from %s (%s/%s/%s)\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip); */
2424 
2425  newconn = aim_directim_connect(sess, userinfo->sn, args->clientip, args->cookie);
2426  if (!newconn || (newconn->fd == -1)) {
2427    /* printf("icbm: imimage: could not connect\n"); */
2428    if (newconn) aim_conn_kill(sess, &newconn);
2429  } else {
2430    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2431    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2432    /* printf("OFT: DirectIM: connected to %s\n", userinfo->sn); */
2433    aim_send_im_direct(sess, newconn, "goodday");
2434  }
2435}
Note: See TracBrowser for help on using the repository browser.