source: aim.c @ 651560f

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