source: aim.c @ 6e3980e

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