source: aim.c @ 8c46404

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 8c46404 was 8c46404, checked in by James M. Kretchmar <kretch@mit.edu>, 17 years ago
Massive changes to AIM. Feel the burn.
  • 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  struct aim_ssi_item *curitem;
1885  struct aim_ssi_item *l;
1886 
1887  va_start(ap, fr);
1888  fmtver = va_arg(ap, unsigned int);
1889  itemcount = va_arg(ap, unsigned int);
1890  stamp = va_arg(ap, fu32_t);
1891  list = va_arg(ap, struct aim_ssi_item *);
1892  va_end(ap);
1893 
1894  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %ld)", fmtver, itemcount, stamp);
1895  /*
1896  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1897    for (l = list; l; l = l->next) {
1898      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1899    }
1900  }
1901  */
1902  aim_ssi_enable(sess);
1903 
1904  return 1;
1905}
1906
1907static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1908{
1909  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1910  /* aim_ssi_enable(sess, fr->conn); */
1911  aim_ssi_enable(sess);
1912  return 1;
1913}
1914
1915static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1916{
1917  va_list ap;
1918  struct aim_icq_offlinemsg *msg;
1919 
1920  va_start(ap, fr);
1921  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1922  va_end(ap);
1923 
1924  if (msg->type == 0x0001) {
1925    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);
1926  } else {
1927    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1928  }
1929  return 1;
1930}
1931
1932static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1933{
1934  /* Tell the server to delete them. */
1935  owl_function_debugmsg("offlinemsg done: ");
1936  aim_icq_ackofflinemsgs(sess);
1937  return 1;
1938}
1939
1940
1941/******************** chat.c **************************/
1942
1943static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1944{
1945  va_list ap;
1946  aim_userinfo_t *userinfo;
1947  int count;
1948  /* int i; */
1949 
1950  va_start(ap, fr);
1951  count = va_arg(ap, int);
1952  userinfo = va_arg(ap, aim_userinfo_t *);
1953  va_end(ap);
1954
1955  owl_function_debugmsg("In faimtest_chat_join");
1956  /*
1957  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1958  for (i = 0; i < count; i++)
1959    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1960  */
1961  return 1;
1962}
1963
1964static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1965{
1966  aim_userinfo_t *userinfo;
1967  va_list ap;
1968  int count;
1969  /* int i; */
1970
1971 
1972  va_start(ap, fr);
1973  count = va_arg(ap, int);
1974  userinfo = va_arg(ap, aim_userinfo_t *);
1975  va_end(ap);
1976 
1977  /*
1978    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1979   
1980    for (i = 0; i < count; i++)
1981    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1982  */
1983  return 1;
1984}
1985
1986static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1987{
1988  va_list ap;
1989  aim_userinfo_t *userinfo;
1990  struct aim_chat_roominfo *roominfo;
1991  char *roomname;
1992  int usercount;
1993  char *roomdesc;
1994  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1995  fu32_t creationtime;
1996  const char *croomname;
1997  /* int i; */
1998 
1999  croomname = aim_chat_getname(fr->conn);
2000 
2001  va_start(ap, fr);
2002  roominfo = va_arg(ap, struct aim_chat_roominfo *);
2003  roomname = va_arg(ap, char *);
2004  usercount = va_arg(ap, int);
2005  userinfo = va_arg(ap, aim_userinfo_t *);
2006  roomdesc = va_arg(ap, char *);
2007  flags = (fu16_t)va_arg(ap, unsigned int);
2008  creationtime = va_arg(ap, fu32_t);
2009  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2010  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
2011  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
2012  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
2013  va_end(ap);
2014
2015  owl_function_debugmsg("In faimtest_chat_infoupdate");
2016  /*
2017  printf("chat: %s:  info update:\n", croomname);
2018  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
2019  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
2020  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
2021  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
2022
2023  for (i = 0; i < usercount; i++)
2024    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
2025 
2026  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
2027         croomname, flags,
2028         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2029         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2030         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2031         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2032  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
2033  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
2034  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
2035  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
2036  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
2037  */
2038 
2039  return(1);
2040}
2041
2042static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
2043{
2044  va_list ap;
2045  aim_userinfo_t *userinfo;
2046  char *msg;
2047  char tmpbuf[1152];
2048 
2049  va_start(ap, fr);
2050  userinfo = va_arg(ap, aim_userinfo_t *);     
2051  msg = va_arg(ap, char *);
2052  va_end(ap);
2053
2054  owl_function_debugmsg("in faimtest_chat_incomingmsg");
2055
2056  /*
2057  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
2058  */
2059 
2060  /*
2061   * Do an echo for testing purposes.  But not for ourselves ("oops!")
2062   */
2063  if (strcmp(userinfo->sn, sess->sn) != 0) {
2064    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
2065    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
2066  }
2067 
2068  return 1;
2069}
2070
2071static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
2072{
2073  fu16_t type;
2074  va_list ap;
2075 
2076  va_start(ap, fr);
2077  type = (fu16_t)va_arg(ap, unsigned int);
2078
2079  owl_function_debugmsg("in faimtest_chatnav_info");
2080 
2081  if (type == 0x0002) {
2082    int maxrooms;
2083    struct aim_chat_exchangeinfo *exchanges;
2084    int exchangecount;
2085    /* int i; */
2086   
2087    maxrooms = va_arg(ap, int);
2088    exchangecount = va_arg(ap, int);
2089    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2090    va_end(ap);
2091
2092    /*
2093    printf("chat info: Chat Rights:\n");
2094    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2095    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
2096    for (i = 0; i < exchangecount; i++) {
2097      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
2098             exchanges[i].number,
2099             exchanges[i].name,
2100             exchanges[i].charset1,
2101             exchanges[i].lang1,
2102             exchanges[i].flags,
2103             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2104             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2105             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2106             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2107    }
2108    */
2109  } else if (type == 0x0008) {
2110    char *fqcn, *name, *ck;
2111    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2112    fu8_t createperms;
2113    fu32_t createtime;
2114   
2115    fqcn = va_arg(ap, char *);
2116    instance = (fu16_t)va_arg(ap, unsigned int);
2117    exchange = (fu16_t)va_arg(ap, unsigned int);
2118    flags = (fu16_t)va_arg(ap, unsigned int);
2119    createtime = va_arg(ap, fu32_t);
2120    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2121    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
2122    createperms = (fu8_t)va_arg(ap, unsigned int);
2123    unknown = (fu16_t)va_arg(ap, unsigned int);
2124    name = va_arg(ap, char *);
2125    ck = va_arg(ap, char *);
2126    va_end(ap);
2127   
2128    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
2129   
2130  } else {
2131    va_end(ap);
2132    /* printf("chatnav info: unknown type (%04x)\n", type); */
2133  }
2134 
2135  return 1;
2136}
2137
2138static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
2139{
2140
2141  owl_function_debugmsg("in faimtest_conninitdone_chat");
2142 
2143  aim_clientready(sess, fr->conn);
2144 
2145  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
2146    /* printf("chatnav ready\n"); */
2147    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
2148    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
2149    aim_chatnav_reqrights(sess, fr->conn);
2150  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
2151    /* printf("chat ready\n"); */
2152    owl_function_debugmsg("Chat ready");
2153    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
2154    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
2155    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
2156    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
2157    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
2158  }
2159  return 1;
2160}
2161
2162void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2163{
2164  aim_conn_t *tstconn;
2165
2166  owl_function_debugmsg("in faimtest_chatnav_redirect");
2167 
2168  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
2169  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2170    /* printf("unable to connect to chat(nav) server\n"); */
2171    if (tstconn)
2172      aim_conn_kill(sess, &tstconn);
2173    return;
2174  }
2175 
2176  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2177  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2178  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2179  /* printf("chatnav: connected\n"); */
2180  return;
2181}
2182
2183/* XXX this needs instance too */
2184void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2185{
2186  aim_conn_t *tstconn;
2187
2188  owl_function_debugmsg("in chat_redirect");
2189 
2190  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2191  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2192    /* printf("unable to connect to chat server\n"); */
2193    if (tstconn) aim_conn_kill(sess, &tstconn);
2194    return; 
2195  }             
2196  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2197 
2198  /*
2199   * We must do this to attach the stored name to the connection!
2200   */
2201  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2202  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2203  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2204  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2205  return;       
2206}
2207
2208
2209/**********************************************************************************/
2210
2211
2212static int faimtest_ssi_rerequestdata(aim_session_t *sess, aim_frame_t *fr, ...)
2213{
2214  aim_ssi_reqdata(sess);
2215  return(0);
2216}
2217
2218static int faimtest_ssi_parseerr(aim_session_t *sess, aim_frame_t *fr, ...)
2219{
2220  /* GaimConnection *gc = sess->aux_data; */
2221  /*    OscarData *od = gc->proto_data; */
2222  va_list ap;
2223  fu16_t reason;
2224
2225  va_start(ap, fr);
2226  reason = (fu16_t)va_arg(ap, unsigned int);
2227  va_end(ap);
2228
2229  owl_function_debugmsg("faimtest_ssi_parseerr: ssi: SNAC error %hu", reason);
2230
2231  if (reason == 0x0005) {
2232    owl_function_error("faimtest_ssi_parseerr: unable to retrieve buddy list");
2233  }
2234
2235  /* Activate SSI */
2236  /* Sending the enable causes other people to be able to see you, and you to see them */
2237  /* Make sure your privacy setting/invisibility is set how you want it before this! */
2238  owl_function_debugmsg("faimtest_ssi_parseerr: ssi: activating server-stored buddy list");
2239  aim_ssi_enable(sess);
2240 
2241  return(1);
2242}
2243
2244static int faimtest_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...)
2245{
2246  /* GaimConnection *gc = sess->aux_data; */
2247  /* OscarData *od = (OscarData *)gc->proto_data; */
2248  int numtypes, i;
2249  fu16_t *maxitems;
2250  va_list ap;
2251
2252  va_start(ap, fr);
2253  numtypes = va_arg(ap, int);
2254  maxitems = va_arg(ap, fu16_t *);
2255  va_end(ap);
2256
2257  owl_function_debugmsg("faimtest_ssi_parserights: ");
2258  for (i=0; i<numtypes; i++) {
2259    owl_function_debugmsg(" max type 0x%04x=%hd,", i, maxitems[i]);
2260  }
2261
2262  /*
2263  if (numtypes >= 0) od->rights.maxbuddies = maxitems[0];
2264  if (numtypes >= 1) od->rights.maxgroups = maxitems[1];
2265  if (numtypes >= 2) od->rights.maxpermits = maxitems[2];
2266  if (numtypes >= 3) od->rights.maxdenies = maxitems[3];
2267  */
2268 
2269  return(1);
2270}
2271
2272#if 0
2273static int faimtest_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...)
2274{
2275  /* GaimConnection *gc = sess->aux_data; */
2276  /* GaimAccount *account = gaim_connection_get_account(gc); */
2277  /* OscarData *od = (OscarData *)gc->proto_data; */
2278  struct aim_ssi_item *curitem;
2279  int tmp;
2280  int export = FALSE;
2281  /* XXX - use these?
2282     va_list ap;
2283     
2284     va_start(ap, fr);
2285     fmtver = (fu16_t)va_arg(ap, int);
2286     numitems = (fu16_t)va_arg(ap, int);
2287     items = va_arg(ap, struct aim_ssi_item);
2288     timestamp = va_arg(ap, fu32_t);
2289     va_end(ap); */
2290 
2291  owl_function_debugmsg("faimtest_ssi_parselist: syncing local list and server list");
2292
2293  /* Clean the buddy list */
2294  aim_ssi_cleanlist(sess);
2295
2296  /* Add from server list to local list */
2297  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
2298    if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
2299      switch (curitem->type) {
2300      case 0x0000: { /* Buddy */
2301        if (curitem->name) {
2302          char *gname = aim_ssi_itemlist_findparentname(sess->ssi.local, curitem->name);
2303          char *gname_utf8 = gname ? gaim_utf8_try_convert(gname) : NULL;
2304          char *alias = aim_ssi_getalias(sess->ssi.local, gname, curitem->name);
2305          char *alias_utf8 = alias ? gaim_utf8_try_convert(alias) : NULL;
2306          GaimBuddy *buddy = gaim_find_buddy(gc->account, curitem->name);
2307          /* Should gname be freed here? -- elb */
2308          /* Not with the current code, but that might be cleaner -- med */
2309          free(alias);
2310          if (buddy) {
2311            /* Get server stored alias */
2312            if (alias_utf8) {
2313              g_free(buddy->alias);
2314              buddy->alias = g_strdup(alias_utf8);
2315            }
2316          } else {
2317            GaimGroup *g;
2318            buddy = gaim_buddy_new(gc->account, curitem->name, alias_utf8);
2319           
2320            if (!(g = gaim_find_group(gname_utf8 ? gname_utf8 : _("Orphans")))) {
2321              g = gaim_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
2322              gaim_blist_add_group(g, NULL);
2323            }
2324           
2325            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2326                       "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname_utf8 ? gname_utf8 : _("Orphans"));
2327            gaim_blist_add_buddy(buddy, NULL, g, NULL);
2328            export = TRUE;
2329          }
2330          g_free(gname_utf8);
2331          g_free(alias_utf8);
2332        }
2333      } break;
2334     
2335      case 0x0001: { /* Group */
2336        /* Shouldn't add empty groups */
2337      } break;
2338     
2339      case 0x0002: { /* Permit buddy */
2340        if (curitem->name) {
2341          /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
2342          GSList *list;
2343          for (list=account->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
2344          if (!list) {
2345            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2346                       "ssi: adding permit buddy %s to local list\n", curitem->name);
2347            gaim_privacy_permit_add(account, curitem->name, TRUE);
2348            export = TRUE;
2349          }
2350        }
2351      } break;
2352     
2353      case 0x0003: { /* Deny buddy */
2354        if (curitem->name) {
2355          GSList *list;
2356          for (list=account->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
2357          if (!list) {
2358            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2359                       "ssi: adding deny buddy %s to local list\n", curitem->name);
2360            gaim_privacy_deny_add(account, curitem->name, TRUE);
2361            export = TRUE;
2362          }
2363        }
2364      } break;
2365     
2366      case 0x0004: { /* Permit/deny setting */
2367        if (curitem->data) {
2368          fu8_t permdeny;
2369          if ((permdeny = aim_ssi_getpermdeny(sess->ssi.local)) && (permdeny != account->perm_deny)) {
2370            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2371                       "ssi: changing permdeny from %d to %hhu\n", account->perm_deny, permdeny);
2372            account->perm_deny = permdeny;
2373            if (od->icq && account->perm_deny == 0x03) {
2374              serv_set_away(gc, "Invisible", "");
2375            }
2376            export = TRUE;
2377          }
2378        }
2379      } break;
2380     
2381      case 0x0005: { /* Presence setting */
2382        /* We don't want to change Gaim's setting because it applies to all accounts */
2383      } break;
2384      } /* End of switch on curitem->type */
2385  } /* End of for loop */
2386 
2387  /* If changes were made, then flush buddy list to file */
2388  if (export)
2389    gaim_blist_save();
2390 
2391  { /* Add from local list to server list */
2392    GaimBlistNode *gnode, *cnode, *bnode;
2393    GaimGroup *group;
2394    GaimBuddy *buddy;
2395    GaimBuddyList *blist;
2396    GSList *cur;
2397   
2398    /* Buddies */
2399    if ((blist = gaim_get_blist()))
2400      for (gnode = blist->root; gnode; gnode = gnode->next) {
2401        if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
2402          continue;
2403        group = (GaimGroup *)gnode;
2404        for (cnode = gnode->child; cnode; cnode = cnode->next) {
2405          if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
2406            continue;
2407          for (bnode = cnode->child; bnode; bnode = bnode->next) {
2408            if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
2409              continue;
2410            buddy = (GaimBuddy *)bnode;
2411            if (buddy->account == gc->account) {
2412              const char *servernick = gaim_buddy_get_setting(buddy, "servernick");
2413              if (servernick)
2414                serv_got_alias(gc, buddy->name, servernick);
2415             
2416              if (aim_ssi_itemlist_exists(sess->ssi.local, buddy->name)) {
2417                /* Store local alias on server */
2418                char *alias = aim_ssi_getalias(sess->ssi.local, group->name, buddy->name);
2419                if (!alias && buddy->alias && strlen(buddy->alias))
2420                  aim_ssi_aliasbuddy(sess, group->name, buddy->name, buddy->alias);
2421                free(alias);
2422              } else {
2423                gaim_debug(GAIM_DEBUG_INFO, "oscar",
2424                           "ssi: adding buddy %s from local list to server list\n", buddy->name);
2425                aim_ssi_addbuddy(sess, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
2426              }
2427            }
2428          }
2429        }
2430      }
2431   
2432    /* Permit list */
2433    if (gc->account->permit) {
2434      for (cur=gc->account->permit; cur; cur=cur->next)
2435        if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
2436          gaim_debug(GAIM_DEBUG_INFO, "oscar",
2437                     "ssi: adding permit %s from local list to server list\n", (char *)cur->data);
2438          aim_ssi_addpermit(sess, cur->data);
2439        }
2440    }
2441   
2442    /* Deny list */
2443    if (gc->account->deny) {
2444      for (cur=gc->account->deny; cur; cur=cur->next)
2445        if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
2446          gaim_debug(GAIM_DEBUG_INFO, "oscar",
2447                     "ssi: adding deny %s from local list to server list\n", (char *)cur->data);
2448          aim_ssi_adddeny(sess, cur->data);
2449        }
2450    }
2451    /* Presence settings (idle time visibility) */
2452    if ((tmp = aim_ssi_getpresence(sess->ssi.local)) != 0xFFFFFFFF)
2453      if (!(tmp & 0x400))
2454        aim_ssi_setpresence(sess, tmp | 0x400);
2455  } /* end adding buddies from local list to server list */
2456 
2457  /* Set our ICQ status */
2458  if  (od->icq && !gc->away) {
2459    aim_setextstatus(sess, AIM_ICQ_STATE_NORMAL);
2460  }
2461 
2462  /* Activate SSI */
2463  /* Sending the enable causes other people to be able to see you, and you to see them */
2464  /* Make sure your privacy setting/invisibility is set how you want it before this! */
2465  gaim_debug(GAIM_DEBUG_INFO, "oscar", "ssi: activating server-stored buddy list\n");
2466  aim_ssi_enable(sess);
2467 
2468  return 1;
2469}
2470
2471static int gaim_ssi_parseack(aim_session_t *sess, aim_frame_t *fr, ...)
2472{
2473  GaimConnection *gc = sess->aux_data;
2474  va_list ap;
2475  struct aim_ssi_tmp *retval;
2476 
2477  va_start(ap, fr);
2478  retval = va_arg(ap, struct aim_ssi_tmp *);
2479  va_end(ap);
2480 
2481  while (retval) {
2482    gaim_debug(GAIM_DEBUG_MISC, "oscar",
2483               "ssi: status is 0x%04hx for a 0x%04hx action with name %s\n", retval->ack,  retval->action, retval->item ? (retval->item->name ? retval->item->name : "no name") : "no item");
2484   
2485    if (retval->ack != 0xffff)
2486      switch (retval->ack) {
2487      case 0x0000: { /* added successfully */
2488      } break;
2489     
2490      case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */
2491        gchar *buf;
2492        buf = g_strdup_printf(_("Could not add the buddy %s because you have too many buddies in your buddy list.  Please remove one and try again."), (retval->name ? retval->name : _("(no name)")));
2493        gaim_notify_error(gc, NULL, _("Unable To Add"), buf);
2494        g_free(buf);
2495      }
2496       
2497      case 0x000e: { /* buddy requires authorization */
2498        if ((retval->action == AIM_CB_SSI_ADD) && (retval->name))
2499          gaim_auth_sendrequest(gc, retval->name);
2500      } break;
2501     
2502      default: { /* La la la */
2503        gchar *buf;
2504        gaim_debug(GAIM_DEBUG_ERROR, "oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
2505        buf = g_strdup_printf(_("Could not add the buddy %s for an unknown reason.  The most common reason for this is that you have the maximum number of allowed buddies in your buddy list."), (retval->name ? retval->name : _("(no name)")));
2506        gaim_notify_error(gc, NULL, _("Unable To Add"), buf);
2507        g_free(buf);
2508        /* XXX - Should remove buddy from local list */
2509      } break;
2510      }
2511   
2512    retval = retval->next;
2513  }
2514 
2515  return 1;
2516}
2517
2518static int gaim_ssi_authgiven(aim_session_t *sess, aim_frame_t *fr, ...)
2519{
2520  GaimConnection *gc = sess->aux_data;
2521  va_list ap;
2522  char *sn, *msg;
2523  gchar *dialog_msg, *nombre;
2524  struct name_data *data;
2525  GaimBuddy *buddy;
2526 
2527  va_start(ap, fr);
2528  sn = va_arg(ap, char *);
2529  msg = va_arg(ap, char *);
2530  va_end(ap);
2531 
2532  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2533             "ssi: %s has given you permission to add him to your buddy list\n", sn);
2534 
2535  buddy = gaim_find_buddy(gc->account, sn);
2536  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2537    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2538  else
2539    nombre = g_strdup(sn);
2540 
2541  dialog_msg = g_strdup_printf(_("The user %s has given you permission to add you to their buddy list.  Do you want to add them?"), nombre);
2542  data = g_new(struct name_data, 1);
2543  data->gc = gc;
2544  data->name = g_strdup(sn);
2545  data->nick = NULL;
2546 
2547  gaim_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
2548                      0, data,
2549                      G_CALLBACK(gaim_icq_buddyadd),
2550                      G_CALLBACK(oscar_free_name_data));
2551 
2552  g_free(dialog_msg);
2553  g_free(nombre);
2554 
2555  return 1;
2556}
2557
2558static int gaim_ssi_authrequest(aim_session_t *sess, aim_frame_t *fr, ...)
2559{
2560  GaimConnection *gc = sess->aux_data;
2561  va_list ap;
2562  char *sn, *msg;
2563  gchar *dialog_msg, *nombre;
2564  struct name_data *data;
2565  GaimBuddy *buddy;
2566 
2567  va_start(ap, fr);
2568  sn = va_arg(ap, char *);
2569  msg = va_arg(ap, char *);
2570  va_end(ap);
2571 
2572  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2573             "ssi: received authorization request from %s\n", sn);
2574 
2575  buddy = gaim_find_buddy(gc->account, sn);
2576  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2577    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2578  else
2579    nombre = g_strdup(sn);
2580 
2581  dialog_msg = g_strdup_printf(_("The user %s wants to add you to their buddy list for the following reason:\n%s"), nombre, msg ? msg : _("No reason given."));
2582  data = g_new(struct name_data, 1);
2583  data->gc = gc;
2584  data->name = g_strdup(sn);
2585  data->nick = NULL;
2586 
2587  gaim_request_action(gc, NULL, _("Authorization Request"), dialog_msg,
2588                      0, data, 2,
2589                      _("Authorize"), G_CALLBACK(gaim_auth_grant),
2590                      _("Deny"), G_CALLBACK(gaim_auth_dontgrant_msgprompt));
2591 
2592  g_free(dialog_msg);
2593  g_free(nombre);
2594 
2595  return 1;
2596}
2597
2598static int gaim_ssi_authreply(aim_session_t *sess, aim_frame_t *fr, ...)
2599{
2600  GaimConnection *gc = sess->aux_data;
2601  va_list ap;
2602  char *sn, *msg;
2603  gchar *dialog_msg, *nombre;
2604  fu8_t reply;
2605  GaimBuddy *buddy;
2606 
2607  va_start(ap, fr);
2608  sn = va_arg(ap, char *);
2609  reply = (fu8_t)va_arg(ap, int);
2610  msg = va_arg(ap, char *);
2611  va_end(ap);
2612 
2613  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2614             "ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", sn, reply);
2615 
2616  buddy = gaim_find_buddy(gc->account, sn);
2617  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2618    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2619  else
2620    nombre = g_strdup(sn);
2621 
2622  if (reply) {
2623    /* Granted */
2624    dialog_msg = g_strdup_printf(_("The user %s has granted your request to add them to your buddy list."), nombre);
2625    gaim_notify_info(gc, NULL, _("Authorization Granted"), dialog_msg);
2626  } else {
2627    /* Denied */
2628    dialog_msg = g_strdup_printf(_("The user %s has denied your request to add them to your buddy list for the following reason:\n%s"), nombre, msg ? msg : _("No reason given."));
2629    gaim_notify_info(gc, NULL, _("Authorization Denied"), dialog_msg);
2630  }
2631  g_free(dialog_msg);
2632  g_free(nombre);
2633 
2634  return 1;
2635}
2636
2637static int gaim_ssi_gotadded(aim_session_t *sess, aim_frame_t *fr, ...)
2638{
2639  GaimConnection *gc = sess->aux_data;
2640  va_list ap;
2641  char *sn;
2642  GaimBuddy *buddy;
2643 
2644  va_start(ap, fr);
2645  sn = va_arg(ap, char *);
2646  va_end(ap);
2647 
2648  buddy = gaim_find_buddy(gc->account, sn);
2649  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2650             "ssi: %s added you to their buddy list\n", sn);
2651  gaim_account_notify_added(gc->account, NULL, sn, (buddy ? gaim_get_buddy_alias_only(buddy) : NULL), NULL);
2652 
2653  return 1;
2654}
2655#endif
Note: See TracBrowser for help on using the repository browser.