source: aim.c @ c045455

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