source: aim.c @ 82a79a6

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 82a79a6 was 82a79a6, checked in by Nelson Elhage <nelhage@mit.edu>, 14 years ago
AIM: Correctly send outgoing IMs with high-bit characters. Encode messages as either iso-8859-1 or ucs-2 as necessary, and set the appropriate flags to make it work properly. We don't support sending characters that are not representable in UCS-2, for now. Doing so would probably require that I better understand libfaim.
  • Property mode set to 100644
File size: 67.1 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[8192+1] = "";
1192  /* int clienttype = AIM_CLIENTTYPE_UNKNOWN; */
1193
1194  /* clienttype = aim_fingerprintclient(args->features, args->featureslen); */
1195
1196  /*
1197  printf("icbm: sn = \"%s\"\n", userinfo->sn);
1198  printf("icbm: probable client type: %d\n", clienttype);
1199  printf("icbm: warnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1200  printf("icbm: flags = 0x%04x = ", userinfo->flags);
1201  printuserflags(userinfo->flags);
1202  printf("\n");
1203  */
1204
1205  /*
1206  printf("icbm: membersince = %lu\n", userinfo->membersince);
1207  printf("icbm: onlinesince = %lu\n", userinfo->onlinesince);
1208  printf("icbm: idletime = 0x%04x\n", userinfo->idletime);
1209  printf("icbm: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1210  */
1211
1212  /*
1213  printf("icbm: icbmflags = ");
1214  if (args->icbmflags & AIM_IMFLAGS_AWAY) printf("away ");
1215  if (args->icbmflags & AIM_IMFLAGS_ACK) printf("ackrequest ");
1216  if (args->icbmflags & AIM_IMFLAGS_OFFLINE) printf("offline ");
1217  if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) printf("buddyreq ");
1218  if (args->icbmflags & AIM_IMFLAGS_HASICON) printf("hasicon ");
1219  printf("\n");
1220  */
1221
1222  /*
1223  if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET) {
1224  printf("icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset);
1225  }
1226  */
1227 
1228  /*
1229   * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1230   * characters with their equivelent HTML entity.
1231   */
1232  if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1233    int i;
1234   
1235    for (i=0; i<args->msglen; i+=2) {
1236      fu16_t uni;
1237
1238      uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1239      if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1240        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1241      } else { /* something else, do UNICODE entity */
1242        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1243      }
1244    }
1245  } else {
1246    /*
1247     * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1248     * no need to do anything special here.  Most
1249     * terminals/whatever will be able to display such characters
1250     * unmodified.
1251     *
1252     * Beware that PC-ASCII 128 through 159 are _not_ actually
1253     * defined in ASCII or ISO 8859-1, and you should send them as
1254     * UNICODE.  WinAIM will send these characters in a UNICODE
1255     * message, so you need to do so as well.
1256     *
1257     * You may not think it necessary to handle UNICODE messages. 
1258     * You're probably wrong.  For one thing, Microsoft "Smart
1259     * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1260     * but real UNICODE). If you don't parse UNICODE at all, your
1261     * users will get a blank message instead of the message
1262     * containing Smart Quotes.
1263     *
1264     */
1265    if (args->msg && args->msglen)
1266      strncpy(realmsg, args->msg, sizeof(realmsg));
1267  }
1268
1269  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: message from: %s", userinfo->sn?userinfo->sn:"");
1270  /* create a message, and put it on the message queue */
1271  stripmsg=owl_text_htmlstrip(realmsg);
1272  wrapmsg=owl_text_wordwrap(stripmsg, 70);
1273  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1274  m=owl_malloc(sizeof(owl_message));
1275  owl_message_create_aim(m,
1276                         nz_screenname,
1277                         owl_global_get_aim_screenname(&g),
1278                         wrapmsg,
1279                         OWL_MESSAGE_DIRECTION_IN,
1280                         0);
1281  if (args->icbmflags & AIM_IMFLAGS_AWAY) owl_message_set_attribute(m, "isauto", "");
1282  owl_global_messagequeue_addmsg(&g, m);
1283  owl_free(stripmsg);
1284  owl_free(wrapmsg);
1285  owl_free(nz_screenname);
1286
1287  return(1);
1288
1289  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: message: %s\n", realmsg);
1290 
1291  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1292    aim_mpmsg_section_t *sec;
1293    int z;
1294
1295    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart: this message has %d parts\n", args->mpmsg.numparts);
1296   
1297    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1298      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1299        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);
1300      } else {
1301        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);
1302      }
1303    }
1304  }
1305 
1306  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1307    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1308    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);
1309  }
1310
1311  /*
1312  if (realmsg) {
1313    int i = 0;
1314    while (realmsg[i] == '<') {
1315      if (realmsg[i] == '<') {
1316        while (realmsg[i] != '>')
1317          i++;
1318        i++;
1319      }
1320    }
1321    tmpstr = realmsg+i;
1322    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1323  }
1324  */
1325 
1326  return(1);
1327}
1328
1329/*
1330 * Channel 2: Rendevous Request
1331 */
1332static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1333{
1334  /*
1335  printf("rendezvous: source sn = %s\n", userinfo->sn);
1336  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1337  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1338  printuserflags(userinfo->flags);
1339  printf("\n");
1340 
1341  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1342  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1343 
1344  printf("rendezvous: message/description = %s\n", args->msg);
1345  printf("rendezvous: encoding = %s\n", args->encoding);
1346  printf("rendezvous: language = %s\n", args->language);
1347  */
1348 
1349  if (args->reqclass == AIM_CAPS_SENDFILE) {
1350    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: send file!");
1351  } else if (args->reqclass == AIM_CAPS_CHAT) {
1352    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);
1353    /*
1354    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1355    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1356    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1357    */
1358    /* Automatically join room... */
1359    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1360
1361    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1362  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1363    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: Buddy Icon from %s, length = %u\n",
1364                          userinfo->sn, args->info.icon.length);
1365  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1366    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: RTF message from %s: (fgcolor = 0x%08x, bgcolor = 0x%08x) %s\n",
1367                          userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg);
1368  } else {
1369    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: icbm: unknown reqclass (%d)\n", args->reqclass);
1370  }
1371  return 1;
1372}
1373
1374static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1375{
1376  fu16_t channel;
1377  aim_userinfo_t *userinfo;
1378  va_list ap;
1379  int ret = 0;
1380 
1381  va_start(ap, fr);
1382  channel = (fu16_t)va_arg(ap, unsigned int);
1383  userinfo = va_arg(ap, aim_userinfo_t *);
1384 
1385  if (channel == 1) {
1386    struct aim_incomingim_ch1_args *args;
1387    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1388    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1389  } else if (channel == 2) {
1390    struct aim_incomingim_ch2_args *args;
1391    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1392    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1393  } else {
1394    owl_function_debugmsg("faimtest_parse_incoming_im: unsupported channel 0x%04x\n", channel);
1395  }
1396  va_end(ap);
1397  owl_function_debugmsg("faimtest_parse_incoming_im: done with ICBM handling (ret = %d)\n", ret);
1398  return 1;
1399}
1400
1401static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1402{
1403  aim_userinfo_t *userinfo;
1404  char *nz_screenname;
1405  owl_buddy *b;
1406  va_list ap;
1407  va_start(ap, fr);
1408  userinfo = va_arg(ap, aim_userinfo_t *);
1409  va_end(ap);
1410
1411  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1412 
1413  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1414
1415  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1416    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1417  }
1418
1419  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1420  if (!b) {
1421    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1422    return(1);
1423  }
1424  if (userinfo->idletime==0) {
1425    owl_buddy_set_unidle(b);
1426  } else {
1427    owl_buddy_set_idle(b);
1428    owl_buddy_set_idle_since(b, userinfo->idletime);
1429  }
1430
1431  if (userinfo->flags & AIM_FLAG_AWAY) {
1432    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1433  }
1434 
1435  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1436   
1437  owl_free(nz_screenname);
1438 
1439  /*
1440    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1441    time(NULL),
1442    userinfo->sn, userinfo->flags,
1443    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1444    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1445    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1446    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1447    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1448    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1449    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1450    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1451    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1452    userinfo->capabilities);
1453  */
1454  return(1);
1455}
1456
1457static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1458{
1459  aim_userinfo_t *userinfo;
1460  char *nz_screenname;
1461  va_list ap;
1462 
1463  va_start(ap, fr);
1464  userinfo = va_arg(ap, aim_userinfo_t *);
1465  va_end(ap);
1466
1467  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1468  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1469  owl_free(nz_screenname);
1470
1471  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1472    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1473  }
1474
1475  /*
1476  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1477         time(NULL),
1478         userinfo->sn, userinfo->flags,
1479         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1480         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1481         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1482         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1483         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1484         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1485         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1486         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1487         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1488         userinfo->capabilities);
1489  */
1490 
1491  return 1;
1492}
1493
1494/* Used by chat as well. */
1495int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1496{
1497  va_list ap;
1498  fu16_t reason;
1499 
1500  va_start(ap, fr);
1501  reason = (fu16_t)va_arg(ap, unsigned int);
1502  va_end(ap);
1503 
1504  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1505  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1506 
1507  return 1;
1508}
1509
1510static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1511{
1512  va_list ap;
1513  const char *destsn;
1514  fu16_t reason;
1515 
1516  va_start(ap, fr);
1517  reason = (fu16_t)va_arg(ap, unsigned int);
1518  destsn = va_arg(ap, const char *);
1519  va_end(ap);
1520 
1521  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1522  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1523
1524  if (reason==4) {
1525    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1526  }
1527 
1528  return 1;
1529}
1530
1531static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1532{
1533  va_list ap;
1534  const char *destsn;
1535  fu16_t reason;
1536 
1537  va_start(ap, fr);
1538  reason = (fu16_t)va_arg(ap, unsigned int);
1539  destsn = va_arg(ap, const char *);
1540  va_end(ap);
1541 
1542  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1543  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1544 
1545  return 1;
1546}
1547
1548static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1549{
1550  static const char *missedreasons[] = {
1551    "Invalid (0)",
1552    "Message too large",
1553    "Rate exceeded",
1554    "Evil Sender",
1555    "Evil Receiver"
1556  };
1557  static int missedreasonslen = 5;
1558 
1559  va_list ap;
1560  fu16_t chan, nummissed, reason;
1561  aim_userinfo_t *userinfo;
1562 
1563  va_start(ap, fr);
1564  chan = (fu16_t)va_arg(ap, unsigned int);
1565  userinfo = va_arg(ap, aim_userinfo_t *);
1566  nummissed = (fu16_t)va_arg(ap, unsigned int);
1567  reason = (fu16_t)va_arg(ap, unsigned int);
1568  va_end(ap);
1569 
1570  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");
1571 
1572  return 1;
1573}
1574
1575/*
1576 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1577 */
1578static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1579{
1580  va_list ap;
1581  fu16_t type;
1582  const char *sn = NULL;
1583 
1584  va_start(ap, fr);
1585  type = (fu16_t)va_arg(ap, unsigned int);
1586  sn = va_arg(ap, const char *);
1587  va_end(ap);
1588 
1589  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1590 
1591  return 1;
1592}
1593
1594static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1595{
1596  static const char *codes[5] = {
1597    "invalid",
1598    "change",
1599    "warning",
1600    "limit",
1601    "limit cleared"
1602  };
1603  va_list ap;
1604  fu16_t code, rateclass;
1605  fu32_t windowsize, clear, alert, limit, disconnect;
1606  fu32_t currentavg, maxavg;
1607 
1608  va_start(ap, fr); 
1609 
1610  /* See code explanations below */
1611  code = (fu16_t)va_arg(ap, unsigned int);
1612 
1613  /*
1614   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1615   */
1616  rateclass = (fu16_t)va_arg(ap, unsigned int);
1617 
1618  /*
1619   * Not sure what this is exactly.  I think its the temporal
1620   * relation factor (ie, how to make the rest of the numbers
1621   * make sense in the real world).
1622   */
1623  windowsize = va_arg(ap, fu32_t);
1624 
1625  /* Explained below */
1626  clear = va_arg(ap, fu32_t);
1627  alert = va_arg(ap, fu32_t);
1628  limit = va_arg(ap, fu32_t);
1629  disconnect = va_arg(ap, fu32_t);
1630  currentavg = va_arg(ap, fu32_t);
1631  maxavg = va_arg(ap, fu32_t);
1632 
1633  va_end(ap);
1634 
1635  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)",
1636                        (code < 5)?codes[code]:"invalid",
1637                        rateclass,
1638                        currentavg, maxavg,
1639                        alert, clear,
1640                        limit, disconnect,
1641                        windowsize);
1642  return 1;
1643}
1644
1645static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1646{
1647  va_list ap;
1648  fu16_t newevil;
1649  aim_userinfo_t *userinfo;
1650 
1651  va_start(ap, fr);
1652  newevil = (fu16_t)va_arg(ap, unsigned int);
1653  userinfo = va_arg(ap, aim_userinfo_t *);
1654  va_end(ap);
1655 
1656  /*
1657   * Evil Notifications that are lacking userinfo->sn are anon-warns
1658   * if they are an evil increases, but are not warnings at all if its
1659   * a decrease (its the natural backoff happening).
1660   *
1661   * newevil is passed as an int representing the new evil value times
1662   * ten.
1663   */
1664  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1665 
1666  return 1;
1667}
1668
1669static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1670{
1671  va_list ap;
1672  const char *address, *SNs;
1673  int num, i;
1674  owl_list list;
1675 
1676  va_start(ap, fr);
1677  address = va_arg(ap, const char *);
1678  num = va_arg(ap, int);
1679  SNs = va_arg(ap, const char *);
1680  va_end(ap);
1681
1682  owl_list_create(&list);
1683 
1684  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1685  for (i=0; i<num; i++) {
1686    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1687    owl_list_append_element(&list, (void *)&SNs[i*(MAXSNLEN+1)]);
1688  }
1689  owl_function_aimsearch_results(address, &list);
1690  owl_list_free_simple(&list);
1691  return(1);
1692}
1693
1694static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1695{
1696  va_list ap;
1697  const char *address;
1698 
1699  va_start(ap, fr);
1700  address = va_arg(ap, const char *);
1701  va_end(ap);
1702
1703  owl_function_error("No results searching for %s", address);
1704  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1705 
1706  return(1);
1707}
1708
1709static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1710{
1711  va_list ap;
1712  const char *msg, *url;
1713  fu16_t width, height, delay;
1714 
1715  va_start(ap, fr);
1716  msg = va_arg(ap, const char *);
1717  url = va_arg(ap, const char *);
1718  width = va_arg(ap, unsigned int);
1719  height = va_arg(ap, unsigned int);
1720  delay = va_arg(ap, unsigned int);
1721  va_end(ap);
1722 
1723  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1724 
1725  return 1;
1726}
1727
1728static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1729{
1730  aim_sendpauseack(sess, fr->conn);
1731  return 1;
1732}
1733
1734static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1735{
1736  va_list ap;
1737  aim_conn_t *bosconn;
1738  const char *bosip;
1739  fu8_t *cookie;
1740 
1741  va_start(ap, fr);
1742  bosip = va_arg(ap, const char *);
1743  cookie = va_arg(ap, fu8_t *);
1744  va_end(ap);
1745 
1746  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1747  aim_conn_kill(sess, &fr->conn);
1748 
1749  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1750    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1751    return 1;
1752  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1753    owl_function_debugmsg("migrate: could not connect to BOS");
1754    aim_conn_kill(sess, &bosconn);
1755    return 1;
1756  }
1757 
1758  /* Login will happen all over again. */
1759  addcb_bos(sess, bosconn);
1760  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1761  return 1;
1762}
1763
1764static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1765{
1766  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1767  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1768  aim_ssi_reqdata(sess);
1769 
1770  return(1);
1771}
1772
1773static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1774{
1775  va_list ap;
1776  fu8_t fmtver;
1777  fu16_t itemcount;
1778  fu32_t stamp;
1779  struct aim_ssi_item *list;
1780  /*
1781  struct aim_ssi_item *curitem;
1782  struct aim_ssi_item *l;
1783  */
1784 
1785  va_start(ap, fr);
1786  fmtver = va_arg(ap, unsigned int);
1787  itemcount = va_arg(ap, unsigned int);
1788  stamp = va_arg(ap, fu32_t);
1789  list = va_arg(ap, struct aim_ssi_item *);
1790  va_end(ap);
1791 
1792  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %u)", fmtver, itemcount, stamp);
1793  /*
1794  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1795    for (l = list; l; l = l->next) {
1796      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1797    }
1798  }
1799  */
1800  aim_ssi_enable(sess);
1801 
1802  return 1;
1803}
1804
1805static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1806{
1807  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1808  /* aim_ssi_enable(sess, fr->conn); */
1809  aim_ssi_enable(sess);
1810  return 1;
1811}
1812
1813static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1814{
1815  va_list ap;
1816  struct aim_icq_offlinemsg *msg;
1817 
1818  va_start(ap, fr);
1819  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1820  va_end(ap);
1821 
1822  if (msg->type == 0x0001) {
1823    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);
1824  } else {
1825    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1826  }
1827  return 1;
1828}
1829
1830static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1831{
1832  /* Tell the server to delete them. */
1833  owl_function_debugmsg("offlinemsg done: ");
1834  aim_icq_ackofflinemsgs(sess);
1835  return 1;
1836}
1837
1838
1839/******************** chat.c **************************/
1840
1841static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1842{
1843  va_list ap;
1844  aim_userinfo_t *userinfo;
1845  int count;
1846  /* int i; */
1847 
1848  va_start(ap, fr);
1849  count = va_arg(ap, int);
1850  userinfo = va_arg(ap, aim_userinfo_t *);
1851  va_end(ap);
1852
1853  owl_function_debugmsg("In faimtest_chat_join");
1854  /*
1855  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1856  for (i = 0; i < count; i++)
1857    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1858  */
1859  return 1;
1860}
1861
1862static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1863{
1864  aim_userinfo_t *userinfo;
1865  va_list ap;
1866  int count;
1867  /* int i; */
1868
1869 
1870  va_start(ap, fr);
1871  count = va_arg(ap, int);
1872  userinfo = va_arg(ap, aim_userinfo_t *);
1873  va_end(ap);
1874 
1875  /*
1876    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1877   
1878    for (i = 0; i < count; i++)
1879    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1880  */
1881  return 1;
1882}
1883
1884static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1885{
1886  va_list ap;
1887  aim_userinfo_t *userinfo;
1888  struct aim_chat_roominfo *roominfo;
1889  const char *roomname;
1890  int usercount;
1891  const char *roomdesc;
1892  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1893  fu32_t creationtime;
1894  const char *croomname;
1895  /* int i; */
1896 
1897  croomname = aim_chat_getname(fr->conn);
1898 
1899  va_start(ap, fr);
1900  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1901  roomname = va_arg(ap, const char *);
1902  usercount = va_arg(ap, int);
1903  userinfo = va_arg(ap, aim_userinfo_t *);
1904  roomdesc = va_arg(ap, const char *);
1905  flags = (fu16_t)va_arg(ap, unsigned int);
1906  creationtime = va_arg(ap, fu32_t);
1907  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1908  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1909  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1910  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1911  va_end(ap);
1912
1913  owl_function_debugmsg("In faimtest_chat_infoupdate");
1914  /*
1915  printf("chat: %s:  info update:\n", croomname);
1916  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1917  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1918  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1919  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1920
1921  for (i = 0; i < usercount; i++)
1922    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1923 
1924  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1925         croomname, flags,
1926         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1927         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1928         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1929         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1930  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1931  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1932  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1933  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1934  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1935  */
1936 
1937  return(1);
1938}
1939
1940static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1941{
1942  va_list ap;
1943  aim_userinfo_t *userinfo;
1944  const char *msg;
1945  char tmpbuf[1152];
1946 
1947  va_start(ap, fr);
1948  userinfo = va_arg(ap, aim_userinfo_t *);     
1949  msg = va_arg(ap, const char *);
1950  va_end(ap);
1951
1952  owl_function_debugmsg("in faimtest_chat_incomingmsg");
1953
1954  /*
1955  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1956  */
1957 
1958  /*
1959   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1960   */
1961  if (strcmp(userinfo->sn, sess->sn) != 0) {
1962    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1963    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1964  }
1965 
1966  return 1;
1967}
1968
1969static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1970{
1971  owl_function_debugmsg("faimtest_conninitdone_chat:");
1972
1973  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1974  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1975  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1976  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1977  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1978 
1979  aim_clientready(sess, fr->conn);
1980 
1981  owl_function_debugmsg("Chat ready");
1982
1983  /*
1984    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
1985    chatcon->id = id;
1986    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
1987  */
1988  return(1);
1989}
1990
1991void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1992{
1993  aim_conn_t *tstconn;
1994
1995  owl_function_debugmsg("in faimtest_chatnav_redirect");
1996 
1997  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1998  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1999    /* printf("unable to connect to chat(nav) server\n"); */
2000    if (tstconn)
2001      aim_conn_kill(sess, &tstconn);
2002    return;
2003  }
2004 
2005  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2006  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2007  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2008  /* printf("chatnav: connected\n"); */
2009  return;
2010}
2011
2012/* XXX this needs instance too */
2013void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2014{
2015  aim_conn_t *tstconn;
2016
2017  owl_function_debugmsg("in chat_redirect");
2018 
2019  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2020  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2021    /* printf("unable to connect to chat server\n"); */
2022    if (tstconn) aim_conn_kill(sess, &tstconn);
2023    return; 
2024  }             
2025  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2026 
2027  /*
2028   * We must do this to attach the stored name to the connection!
2029   */
2030  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2031  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2032  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2033  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2034  return;       
2035}
2036
2037void owl_process_aim(void)
2038{
2039  if (owl_global_is_doaimevents(&g)) {
2040    owl_aim_process_events();
2041  }
2042}
Note: See TracBrowser for help on using the repository browser.