source: aim.c @ 7967433

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