source: aim.c @ 9854278

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