source: aim.c @ 26255f0

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 26255f0 was 1fdca1b, checked in by Nelson Elhage <nelhage@mit.edu>, 12 years ago
AIM: Decode incoming messages properly. We can handle unicode now, so there's no need to HTML-encode high-bit characters. Encode them into utf-8 so they show up properly.
  • Property mode set to 100644
File size: 64.5 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  int connected;
14};
15
16static const char *msgerrreasons[] = {
17        "Invalid error",
18        "Invalid SNAC",
19        "Rate to host",
20        "Rate to client",
21        "Not logged on",
22        "Service unavailable",
23        "Service not defined",
24        "Obsolete SNAC",
25        "Not supported by host",
26        "Not supported by client",
27        "Refused by client",
28        "Reply too big",
29        "Responses lost",
30        "Request denied",
31        "Busted SNAC payload",
32        "Insufficient rights",
33        "In local permit/deny",
34        "Too evil (sender)",
35        "Too evil (receiver)",
36        "User temporarily unavailable",
37        "No match",
38        "List overflow",
39        "Request ambiguous",
40        "Queue full",
41        "Not while on AOL",
42};
43static int msgerrreasonslen = 25;
44
45static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
46static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
47static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
48int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
49int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
50void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
51static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
52static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
53static int conninitdone_chat     (aim_session_t *, aim_frame_t *, ...);
54int logout(aim_session_t *sess);
55
56static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...);
57static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...);
58static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...);
60static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...);
61static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...);
62static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...);
63static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...);
64static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...);
65/* static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); */
66static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...);
67static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname);
68static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...);
69/* static void printuserflags(fu16_t flags); */
70static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...);
71static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args);
72static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
73static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...);
74static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...);
75static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...);
76int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...);
77static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...);
78static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...);
79static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...);
80static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...);
81static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...);
82static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...);
83static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...);
84static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...);
85static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...);
86static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...);
87static int migrate(aim_session_t *sess, aim_frame_t *fr, ...);
88static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...);
89static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...);
90static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...);
91static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...);
92static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...);
93/*
94static int faimtest_ssi_parseerr     (aim_session_t *, aim_frame_t *, ...);
95static int faimtest_ssi_parserights  (aim_session_t *, aim_frame_t *, ...);
96static int faimtest_ssi_parselist    (aim_session_t *, aim_frame_t *, ...);
97static int faimtest_ssi_parseack     (aim_session_t *, aim_frame_t *, ...);
98static int faimtest_ssi_authgiven    (aim_session_t *, aim_frame_t *, ...);
99static int faimtest_ssi_authrequest  (aim_session_t *, aim_frame_t *, ...);
100static int faimtest_ssi_authreply    (aim_session_t *, aim_frame_t *, ...);
101static int faimtest_ssi_gotadded     (aim_session_t *, aim_frame_t *, ...);
102*/
103
104void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
105void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
106
107/*****************************************************************/
108
109void owl_aim_init(void)
110{
111  /* this has all been moved to owl_aim_login, but we'll leave the
112   * function here, in case there's stuff we want to init in the
113   * future.  It's still called by Owl.
114   */
115     
116}
117
118void owl_aim_send_nop(owl_timer *t, void *data) {
119    if(owl_global_is_doaimevents(&g)) {
120        aim_session_t *sess = owl_global_get_aimsess(&g);
121        aim_flap_nop(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS));
122    }
123}
124
125
126int owl_aim_login(const char *screenname, const char *password)
127{
128  struct owlfaim_priv *priv;
129  aim_conn_t *conn;
130  aim_session_t *sess;
131
132  sess=owl_global_get_aimsess(&g);
133
134  aim_session_init(sess, TRUE, 0);
135  aim_setdebuggingcb(sess, faimtest_debugcb);
136  aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
137 
138  /* this will leak, I know and just don't care right now */
139  priv=owl_malloc(sizeof(struct owlfaim_priv));
140  memset(priv, 0, sizeof(struct owlfaim_priv));
141
142  priv->screenname = owl_strdup(screenname);
143  priv->password = owl_strdup(password);
144  priv->server = owl_strdup(FAIM_LOGIN_SERVER);
145  sess->aux_data = priv;
146
147  conn=aim_newconn(sess, AIM_CONN_TYPE_AUTH, priv->server ? priv->server : FAIM_LOGIN_SERVER);
148  /*  conn=aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL); */
149  if (!conn) {
150    owl_function_error("owl_aim_login: connection error during AIM login\n");
151    owl_global_set_aimnologgedin(&g);
152    owl_global_set_no_doaimevents(&g);
153    return (-1);
154  }
155
156  /*
157  else if (conn->fd == -1) {
158    if (conn->status & AIM_CONN_STATUS_RESOLVERR) {
159      owl_function_error("owl_aim_login: could not resolve authorize name");
160    } else if (conn->status & AIM_CONN_STATUS_CONNERR) {
161      owl_function_error("owl_aim_login: could not connect to authorizer");
162    } else {
163      owl_function_error("owl_aim_login: unknown connection error");
164    }
165    owl_global_set_aimnologgedin(&g);
166    owl_global_set_no_doaimevents(&g);
167    aim_conn_kill(sess, &conn);
168    return(-1);
169  }
170  */
171
172   
173  aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
174  aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
175
176  aim_conn_addhandler(sess, conn, AIM_CB_FAM_ATH, AIM_CB_ATH_AUTHRESPONSE, faimtest_parse_login, 0);
177  aim_conn_addhandler(sess, conn, AIM_CB_FAM_ATH, AIM_CB_ATH_LOGINRESPONSE, faimtest_parse_authresp, 0);
178  /* aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0); */
179  /* aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0); */
180  /* aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); */
181   
182  /* start processing AIM events */
183  owl_global_set_doaimevents(&g);
184  /* conn->status |= AIM_CONN_STATUS_INPROGRESS; */
185  owl_function_debugmsg("owl_aim_login: sending login request for %s", screenname);
186  aim_request_login(sess, conn, screenname);
187  owl_function_debugmsg("owl_aim_login: connecting");
188
189  g.aim_nop_timer = owl_select_add_timer(30, 30, owl_aim_send_nop, NULL, NULL);
190
191  return(0);
192}
193
194void owl_aim_unset_ignorelogin(owl_timer *t, void *data) {      /* noproto */
195    owl_global_unset_ignore_aimlogin(&g);
196}
197
198/* stuff to run once login has been successful */
199void owl_aim_successful_login(const char *screenname)
200{
201  char *buff;
202  owl_function_debugmsg("doing owl_aim_successful_login");
203  owl_global_set_aimloggedin(&g, screenname);
204  owl_global_set_doaimevents(&g); /* this should already be on */
205  owl_function_makemsg("%s logged in", screenname);
206  buff=owl_sprintf("Logged in to AIM as %s", screenname);
207  owl_function_adminmsg("", buff);
208  owl_free(buff);
209
210  owl_function_debugmsg("Successful AIM login for %s", screenname);
211
212  /* start the ingorelogin timer */
213  owl_global_set_ignore_aimlogin(&g);
214  owl_select_add_timer(owl_global_get_aim_ignorelogin_timer(&g),
215                       0, owl_aim_unset_ignorelogin, NULL, NULL);
216
217  /* aim_ssi_setpresence(owl_global_get_aimsess(&g), 0x00000400); */
218  /* aim_bos_setidle(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), 5000); */
219}
220
221void owl_aim_logout(void)
222{
223  /* need to check if it's connected first, I think */
224  logout(owl_global_get_aimsess(&g));
225
226  if (owl_global_is_aimloggedin(&g)) owl_function_adminmsg("", "Logged out of AIM");
227  owl_global_set_aimnologgedin(&g);
228  owl_global_set_no_doaimevents(&g);
229  owl_select_remove_timer(g.aim_nop_timer);
230}
231
232void owl_aim_logged_out(void)
233{
234  if (owl_global_is_aimloggedin(&g)) owl_function_adminmsg("", "Logged out of AIM");
235  owl_aim_logout();
236}
237
238void owl_aim_login_error(const char *message)
239{
240  if (message) {
241    owl_function_error("%s", message);
242  } else {
243    owl_function_error("Authentication error on login");
244  }
245  owl_function_beep();
246  owl_global_set_aimnologgedin(&g);
247  owl_global_set_no_doaimevents(&g);
248  owl_select_remove_timer(g.aim_nop_timer);
249}
250
251/*
252 * I got these constants by skimming libfaim/im.c
253 *
254 * "UNICODE" actually means "UCS-2BE".
255 */
256#define AIM_CHARSET_ISO_8859_1         0x0003
257#define AIM_CHARSET_UNICODE            0x0002
258
259int owl_aim_do_send(const char *to, const char *msg, int flags) /* noproto */
260{
261  int ret;
262  char *encoded;
263  struct aim_sendimext_args args;
264    gsize len;
265
266  encoded = g_convert(msg, -1, "ISO-8859-1", "UTF-8", NULL, &len, NULL);
267  if (encoded) {
268    owl_function_debugmsg("Encoded outgoing AIM as ISO-8859-1");
269    args.charset = AIM_CHARSET_ISO_8859_1;
270    args.charsubset = 0;
271    args.flags = AIM_IMFLAGS_ISO_8859_1;
272  } else {
273    owl_function_debugmsg("Encoding outgoing IM as UCS-2BE");
274    encoded = g_convert(msg, -1, "UCS-2BE", "UTF-8", NULL, &len, NULL);
275    if (!encoded) {
276      /*
277       * TODO: Strip or HTML-encode characters, or figure out how to
278       * send in a differen charset.
279       */
280      owl_function_error("Unable to encode outgoing AIM message in UCS-2");
281      return 1;
282    }
283
284    args.charset = AIM_CHARSET_UNICODE;
285    args.charsubset = 0;
286    args.flags = AIM_IMFLAGS_UNICODE;
287  }
288
289  args.destsn = to;
290  args.msg = encoded;
291  args.msglen = len;
292  args.flags |= flags;
293
294  ret=aim_im_sendch1_ext(owl_global_get_aimsess(&g), &args);
295
296  owl_free(encoded);
297
298  return(ret);
299}
300
301int owl_aim_send_im(const char *to, const char *msg)
302{
303  return owl_aim_do_send(to, msg, 0);
304}
305
306int owl_aim_send_awaymsg(const char *to, const char *msg)
307{
308  return owl_aim_do_send(to, msg, AIM_IMFLAGS_AWAY);
309}
310
311void owl_aim_addbuddy(const char *name)
312{
313
314  aim_ssi_addbuddy(owl_global_get_aimsess(&g), name, "Buddies", NULL, NULL, NULL, 0);
315
316  /*
317  aim_ssi_addbuddy(owl_global_get_aimsess(&g),
318                   name,
319                   "Buddies",
320                   NULL, NULL, NULL,
321                   aim_ssi_waitingforauth(owl_global_get_aimsess(&g)->ssi.local, "Buddies", name));
322  */
323}
324
325void owl_aim_delbuddy(const char *name)
326{
327  aim_ssi_delbuddy(owl_global_get_aimsess(&g), name, "Buddies");
328  owl_buddylist_offgoing(owl_global_get_buddylist(&g), name);
329}
330
331void owl_aim_search(const char *email)
332{
333  int ret;
334
335  owl_function_debugmsg("owl_aim_search: doing search for %s", email);
336  ret=aim_search_address(owl_global_get_aimsess(&g), 
337                         aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_BOS),
338                         email);
339
340  if (ret) owl_function_error("owl_aim_search: aim_search_address returned %i", ret);
341}
342
343
344int owl_aim_set_awaymsg(const char *msg)
345{
346  int len;
347  char *foo;
348  /* there is a max away message lentgh we should check against */
349
350  foo=owl_strdup(msg);
351  len=strlen(foo);
352  if (len>500) {
353    foo[500]='\0';
354    len=499;
355  }
356   
357  aim_locate_setprofile(owl_global_get_aimsess(&g),
358                        NULL, NULL, 0,
359                        "us-ascii", foo, len);
360  owl_free(foo);
361
362  /*
363  aim_bos_setprofile(owl_global_get_aimsess(&g),
364                     owl_global_get_bosconn(&g),
365                     NULL, NULL, 0, "us-ascii", msg,
366                     strlen(msg), 0);
367  */
368  return(0);
369}
370
371void owl_aim_chat_join(const char *name, int exchange)
372{
373  int ret;
374  aim_conn_t *cur;
375  /*
376  OscarData *od = g->proto_data;
377  const char *name, *exchange;
378  */
379
380  owl_function_debugmsg("Attempting to join chatroom %s exchange %i", name, exchange);
381
382  /*
383  name = g_hash_table_lookup(data, "room");
384  exchange = g_hash_table_lookup(data, "exchange");
385  */
386  if ((cur = aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV))) {
387    owl_function_debugmsg("owl_aim_chat_join: chatnav exists, creating room");
388    aim_chatnav_createroom(owl_global_get_aimsess(&g), cur, name, exchange);
389  } else {
390    /*    struct create_room *cr = g_new0(struct create_room, 1); */
391    owl_function_debugmsg("owl_aim_chat_join: chatnav does not exist, opening chatnav");
392    /*
393    cr->exchange = atoi(exchange);
394    cr->name = g_strdup(name);
395    od->create_rooms = g_slist_append(od->create_rooms, cr);
396    */
397    aim_reqservice(owl_global_get_aimsess(&g),
398                   aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV),
399                   AIM_CONN_TYPE_CHATNAV);
400    aim_reqservice(owl_global_get_aimsess(&g), NULL, AIM_CONN_TYPE_CHATNAV);
401    aim_chatnav_createroom(owl_global_get_aimsess(&g), cur, name, exchange);
402    ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, name, 0x0000);
403
404  }
405  return;
406  /******/
407
408
409  /* ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, chatroom, 0x0000); */
410  /*
411  ret=aim_chat_join(owl_global_get_aimsess(&g),
412                    aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), exchange, chatroom, 0x0000);
413  */
414
415  aim_reqservice(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), AIM_CONN_TYPE_CHATNAV);
416  ret = aim_chatnav_createroom(owl_global_get_aimsess(&g),
417                               aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), name, exchange);
418   ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, name, 0x0000);
419 
420}
421
422void owl_aim_chat_leave(const char *chatroom)
423{
424}
425
426int owl_aim_chat_sendmsg(const char *chatroom, const char *msg)
427{
428  return(0);
429}
430
431/* caller must free the return */
432char *owl_aim_normalize_screenname(const char *in)
433{
434  char *out;
435  int i, j, k;
436
437  j=strlen(in);
438  out=owl_malloc(j+30);
439  k=0;
440  for (i=0; i<j; i++) {
441    if (in[i]!=' ') {
442      out[k]=in[i];
443      k++;
444    }
445  }
446  out[k]='\0';
447  return(out);
448}
449
450int owl_aim_process_events(void)
451{
452  aim_session_t *aimsess;
453  aim_conn_t *waitingconn = NULL;
454  struct timeval tv;
455  int selstat = 0;
456  struct owlfaim_priv *priv;
457
458  aimsess=owl_global_get_aimsess(&g);
459  priv = aimsess->aux_data;
460
461  /* do a select without blocking */
462  tv.tv_sec = 0;
463  tv.tv_usec = 0;
464  waitingconn = aim_select(aimsess, &tv, &selstat);
465
466  if (selstat == -1) {
467    owl_aim_logged_out();
468  } else if (selstat == 0) { 
469    /* no events pending */
470  } else if (selstat == 1) { /* outgoing data pending */
471    aim_tx_flushqueue(aimsess);
472  } else if (selstat == 2) { /* incoming data pending */
473    /* printf("selstat == 2\n"); */
474   
475    if (aim_get_command(aimsess, waitingconn) >= 0) {
476      aim_rxdispatch(aimsess);
477    } else {
478      /* printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype); */
479      /* we should have callbacks for all these, else the library will do the conn_kill for us. */
480      if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
481        if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
482          /* printf("disconnected from %s\n", aim_directim_getsn(waitingconn)); */
483          aim_conn_kill(aimsess, &waitingconn);
484          owl_aim_logged_out();
485        }
486      } else {
487        aim_conn_kill(aimsess, &waitingconn);
488        owl_aim_logged_out();
489      }
490      if (!aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS)) {
491        /* printf("major connection error\n"); */
492        owl_aim_logged_out();
493        /* break; */
494      }
495    }
496  }
497  /* exit(0); */
498  return(0);
499}
500
501static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
502{
503  return;
504}
505
506static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
507{
508  struct owlfaim_priv *priv = sess->aux_data;
509  struct client_info_s info = CLIENTINFO_AIM_KNOWNGOOD;
510   
511  const char *key;
512  va_list ap;
513
514  va_start(ap, fr);
515  key = va_arg(ap, const char *);
516  va_end(ap);
517
518  owl_function_debugmsg("faimtest_parse_login: %s %s %s", priv->screenname, priv->password, key);
519
520  aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key);
521 
522  return(1);
523}
524
525
526static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...)
527{
528  va_list ap;
529  struct aim_authresp_info *info;
530  aim_conn_t *bosconn;
531
532  va_start(ap, fr);
533  info = va_arg(ap, struct aim_authresp_info *);
534  va_end(ap);
535
536  /* printf("Screen name: %s\n", info->sn); */
537  owl_function_debugmsg("doing faimtest_parse_authresp");
538  owl_function_debugmsg("faimtest_parse_authresp: %s", info->sn);
539
540  /*
541   * Check for error.
542   */
543  if (info->errorcode || !info->bosip || !info->cookie) {
544    /*
545    printf("Login Error Code 0x%04x\n", info->errorcode);
546    printf("Error URL: %s\n", info->errorurl);
547    */
548    if (info->errorcode==0x05) {
549      owl_aim_login_error("Incorrect nickname or password.");
550    } else if (info->errorcode==0x11) {
551      owl_aim_login_error("Your account is currently suspended.");
552    } else if (info->errorcode==0x14) {
553      owl_aim_login_error("The AOL Instant Messenger service is temporarily unavailable.");
554    } else if (info->errorcode==0x18) {
555      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.");
556    } else if (info->errorcode==0x1c) {
557      owl_aim_login_error("The client version you are using is too old.");
558    } else {
559      owl_aim_login_error(NULL);
560    }
561    aim_conn_kill(sess, &fr->conn);
562    return(1);
563  }
564
565  /*
566  printf("Reg status: %d\n", info->regstatus);
567  printf("Email: %s\n", info->email);
568  printf("BOS IP: %s\n", info->bosip);
569  */
570
571  /* printf("Closing auth connection...\n"); */
572  aim_conn_kill(sess, &fr->conn);
573  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, info->bosip))) {
574    /* printf("could not connect to BOS: internal error\n"); */
575    return(1);
576  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
577    /* printf("could not connect to BOS\n"); */
578    aim_conn_kill(sess, &bosconn);
579    return(1);
580  }
581  owl_global_set_bossconn(&g, bosconn);
582  owl_aim_successful_login(info->sn);
583  addcb_bos(sess, bosconn);
584  aim_sendcookie(sess, bosconn, info->cookielen, info->cookie);
585  return(1);
586}
587
588int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
589{
590  owl_function_debugmsg("doing faimtest_flapversion");
591
592#if 0
593  /* XXX fix libfaim to support this */
594  printf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
595
596  /*
597   * This is an alternate location for starting the login process.
598   */
599  /* XXX should do more checking to make sure its really the right AUTH conn */
600  if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
601    /* do NOT send a flapversion, request_login will send it if needed */
602    aim_request_login(sess, fr->conn, priv->screenname);
603    /* printf("faimtest: login request sent\n"); */
604  }
605#endif
606
607  return 1;
608}
609
610
611int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
612{
613  owl_function_debugmsg("doing faimtest_conncomplete");
614  /* owl_aim_successful_login(info->sn); */
615  return 1;
616}
617
618void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
619{
620  owl_function_debugmsg("doing addcb_bos");
621  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
622  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
623
624  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0003,                        ssirights, 0);
625  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0006,                        ssidata, 0);
626  aim_conn_addhandler(sess, bosconn, 0x0013,         0x000f,                        ssidatanochange, 0);
627  aim_conn_addhandler(sess, bosconn, 0x0008,         0x0002,                        handlepopup, 0);
628  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0003,                        faimtest_bosrights, 0);
629  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT,           faimtest_handleredirect, 0);
630  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL,  faimtest_reportinterval, 0);
631  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO,         faimtest_parse_buddyrights, 0);
632  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD,               faimtest_parse_motd, 0);
633  aim_conn_addhandler(sess, bosconn, 0x0004,         0x0005,                        faimtest_icbmparaminfo, 0);
634  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,    faimtest_parse_connerr, 0);
635  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO,         faimtest_locrights, 0);
636  aim_conn_addhandler(sess, bosconn, 0x0001,         0x001f,                        faimtest_memrequest, 0);
637  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING,           faimtest_parse_oncoming, 0);
638  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING,           faimtest_parse_offgoing, 0);
639  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING,           faimtest_parse_incoming_im, 0);
640  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR,              faimtest_parse_locerr, 0);
641  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL,         faimtest_parse_misses, 0);
642  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE,         faimtest_parse_ratechange, 0);
643  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL,               faimtest_parse_evilnotify, 0);
644
645  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0001,                        faimtest_parse_searcherror, 0);
646  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0003,                        faimtest_parse_searchreply, 0);
647
648  /*
649  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, AIM_CB_LOK_ERROR, faimtest_parse_searcherror, 0);
650  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, 0x0003, faimtest_parse_searchreply, 0);
651  */
652 
653  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR,              faimtest_parse_msgerr, 0);
654  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO,           faimtest_parse_userinfo, 0);
655  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK,                faimtest_parse_msgack, 0);
656
657  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0001,                        faimtest_parse_genericerr, 0);
658  aim_conn_addhandler(sess, bosconn, 0x0003,         0x0001,                        faimtest_parse_genericerr, 0);
659  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0001,                        faimtest_parse_genericerr, 0);
660  aim_conn_addhandler(sess, bosconn, 0x0001,         0x000b,                        serverpause, 0);
661  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0012,                        migrate, 0);
662  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG,         offlinemsg, 0);
663  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
664
665  /*
666  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,     gaim_connerr, 0);
667  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chatnav, 0);
668  */
669
670  /*
671  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_ERROR,              faimtest_ssi_parseerr, 0);
672  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO,         faimtest_ssi_parserights, 0);
673  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST,               faimtest_ssi_parselist, 0);
674  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_NOLIST,             faimtest_ssi_parselist, 0);
675  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK,             faimtest_ssi_parseack, 0);
676  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTH,           faimtest_ssi_authgiven, 0);
677  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTHREQ,        faimtest_ssi_authrequest, 0);
678  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTHREP,        faimtest_ssi_authreply, 0);
679  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_ADDED,              faimtest_ssi_gotadded, 0);
680  */
681
682  return;
683}
684
685static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
686{
687  owl_function_debugmsg("doing coninitdone_bos");
688
689
690  aim_reqpersonalinfo(sess, fr->conn);
691  aim_ssi_reqrights(sess);
692  aim_ssi_reqdata(sess);
693  aim_locate_reqrights(sess);
694  aim_buddylist_reqrights(sess, fr->conn);
695
696  aim_im_reqparams(sess);
697  /* aim_bos_reqrights(sess, fr->conn); */ /* XXX - Don't call this with ssi */
698
699  owl_function_debugmsg("conninitdone_bos: requesting rights");
700  aim_bos_reqrights(sess, fr->conn); /* XXX - Don't call this with ssi */
701  aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
702  aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE | AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
703
704  return(1);
705}
706
707static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
708{
709  aim_clientready(sess, fr->conn);
710  owl_function_debugmsg("conninitdone_admin: initializtion done for admin connection");
711  return(1);
712}
713
714int logout(aim_session_t *sess)
715{
716  aim_session_kill(sess);
717  owl_aim_init();
718
719  owl_function_debugmsg("libfaim logout called");
720  /*
721  if (faimtest_init() == -1)
722    printf("faimtest_init failed\n");
723  */
724
725  return(0);
726}
727
728/**************************************************************************************************/
729
730static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
731{
732  struct owlfaim_priv *priv = sess->aux_data;
733  va_list ap;
734  fu16_t code;
735  const char *msg;
736 
737  va_start(ap, fr);
738  code = va_arg(ap, int);
739  msg = va_arg(ap, const char *);
740  va_end(ap);
741 
742  owl_function_error("faimtest_parse_connerr: Code 0x%04x: %s\n", code, msg);
743  aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
744 
745  priv->connected = 0;
746 
747  return 1;
748}
749
750static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
751{
752  int status;
753  va_list ap;
754 
755  va_start(ap, fr);
756  status = va_arg(ap, int); /* status code of confirmation request */
757  va_end(ap);
758
759  /* owl_function_debugmsg("faimtest_accountconfirm: Code 0x%04x: %s\n", code, msg); */
760  owl_function_debugmsg("faimtest_accountconfirm: account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
761 
762  return 1;
763}
764
765static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
766{
767  fu16_t change = 0, perms, type;
768  int length, str;
769  const char *val;
770  va_list ap;
771 
772  va_start(ap, fr);
773  change = va_arg(ap, int);
774  perms = (fu16_t)va_arg(ap, unsigned int);
775  type = (fu16_t)va_arg(ap, unsigned int);
776  length = va_arg(ap, int);
777  val = va_arg(ap, const char *);
778  str = va_arg(ap, int);
779  va_end(ap);
780 
781  owl_function_debugmsg("faimtest_infochange: info%s: perms = %d, type = %x, length = %d, val = %s", change?" change":"", perms, type, length, str?val:"(not string)");
782 
783  return(1);
784}
785
786
787static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
788{
789  va_list ap;
790  struct aim_redirect_data *redir;
791
792  owl_function_debugmsg("faimtest_handledirect:");
793 
794  va_start(ap, fr);
795  redir = va_arg(ap, struct aim_redirect_data *);
796 
797  if (redir->group == 0x0005) {  /* Adverts */
798   
799  } else if (redir->group == 0x0007) {  /* Authorizer */
800    aim_conn_t *tstconn;
801
802    owl_function_debugmsg("faimtest_handledirect: autorizer");
803   
804    tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, redir->ip);
805    if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
806      owl_function_error("faimtest_handleredirect: unable to reconnect with authorizer");
807    } else {
808      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
809      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
810      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
811      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
812      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
813      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
814      /* Send the cookie to the Auth */
815      aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
816      owl_function_debugmsg("faimtest_handleredirect: sent cookie to authorizer host");
817    }
818  } else if (redir->group == 0x000d) {  /* ChatNav */
819    owl_function_debugmsg("faimtest_handledirect: chatnav");
820    chatnav_redirect(sess, redir);
821  } else if (redir->group == 0x000e) { /* Chat */
822    owl_function_debugmsg("faimtest_handledirect: chat");
823    chat_redirect(sess, redir);
824  } else {
825    owl_function_debugmsg("faimtest_handleredirect: uh oh... got redirect for unknown service 0x%04x!!", redir->group);
826  }
827  va_end(ap);
828  return 1;
829}
830
831static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
832{
833  struct aim_icbmparameters *params;
834  va_list ap;
835 
836  va_start(ap, fr);
837  params = va_arg(ap, struct aim_icbmparameters *);
838  va_end(ap);
839 
840  owl_function_debugmsg("faimtest_icbmparaminfo: ICBM Parameters: maxchannel = %d, default flags = 0x%08x, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %u",
841                       params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval);
842     
843  /*
844  * Set these to your taste, or client medium.  Setting minmsginterval
845  * higher is good for keeping yourself from getting flooded (esp
846  * if you're on a slow connection or something where that would be
847  * useful).
848  */
849  params->maxmsglen = 8000;
850  params->minmsginterval = 0; /* in milliseconds */
851  /* aim_seticbmparam(sess, params); */
852  aim_im_setparams(sess, params);
853 
854  return 1;
855}
856
857static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
858{
859  va_list ap;
860  fu16_t maxbuddies, maxwatchers;
861 
862  va_start(ap, fr);
863  maxbuddies = va_arg(ap, int);
864  maxwatchers = va_arg(ap, int);
865  va_end(ap);
866 
867  owl_function_debugmsg("faimtest_parse_buddyrights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
868 
869  /* aim_ssi_reqrights(sess, fr->conn); */
870  aim_ssi_reqrights(sess);
871 
872  return 1;
873}
874
875static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
876{
877  va_list ap;
878  fu16_t maxpermits, maxdenies;
879 
880  va_start(ap, fr);
881  maxpermits = va_arg(ap, int);
882  maxdenies = va_arg(ap, int);
883  va_end(ap);
884 
885  owl_function_debugmsg("faimtest_bosrights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
886  aim_clientready(sess, fr->conn);
887  owl_function_debugmsg("officially connected to BOS.");
888  aim_icq_reqofflinemsgs(sess);
889  return 1;
890}
891
892static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
893{
894  va_list ap;
895  fu16_t maxsiglen;
896 
897  va_start(ap, fr);
898  maxsiglen = va_arg(ap, int);
899  va_end(ap);
900
901  owl_function_debugmsg("faimtest_locrights: rights: max signature length = %d\n", maxsiglen);
902 
903  return(1);
904}
905
906static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
907{
908  struct owlfaim_priv *priv = sess->aux_data;
909  va_list ap;
910  fu16_t interval;
911
912  va_start(ap, fr);
913  interval = va_arg(ap, int);
914  va_end(ap);
915
916  owl_function_debugmsg("faimtest_reportinterval: %d (seconds?)\n", interval);
917
918  if (!priv->connected) {
919    priv->connected++;
920  }
921  /* aim_reqicbmparams(sess); */
922  aim_im_reqparams(sess);
923  /* kretch */
924  return 1;
925}
926
927static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
928{
929  const char *msg;
930  fu16_t id;
931  va_list ap;
932  static int codeslen = 5;
933  static const char *codes[] = {
934    "Unknown",
935    "Mandatory upgrade",
936    "Advisory upgrade",
937    "System bulletin",
938    "Top o' the world!"
939  };
940
941  va_start(ap, fr);
942  id = va_arg(ap, int);
943  msg = va_arg(ap, const char *);
944  va_end(ap);
945
946  owl_function_debugmsg("faimtest_parse_motd: %s (%d / %s)\n", msg?msg:"nomsg", id, (id < codeslen)?codes[id]:"unknown");
947 
948  return 1;
949}
950
951/*
952 * This is a little more complicated than it looks.  The module
953 * name (proto, boscore, etc) may or may not be given.  If it is
954 * not given, then use aim.exe.  If it is given, put ".ocm" on the
955 * end of it.
956 *
957 * Now, if the offset or length requested would cause a read past
958 * the end of the file, then the request is considered invalid.  Invalid
959 * requests are processed specially.  The value hashed is the
960 * the request, put into little-endian (eight bytes: offset followed
961 * by length). 
962 *
963 * Additionally, if the request is valid, the length is mod 4096.  It is
964 * important that the length is checked for validity first before doing
965 * the mod.
966 *
967 * Note to Bosco's Brigade: if you'd like to break this, put the
968 * module name on an invalid request.
969 *
970 */
971static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
972{
973  struct owlfaim_priv *priv = sess->aux_data;
974  FILE *f;
975  static const char defaultmod[] = "aim.exe";
976  char *filename = NULL;
977  struct stat st;
978  unsigned char *buf;
979  int invalid = 0;
980 
981  if (!bufret || !buflenret)
982    return -1;
983 
984  if (modname) {
985    filename = owl_sprintf("%s/%s.ocm", priv->aimbinarypath, modname);
986  } else {
987    filename = owl_sprintf("%s/%s", priv->aimbinarypath, defaultmod);
988  }
989 
990  if (stat(filename, &st) == -1) {
991    if (!modname) {
992      /* perror("memrequest: stat"); */
993      owl_free(filename);
994      return -1;
995    }
996    invalid = 1;
997  }
998 
999  if (!invalid) {
1000    if ((offset > st.st_size) || (len > st.st_size))
1001      invalid = 1;
1002    else if ((st.st_size - offset) < len)
1003      len = st.st_size - offset;
1004    else if ((st.st_size - len) < len)
1005      len = st.st_size - len;
1006  }
1007 
1008  if (!invalid && len) {
1009    len %= 4096;
1010  }
1011 
1012  if (invalid) {
1013    int i;
1014   
1015    owl_free(filename); /* not needed */
1016    owl_function_error("getaimdata memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
1017    i = 8;
1018    if (modname) {
1019      i+=strlen(modname);
1020    }
1021   
1022    if (!(buf = owl_malloc(i))) {
1023      return -1;
1024    }
1025   
1026    i=0;
1027   
1028    if (modname) {
1029      memcpy(buf, modname, strlen(modname));
1030      i+=strlen(modname);
1031    }
1032   
1033    /* Damn endianness. This must be little (LSB first) endian. */
1034    buf[i++] = offset & 0xff;
1035    buf[i++] = (offset >> 8) & 0xff;
1036    buf[i++] = (offset >> 16) & 0xff;
1037    buf[i++] = (offset >> 24) & 0xff;
1038    buf[i++] = len & 0xff;
1039    buf[i++] = (len >> 8) & 0xff;
1040    buf[i++] = (len >> 16) & 0xff;
1041    buf[i++] = (len >> 24) & 0xff;
1042   
1043    *bufret = buf;
1044    *buflenret = i;
1045  } else {
1046    if (!(buf = owl_malloc(len))) {
1047      owl_free(filename);
1048      return -1;
1049    }
1050    /* printf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); */
1051    if (!(f = fopen(filename, "r"))) {
1052      /* perror("memrequest: fopen"); */
1053      owl_free(filename);
1054      owl_free(buf);
1055      return -1;
1056    }
1057   
1058    owl_free(filename);
1059   
1060    if (fseek(f, offset, SEEK_SET) == -1) {
1061      /* perror("memrequest: fseek"); */
1062      fclose(f);
1063      owl_free(buf);
1064      return -1;
1065    }
1066   
1067    if (fread(buf, len, 1, f) != 1) {
1068      /* perror("memrequest: fread"); */
1069      fclose(f);
1070      owl_free(buf);
1071      return -1;
1072    }
1073   
1074    fclose(f);
1075    *bufret = buf;
1076    *buflenret = len;
1077  }
1078  return 0; /* success! */
1079}
1080
1081/*
1082 * This will get an offset and a length.  The client should read this
1083 * data out of whatever AIM.EXE binary the user has provided (hopefully
1084 * it matches the client information thats sent at login) and pass a
1085 * buffer back to libfaim so it can hash the data and send it to AOL for
1086 * inspection by the client police.
1087 */
1088static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
1089{
1090  struct owlfaim_priv *priv = sess->aux_data;
1091  va_list ap;
1092  fu32_t offset, len;
1093  const char *modname;
1094  unsigned char *buf;
1095  int buflen;
1096 
1097  va_start(ap, fr);
1098  offset = va_arg(ap, fu32_t);
1099  len = va_arg(ap, fu32_t);
1100  modname = va_arg(ap, const char *);
1101  va_end(ap);
1102 
1103  if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
1104    aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1105    owl_free(buf);
1106  } else {
1107    owl_function_debugmsg("faimtest_memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
1108    aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1109  }
1110  return 1;
1111}
1112
1113/*
1114static void printuserflags(fu16_t flags)
1115{
1116  if (flags & AIM_FLAG_UNCONFIRMED) printf("UNCONFIRMED ");
1117  if (flags & AIM_FLAG_ADMINISTRATOR) printf("ADMINISTRATOR ");
1118  if (flags & AIM_FLAG_AOL) printf("AOL ");
1119  if (flags & AIM_FLAG_OSCAR_PAY) printf("OSCAR_PAY ");
1120  if (flags & AIM_FLAG_FREE) printf("FREE ");
1121  if (flags & AIM_FLAG_AWAY) printf("AWAY ");
1122  if (flags & AIM_FLAG_ICQ) printf("ICQ ");
1123  if (flags & AIM_FLAG_WIRELESS) printf("WIRELESS ");
1124  if (flags & AIM_FLAG_ACTIVEBUDDY) printf("ACTIVEBUDDY ");
1125 
1126  return;
1127}
1128*/
1129
1130static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
1131{
1132  aim_userinfo_t *userinfo;
1133  const char *prof_encoding = NULL;
1134  const char *prof = NULL;
1135  fu16_t inforeq = 0;
1136  owl_buddy *b;
1137  va_list ap;
1138  va_start(ap, fr);
1139  userinfo = va_arg(ap, aim_userinfo_t *);
1140  inforeq = (fu16_t)va_arg(ap, unsigned int);
1141  prof_encoding = va_arg(ap, const char *);
1142  prof = va_arg(ap, const char *);
1143  va_end(ap);
1144
1145  /* right now the only reason we call this is for idle times */
1146  owl_function_debugmsg("parse_userinfo sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1147  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g),
1148                                userinfo->sn);
1149  if (!b) return(1);
1150  owl_buddy_set_idle_since(b, userinfo->idletime);
1151  return(1);
1152
1153  /*
1154  printf("userinfo: sn: %s\n", userinfo->sn);
1155  printf("userinfo: warnlevel: %f\n", aim_userinfo_warnlevel(userinfo));
1156  printf("userinfo: flags: 0x%04x = ", userinfo->flags);
1157  printuserflags(userinfo->flags);
1158  printf("\n");
1159  */
1160
1161  /*
1162  printf("userinfo: membersince: %lu\n", userinfo->membersince);
1163  printf("userinfo: onlinesince: %lu\n", userinfo->onlinesince);
1164  printf("userinfo: idletime: 0x%04x\n", userinfo->idletime);
1165  printf("userinfo: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1166  */
1167
1168  /*
1169  if (inforeq == AIM_GETINFO_GENERALINFO) {
1170    owl_function_debugmsg("userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1171    owl_function_debugmsg("userinfo: prof: %s\n", prof ? prof : "[none]");
1172  } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
1173    owl_function_debugmsg("userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1174    owl_function_debugmsg("userinfo: awaymsg: %s\n", prof ? prof : "[none]");
1175  } else if (inforeq == AIM_GETINFO_CAPABILITIES) {
1176    owl_function_debugmsg("userinfo: capabilities: see above\n");
1177  } else {
1178    owl_function_debugmsg("userinfo: unknown info request\n");
1179  }
1180  */
1181  return(1);
1182}
1183
1184/*
1185 * Channel 1: Standard Message
1186 */
1187static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1188{
1189  owl_message *m;
1190  char *stripmsg, *nz_screenname, *wrapmsg;
1191  char *realmsg = NULL;
1192
1193  if (!args->msg) {
1194    realmsg = owl_strdup("");
1195  } else if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1196    realmsg = g_convert(args->msg, args->msglen, "UTF-8", "UCS-2BE",
1197                        NULL, NULL, NULL);
1198  } else if(args->icbmflags & AIM_IMFLAGS_ISO_8859_1) {
1199    realmsg = g_convert(args->msg, args->msglen, "UTF-8", "ISO-8859-1",
1200                        NULL, NULL, NULL);
1201  } else {
1202    realmsg = owl_strdup(args->msg);
1203  }
1204
1205  if (!realmsg) {
1206    realmsg = owl_strdup("[Error decoding incoming IM]");
1207  }
1208
1209  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: message from: %s", userinfo->sn?userinfo->sn:"");
1210  /* create a message, and put it on the message queue */
1211  stripmsg=owl_text_htmlstrip(realmsg);
1212  wrapmsg=owl_text_wordwrap(stripmsg, 70);
1213  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1214  m=owl_malloc(sizeof(owl_message));
1215  owl_message_create_aim(m,
1216                         nz_screenname,
1217                         owl_global_get_aim_screenname(&g),
1218                         wrapmsg,
1219                         OWL_MESSAGE_DIRECTION_IN,
1220                         0);
1221  if (args->icbmflags & AIM_IMFLAGS_AWAY) owl_message_set_attribute(m, "isauto", "");
1222  owl_global_messagequeue_addmsg(&g, m);
1223  owl_free(stripmsg);
1224  owl_free(wrapmsg);
1225  owl_free(nz_screenname);
1226
1227  return(1);
1228
1229  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: message: %s\n", realmsg);
1230 
1231  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1232    aim_mpmsg_section_t *sec;
1233    int z;
1234
1235    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart: this message has %d parts\n", args->mpmsg.numparts);
1236   
1237    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1238      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1239        owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data);
1240      } else {
1241        owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset);
1242      }
1243    }
1244  }
1245 
1246  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1247    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1248    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: their icon: iconstamp = %ld, iconlen = 0x%08x, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum);
1249  }
1250
1251  owl_free(realmsg);
1252
1253  return(1);
1254}
1255
1256/*
1257 * Channel 2: Rendevous Request
1258 */
1259static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1260{
1261  /*
1262  printf("rendezvous: source sn = %s\n", userinfo->sn);
1263  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1264  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1265  printuserflags(userinfo->flags);
1266  printf("\n");
1267 
1268  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1269  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1270 
1271  printf("rendezvous: message/description = %s\n", args->msg);
1272  printf("rendezvous: encoding = %s\n", args->encoding);
1273  printf("rendezvous: language = %s\n", args->language);
1274  */
1275 
1276  if (args->reqclass == AIM_CAPS_SENDFILE) {
1277    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: send file!");
1278  } else if (args->reqclass == AIM_CAPS_CHAT) {
1279    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: chat invite: %s, %i, %i", args->info.chat.roominfo.name, args->info.chat.roominfo.exchange, args->info.chat.roominfo.instance);
1280    /*
1281    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1282    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1283    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1284    */
1285    /* Automatically join room... */
1286    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1287
1288    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1289  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1290    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: Buddy Icon from %s, length = %u\n",
1291                          userinfo->sn, args->info.icon.length);
1292  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1293    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: RTF message from %s: (fgcolor = 0x%08x, bgcolor = 0x%08x) %s\n",
1294                          userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg);
1295  } else {
1296    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: icbm: unknown reqclass (%d)\n", args->reqclass);
1297  }
1298  return 1;
1299}
1300
1301static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1302{
1303  fu16_t channel;
1304  aim_userinfo_t *userinfo;
1305  va_list ap;
1306  int ret = 0;
1307 
1308  va_start(ap, fr);
1309  channel = (fu16_t)va_arg(ap, unsigned int);
1310  userinfo = va_arg(ap, aim_userinfo_t *);
1311 
1312  if (channel == 1) {
1313    struct aim_incomingim_ch1_args *args;
1314    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1315    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1316  } else if (channel == 2) {
1317    struct aim_incomingim_ch2_args *args;
1318    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1319    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1320  } else {
1321    owl_function_debugmsg("faimtest_parse_incoming_im: unsupported channel 0x%04x\n", channel);
1322  }
1323  va_end(ap);
1324  owl_function_debugmsg("faimtest_parse_incoming_im: done with ICBM handling (ret = %d)\n", ret);
1325  return 1;
1326}
1327
1328static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1329{
1330  aim_userinfo_t *userinfo;
1331  char *nz_screenname;
1332  owl_buddy *b;
1333  va_list ap;
1334  va_start(ap, fr);
1335  userinfo = va_arg(ap, aim_userinfo_t *);
1336  va_end(ap);
1337
1338  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1339 
1340  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1341
1342  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1343    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1344  }
1345
1346  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1347  if (!b) {
1348    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1349    return(1);
1350  }
1351  if (userinfo->idletime==0) {
1352    owl_buddy_set_unidle(b);
1353  } else {
1354    owl_buddy_set_idle(b);
1355    owl_buddy_set_idle_since(b, userinfo->idletime);
1356  }
1357
1358  if (userinfo->flags & AIM_FLAG_AWAY) {
1359    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1360  }
1361 
1362  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1363   
1364  owl_free(nz_screenname);
1365 
1366  /*
1367    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1368    time(NULL),
1369    userinfo->sn, userinfo->flags,
1370    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1371    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1372    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1373    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1374    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1375    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1376    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1377    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1378    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1379    userinfo->capabilities);
1380  */
1381  return(1);
1382}
1383
1384static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1385{
1386  aim_userinfo_t *userinfo;
1387  char *nz_screenname;
1388  va_list ap;
1389 
1390  va_start(ap, fr);
1391  userinfo = va_arg(ap, aim_userinfo_t *);
1392  va_end(ap);
1393
1394  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1395  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1396  owl_free(nz_screenname);
1397
1398  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1399    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1400  }
1401
1402  /*
1403  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1404         time(NULL),
1405         userinfo->sn, userinfo->flags,
1406         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1407         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1408         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1409         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1410         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1411         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1412         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1413         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1414         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1415         userinfo->capabilities);
1416  */
1417 
1418  return 1;
1419}
1420
1421/* Used by chat as well. */
1422int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1423{
1424  va_list ap;
1425  fu16_t reason;
1426 
1427  va_start(ap, fr);
1428  reason = (fu16_t)va_arg(ap, unsigned int);
1429  va_end(ap);
1430 
1431  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1432  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1433 
1434  return 1;
1435}
1436
1437static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1438{
1439  va_list ap;
1440  const char *destsn;
1441  fu16_t reason;
1442 
1443  va_start(ap, fr);
1444  reason = (fu16_t)va_arg(ap, unsigned int);
1445  destsn = va_arg(ap, const char *);
1446  va_end(ap);
1447 
1448  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1449  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1450
1451  if (reason==4) {
1452    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1453  }
1454 
1455  return 1;
1456}
1457
1458static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1459{
1460  va_list ap;
1461  const char *destsn;
1462  fu16_t reason;
1463 
1464  va_start(ap, fr);
1465  reason = (fu16_t)va_arg(ap, unsigned int);
1466  destsn = va_arg(ap, const char *);
1467  va_end(ap);
1468 
1469  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1470  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1471 
1472  return 1;
1473}
1474
1475static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1476{
1477  static const char *missedreasons[] = {
1478    "Invalid (0)",
1479    "Message too large",
1480    "Rate exceeded",
1481    "Evil Sender",
1482    "Evil Receiver"
1483  };
1484  static int missedreasonslen = 5;
1485 
1486  va_list ap;
1487  fu16_t chan, nummissed, reason;
1488  aim_userinfo_t *userinfo;
1489 
1490  va_start(ap, fr);
1491  chan = (fu16_t)va_arg(ap, unsigned int);
1492  userinfo = va_arg(ap, aim_userinfo_t *);
1493  nummissed = (fu16_t)va_arg(ap, unsigned int);
1494  reason = (fu16_t)va_arg(ap, unsigned int);
1495  va_end(ap);
1496 
1497  owl_function_debugmsg("faimtest_parse_misses: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1498 
1499  return 1;
1500}
1501
1502/*
1503 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1504 */
1505static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1506{
1507  va_list ap;
1508  fu16_t type;
1509  const char *sn = NULL;
1510 
1511  va_start(ap, fr);
1512  type = (fu16_t)va_arg(ap, unsigned int);
1513  sn = va_arg(ap, const char *);
1514  va_end(ap);
1515 
1516  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1517 
1518  return 1;
1519}
1520
1521static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1522{
1523  static const char *codes[5] = {
1524    "invalid",
1525    "change",
1526    "warning",
1527    "limit",
1528    "limit cleared"
1529  };
1530  va_list ap;
1531  fu16_t code, rateclass;
1532  fu32_t windowsize, clear, alert, limit, disconnect;
1533  fu32_t currentavg, maxavg;
1534 
1535  va_start(ap, fr); 
1536 
1537  /* See code explanations below */
1538  code = (fu16_t)va_arg(ap, unsigned int);
1539 
1540  /*
1541   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1542   */
1543  rateclass = (fu16_t)va_arg(ap, unsigned int);
1544 
1545  /*
1546   * Not sure what this is exactly.  I think its the temporal
1547   * relation factor (ie, how to make the rest of the numbers
1548   * make sense in the real world).
1549   */
1550  windowsize = va_arg(ap, fu32_t);
1551 
1552  /* Explained below */
1553  clear = va_arg(ap, fu32_t);
1554  alert = va_arg(ap, fu32_t);
1555  limit = va_arg(ap, fu32_t);
1556  disconnect = va_arg(ap, fu32_t);
1557  currentavg = va_arg(ap, fu32_t);
1558  maxavg = va_arg(ap, fu32_t);
1559 
1560  va_end(ap);
1561 
1562  owl_function_debugmsg("faimtest_parse_ratechange: rate %s (rate class 0x%04x): curavg = %u, maxavg = %u, alert at %u, clear warning at %u, limit at %u, disconnect at %u (window size = %u)",
1563                        (code < 5)?codes[code]:"invalid",
1564                        rateclass,
1565                        currentavg, maxavg,
1566                        alert, clear,
1567                        limit, disconnect,
1568                        windowsize);
1569  return 1;
1570}
1571
1572static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1573{
1574  va_list ap;
1575  fu16_t newevil;
1576  aim_userinfo_t *userinfo;
1577 
1578  va_start(ap, fr);
1579  newevil = (fu16_t)va_arg(ap, unsigned int);
1580  userinfo = va_arg(ap, aim_userinfo_t *);
1581  va_end(ap);
1582 
1583  /*
1584   * Evil Notifications that are lacking userinfo->sn are anon-warns
1585   * if they are an evil increases, but are not warnings at all if its
1586   * a decrease (its the natural backoff happening).
1587   *
1588   * newevil is passed as an int representing the new evil value times
1589   * ten.
1590   */
1591  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1592 
1593  return 1;
1594}
1595
1596static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1597{
1598  va_list ap;
1599  const char *address, *SNs;
1600  int num, i;
1601  owl_list list;
1602 
1603  va_start(ap, fr);
1604  address = va_arg(ap, const char *);
1605  num = va_arg(ap, int);
1606  SNs = va_arg(ap, const char *);
1607  va_end(ap);
1608
1609  owl_list_create(&list);
1610 
1611  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1612  for (i=0; i<num; i++) {
1613    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1614    owl_list_append_element(&list, (void *)&SNs[i*(MAXSNLEN+1)]);
1615  }
1616  owl_function_aimsearch_results(address, &list);
1617  owl_list_free_simple(&list);
1618  return(1);
1619}
1620
1621static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1622{
1623  va_list ap;
1624  const char *address;
1625 
1626  va_start(ap, fr);
1627  address = va_arg(ap, const char *);
1628  va_end(ap);
1629
1630  owl_function_error("No results searching for %s", address);
1631  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1632 
1633  return(1);
1634}
1635
1636static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1637{
1638  va_list ap;
1639  const char *msg, *url;
1640  fu16_t width, height, delay;
1641 
1642  va_start(ap, fr);
1643  msg = va_arg(ap, const char *);
1644  url = va_arg(ap, const char *);
1645  width = va_arg(ap, unsigned int);
1646  height = va_arg(ap, unsigned int);
1647  delay = va_arg(ap, unsigned int);
1648  va_end(ap);
1649 
1650  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1651 
1652  return 1;
1653}
1654
1655static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1656{
1657  aim_sendpauseack(sess, fr->conn);
1658  return 1;
1659}
1660
1661static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1662{
1663  va_list ap;
1664  aim_conn_t *bosconn;
1665  const char *bosip;
1666  fu8_t *cookie;
1667 
1668  va_start(ap, fr);
1669  bosip = va_arg(ap, const char *);
1670  cookie = va_arg(ap, fu8_t *);
1671  va_end(ap);
1672 
1673  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1674  aim_conn_kill(sess, &fr->conn);
1675 
1676  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1677    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1678    return 1;
1679  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1680    owl_function_debugmsg("migrate: could not connect to BOS");
1681    aim_conn_kill(sess, &bosconn);
1682    return 1;
1683  }
1684 
1685  /* Login will happen all over again. */
1686  addcb_bos(sess, bosconn);
1687  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1688  return 1;
1689}
1690
1691static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1692{
1693  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1694  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1695  aim_ssi_reqdata(sess);
1696 
1697  return(1);
1698}
1699
1700static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1701{
1702  va_list ap;
1703  fu8_t fmtver;
1704  fu16_t itemcount;
1705  fu32_t stamp;
1706  struct aim_ssi_item *list;
1707  /*
1708  struct aim_ssi_item *curitem;
1709  struct aim_ssi_item *l;
1710  */
1711 
1712  va_start(ap, fr);
1713  fmtver = va_arg(ap, unsigned int);
1714  itemcount = va_arg(ap, unsigned int);
1715  stamp = va_arg(ap, fu32_t);
1716  list = va_arg(ap, struct aim_ssi_item *);
1717  va_end(ap);
1718 
1719  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %u)", fmtver, itemcount, stamp);
1720  /*
1721  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1722    for (l = list; l; l = l->next) {
1723      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1724    }
1725  }
1726  */
1727  aim_ssi_enable(sess);
1728 
1729  return 1;
1730}
1731
1732static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1733{
1734  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1735  /* aim_ssi_enable(sess, fr->conn); */
1736  aim_ssi_enable(sess);
1737  return 1;
1738}
1739
1740static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1741{
1742  va_list ap;
1743  struct aim_icq_offlinemsg *msg;
1744 
1745  va_start(ap, fr);
1746  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1747  va_end(ap);
1748 
1749  if (msg->type == 0x0001) {
1750    owl_function_debugmsg("offlinemsg: from %u at %d/%d/%d %02d:%02d : %s", msg->sender, msg->year, msg->month, msg->day, msg->hour, msg->minute, msg->msg);
1751  } else {
1752    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1753  }
1754  return 1;
1755}
1756
1757static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1758{
1759  /* Tell the server to delete them. */
1760  owl_function_debugmsg("offlinemsg done: ");
1761  aim_icq_ackofflinemsgs(sess);
1762  return 1;
1763}
1764
1765
1766/******************** chat.c **************************/
1767
1768static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1769{
1770  va_list ap;
1771  aim_userinfo_t *userinfo;
1772  int count;
1773  /* int i; */
1774 
1775  va_start(ap, fr);
1776  count = va_arg(ap, int);
1777  userinfo = va_arg(ap, aim_userinfo_t *);
1778  va_end(ap);
1779
1780  owl_function_debugmsg("In faimtest_chat_join");
1781  /*
1782  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1783  for (i = 0; i < count; i++)
1784    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1785  */
1786  return 1;
1787}
1788
1789static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1790{
1791  aim_userinfo_t *userinfo;
1792  va_list ap;
1793  int count;
1794  /* int i; */
1795
1796 
1797  va_start(ap, fr);
1798  count = va_arg(ap, int);
1799  userinfo = va_arg(ap, aim_userinfo_t *);
1800  va_end(ap);
1801 
1802  /*
1803    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1804   
1805    for (i = 0; i < count; i++)
1806    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1807  */
1808  return 1;
1809}
1810
1811static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1812{
1813  va_list ap;
1814  aim_userinfo_t *userinfo;
1815  struct aim_chat_roominfo *roominfo;
1816  const char *roomname;
1817  int usercount;
1818  const char *roomdesc;
1819  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1820  fu32_t creationtime;
1821  const char *croomname;
1822  /* int i; */
1823 
1824  croomname = aim_chat_getname(fr->conn);
1825 
1826  va_start(ap, fr);
1827  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1828  roomname = va_arg(ap, const char *);
1829  usercount = va_arg(ap, int);
1830  userinfo = va_arg(ap, aim_userinfo_t *);
1831  roomdesc = va_arg(ap, const char *);
1832  flags = (fu16_t)va_arg(ap, unsigned int);
1833  creationtime = va_arg(ap, fu32_t);
1834  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1835  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1836  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1837  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1838  va_end(ap);
1839
1840  owl_function_debugmsg("In faimtest_chat_infoupdate");
1841  /*
1842  printf("chat: %s:  info update:\n", croomname);
1843  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1844  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1845  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1846  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1847
1848  for (i = 0; i < usercount; i++)
1849    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1850 
1851  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1852         croomname, flags,
1853         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1854         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1855         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1856         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1857  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1858  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1859  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1860  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1861  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1862  */
1863 
1864  return(1);
1865}
1866
1867static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1868{
1869  va_list ap;
1870  aim_userinfo_t *userinfo;
1871  const char *msg;
1872  char tmpbuf[1152];
1873 
1874  va_start(ap, fr);
1875  userinfo = va_arg(ap, aim_userinfo_t *);     
1876  msg = va_arg(ap, const char *);
1877  va_end(ap);
1878
1879  owl_function_debugmsg("in faimtest_chat_incomingmsg");
1880
1881  /*
1882  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1883  */
1884 
1885  /*
1886   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1887   */
1888  if (strcmp(userinfo->sn, sess->sn) != 0) {
1889    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1890    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1891  }
1892 
1893  return 1;
1894}
1895
1896static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1897{
1898  owl_function_debugmsg("faimtest_conninitdone_chat:");
1899
1900  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1901  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1902  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1903  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1904  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1905 
1906  aim_clientready(sess, fr->conn);
1907 
1908  owl_function_debugmsg("Chat ready");
1909
1910  /*
1911    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
1912    chatcon->id = id;
1913    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
1914  */
1915  return(1);
1916}
1917
1918void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1919{
1920  aim_conn_t *tstconn;
1921
1922  owl_function_debugmsg("in faimtest_chatnav_redirect");
1923 
1924  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1925  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1926    /* printf("unable to connect to chat(nav) server\n"); */
1927    if (tstconn)
1928      aim_conn_kill(sess, &tstconn);
1929    return;
1930  }
1931 
1932  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1933  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1934  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1935  /* printf("chatnav: connected\n"); */
1936  return;
1937}
1938
1939/* XXX this needs instance too */
1940void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1941{
1942  aim_conn_t *tstconn;
1943
1944  owl_function_debugmsg("in chat_redirect");
1945 
1946  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
1947  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1948    /* printf("unable to connect to chat server\n"); */
1949    if (tstconn) aim_conn_kill(sess, &tstconn);
1950    return; 
1951  }             
1952  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
1953 
1954  /*
1955   * We must do this to attach the stored name to the connection!
1956   */
1957  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
1958  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1959  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1960  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1961  return;       
1962}
1963
1964void owl_process_aim(void)
1965{
1966  if (owl_global_is_doaimevents(&g)) {
1967    owl_aim_process_events();
1968  }
1969}
Note: See TracBrowser for help on using the repository browser.