source: aim.c @ a352335c

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