source: aim.c @ 2674412

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