source: aim.c @ 4708281

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