source: aim.c @ e7bcd1b

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