source: aim.c @ 50dd3a0

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 50dd3a0 was db0ac7e, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 17 years ago
Merged revisions 983-1032 via svnmerge from file:///afs/sipb.mit.edu/project/barnowl/src/svn/trunk ........ r985 | nelhage | 2008-03-11 12:38:20 -0400 (Tue, 11 Mar 2008) | 2 lines Generate less ugly error spew if a module fails to load ........ r986 | geofft | 2008-03-13 15:56:20 -0400 (Thu, 13 Mar 2008) | 1 line Added :webzephyr command with keybinding W. ........ r987 | asedeno | 2008-03-18 23:57:24 -0400 (Tue, 18 Mar 2008) | 2 lines Fix a race condition in which zephyrs received during init are not noticed until the next zephyr after entering the mainloop. ........ r988 | geofft | 2008-03-19 15:46:43 -0400 (Wed, 19 Mar 2008) | 6 lines IRC: explicitly include the network (-a $alias) in reply commands. This may be unnecessary because :irc-msg looks at getcurmsg() if it cannot automatically determine the network. ........ r989 | geofft | 2008-03-21 14:47:51 -0400 (Fri, 21 Mar 2008) | 1 line syntax error. ........ r990 | nelhage | 2008-03-26 02:24:26 -0400 (Wed, 26 Mar 2008) | 2 lines Fix sending jabbers to JIDs beginning with `+' ........ r994 | nelhage | 2008-03-29 17:02:05 -0400 (Sat, 29 Mar 2008) | 3 lines Compile zcrypt.c with -w so I don't get all these warnings in my compile output whenever I change any headers ........ r998 | geofft | 2008-03-31 01:59:47 -0400 (Mon, 31 Mar 2008) | 1 line Implement /me for outgoing IRC messages ........ r999 | geofft | 2008-03-31 09:58:56 -0400 (Mon, 31 Mar 2008) | 1 line I think this fixes the resizing bug. ........ r1000 | nelhage | 2008-03-31 11:29:29 -0400 (Mon, 31 Mar 2008) | 2 lines Make `svkversion' handle exported trees better ........ r1001 | nelhage | 2008-03-31 11:52:39 -0400 (Mon, 31 Mar 2008) | 2 lines Add a makefile rule to support emacs flymake-mode ........ r1015 | nelhage | 2008-04-04 14:58:45 -0400 (Fri, 04 Apr 2008) | 3 lines Bind the combinations the iPhone sends for arrow keys [probably other terminals, too] ........ r1018 | shadow | 2008-04-08 13:57:49 -0400 (Tue, 08 Apr 2008) | 2 lines avoid null pointer dereference if msg is NULL (or a 0 length is claimed) ........ r1019 | nelhage | 2008-04-09 18:08:26 -0400 (Wed, 09 Apr 2008) | 2 lines Fix some stupid typos ........ r1020 | chmrr | 2008-04-09 18:16:02 -0400 (Wed, 09 Apr 2008) | 3 lines r29300@kohr-ah: chmrr | 2008-04-09 18:14:37 -0400 * It's apparently a popular typo ........ r1022 | asedeno | 2008-04-16 17:05:36 -0400 (Wed, 16 Apr 2008) | 2 lines Jabber reply bugfix. Reported by several people, resolved by arolfe. ........ r1023 | nelhage | 2008-04-28 23:33:03 -0400 (Mon, 28 Apr 2008) | 3 lines Initialized merge tracking via "svnmerge" with revisions "735" from svn+ssh://lunatique.mit.edu/mit/barnowl/src/svn/branches/barnowl_unicode ........ r1024 | nelhage | 2008-04-28 23:33:12 -0400 (Mon, 28 Apr 2008) | 3 lines Initialized merge tracking via "svnmerge" with revisions "735" from svn+ssh://lunatique.mit.edu/mit/barnowl/src/svn/branches/barnowl_sqlite ........ r1025 | nelhage | 2008-04-29 01:21:12 -0400 (Tue, 29 Apr 2008) | 2 lines Clone owl_perl from the sqlite branch because I'm about to make use of it. ........ r1026 | nelhage | 2008-04-29 01:21:13 -0400 (Tue, 29 Apr 2008) | 4 lines Initial step of moving styles from the current mishmash of different options to a unified object interface. No backwards-compatibility support yet. ........ r1027 | nelhage | 2008-04-29 01:21:15 -0400 (Tue, 29 Apr 2008) | 2 lines Implement back-compat with old-style owl::format_msg() styles ........ r1028 | nelhage | 2008-04-29 01:21:16 -0400 (Tue, 29 Apr 2008) | 2 lines Remove nearly all references to the "basic" style. ........ r1029 | nelhage | 2008-04-29 01:21:17 -0400 (Tue, 29 Apr 2008) | 2 lines Support the `style' command again. Note that it is deprecated. ........ r1031 | nelhage | 2008-04-30 13:29:45 -0400 (Wed, 30 Apr 2008) | 2 lines Refactor default style code somewhat to be more easily extensible ........
  • Property mode set to 100644
File size: 91.6 KB
Line 
1#include <stdio.h>
2#include <stdio.h>
3#include <sys/stat.h>
4#include "owl.h"
5
6/**********************************************************************/
7
8struct owlfaim_priv {
9  char *aimbinarypath;
10  char *screenname;
11  char *password;
12  char *server;
13  char *proxy;
14  char *proxyusername;
15  char *proxypass;
16  char *ohcaptainmycaptain;
17  int connected;
18
19  FILE *listingfile;
20  char *listingpath;
21
22  fu8_t *buddyicon;
23  int buddyiconlen;
24  time_t buddyiconstamp;
25  fu16_t buddyiconsum;
26};
27
28static char *msgerrreasons[] = {
29        "Invalid error",
30        "Invalid SNAC",
31        "Rate to host",
32        "Rate to client",
33        "Not logged on",
34        "Service unavailable",
35        "Service not defined",
36        "Obsolete SNAC",
37        "Not supported by host",
38        "Not supported by client",
39        "Refused by client",
40        "Reply too big",
41        "Responses lost",
42        "Request denied",
43        "Busted SNAC payload",
44        "Insufficient rights",
45        "In local permit/deny",
46        "Too evil (sender)",
47        "Too evil (receiver)",
48        "User temporarily unavailable",
49        "No match",
50        "List overflow",
51        "Request ambiguous",
52        "Queue full",
53        "Not while on AOL",
54};
55static int msgerrreasonslen = 25;
56
57static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
58static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
60int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
61int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
62void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
63static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
64static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
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 = owl_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 = owl_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      owl_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    owl_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 = owl_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 = owl_malloc(len))) {
1020      owl_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      owl_free(filename);
1027      owl_free(buf);
1028      return -1;
1029    }
1030   
1031    owl_free(filename);
1032   
1033    if (fseek(f, offset, SEEK_SET) == -1) {
1034      /* perror("memrequest: fseek"); */
1035      fclose(f);
1036      owl_free(buf);
1037      return -1;
1038    }
1039   
1040    if (fread(buf, len, 1, f) != 1) {
1041      /* perror("memrequest: fread"); */
1042      fclose(f);
1043      owl_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    owl_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 = owl_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      owl_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    if (args->msg && args->msglen)
1455      strncpy(realmsg, args->msg, sizeof(realmsg));
1456  }
1457
1458  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: message from: %s", userinfo->sn?userinfo->sn:"");
1459  /* create a message, and put it on the message queue */
1460  stripmsg=owl_text_htmlstrip(realmsg);
1461  wrapmsg=owl_text_wordwrap(stripmsg, 70);
1462  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1463  m=owl_malloc(sizeof(owl_message));
1464  owl_message_create_aim(m,
1465                         nz_screenname,
1466                         owl_global_get_aim_screenname(&g),
1467                         wrapmsg,
1468                         OWL_MESSAGE_DIRECTION_IN,
1469                         0);
1470  if (args->icbmflags & AIM_IMFLAGS_AWAY) owl_message_set_attribute(m, "isauto", "");
1471  owl_global_messagequeue_addmsg(&g, m);
1472  owl_free(stripmsg);
1473  owl_free(wrapmsg);
1474  owl_free(nz_screenname);
1475
1476  return(1);
1477
1478  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: message: %s\n", realmsg);
1479 
1480  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1481    aim_mpmsg_section_t *sec;
1482    int z;
1483
1484    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart: this message has %d parts\n", args->mpmsg.numparts);
1485   
1486    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1487      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1488        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);
1489      } else {
1490        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);
1491      }
1492    }
1493  }
1494 
1495  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1496    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1497    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);
1498  }
1499
1500  /*
1501  if (realmsg) {
1502    int i = 0;
1503    while (realmsg[i] == '<') {
1504      if (realmsg[i] == '<') {
1505        while (realmsg[i] != '>')
1506          i++;
1507        i++;
1508      }
1509    }
1510    tmpstr = realmsg+i;
1511    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1512  }
1513  */
1514 
1515  if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
1516    /* aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum); */
1517  }
1518 
1519  return(1);
1520}
1521
1522/*
1523 * Channel 2: Rendevous Request
1524 */
1525static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1526{
1527  /*
1528  printf("rendezvous: source sn = %s\n", userinfo->sn);
1529  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1530  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1531  printuserflags(userinfo->flags);
1532  printf("\n");
1533 
1534  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1535  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1536 
1537  printf("rendezvous: message/description = %s\n", args->msg);
1538  printf("rendezvous: encoding = %s\n", args->encoding);
1539  printf("rendezvous: language = %s\n", args->language);
1540  */
1541 
1542  if (args->reqclass == AIM_CAPS_SENDFILE) {
1543    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: send file!");
1544  } else if (args->reqclass == AIM_CAPS_CHAT) {
1545    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);
1546    /*
1547    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1548    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1549    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1550    */
1551    /* Automatically join room... */
1552    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1553
1554    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1555  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1556    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: Buddy Icon from %s, length = %lu\n",
1557                          userinfo->sn, args->info.icon.length);
1558  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1559    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: RTF message from %s: (fgcolor = 0x%08lx, bgcolor = 0x%08lx) %s\n",
1560                          userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg);
1561  } else {
1562    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: icbm: unknown reqclass (%d)\n", args->reqclass);
1563  }
1564  return 1;
1565}
1566
1567static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1568{
1569  fu16_t channel;
1570  aim_userinfo_t *userinfo;
1571  va_list ap;
1572  int ret = 0;
1573 
1574  va_start(ap, fr);
1575  channel = (fu16_t)va_arg(ap, unsigned int);
1576  userinfo = va_arg(ap, aim_userinfo_t *);
1577 
1578  if (channel == 1) {
1579    struct aim_incomingim_ch1_args *args;
1580    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1581    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1582  } else if (channel == 2) {
1583    struct aim_incomingim_ch2_args *args;
1584    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1585    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1586  } else {
1587    owl_function_debugmsg("faimtest_parse_incoming_im: unsupported channel 0x%04x\n", channel);
1588  }
1589  va_end(ap);
1590  owl_function_debugmsg("faimtest_parse_incoming_im: done with ICBM handling (ret = %d)\n", ret);
1591  return 1;
1592}
1593
1594static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1595{
1596  aim_userinfo_t *userinfo;
1597  char *nz_screenname;
1598  owl_buddy *b;
1599  owl_buddylist *bl;
1600  va_list ap;
1601  va_start(ap, fr);
1602  userinfo = va_arg(ap, aim_userinfo_t *);
1603  va_end(ap);
1604
1605  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1606  bl=owl_global_get_buddylist(&g);
1607 
1608  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1609
1610  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1611    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1612  }
1613
1614  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1615  if (!b) {
1616    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1617    return(1);
1618  }
1619  if (userinfo->idletime==0) {
1620    owl_buddy_set_unidle(b);
1621  } else {
1622    owl_buddy_set_idle(b);
1623    owl_buddy_set_idle_since(b, userinfo->idletime);
1624  }
1625
1626  if (userinfo->flags & AIM_FLAG_AWAY) {
1627    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1628  }
1629 
1630  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1631   
1632  owl_free(nz_screenname);
1633 
1634  /*
1635    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1636    time(NULL),
1637    userinfo->sn, userinfo->flags,
1638    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1639    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1640    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1641    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1642    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1643    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1644    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1645    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1646    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1647    userinfo->capabilities);
1648  */
1649  return(1);
1650}
1651
1652static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1653{
1654  aim_userinfo_t *userinfo;
1655  char *nz_screenname;
1656  va_list ap;
1657 
1658  va_start(ap, fr);
1659  userinfo = va_arg(ap, aim_userinfo_t *);
1660  va_end(ap);
1661
1662  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1663  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1664  owl_free(nz_screenname);
1665
1666  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1667    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1668  }
1669
1670  /*
1671  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1672         time(NULL),
1673         userinfo->sn, userinfo->flags,
1674         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1675         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1676         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1677         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1678         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1679         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1680         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1681         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1682         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1683         userinfo->capabilities);
1684  */
1685 
1686  return 1;
1687}
1688
1689/* Used by chat as well. */
1690int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1691{
1692  va_list ap;
1693  fu16_t reason;
1694 
1695  va_start(ap, fr);
1696  reason = (fu16_t)va_arg(ap, unsigned int);
1697  va_end(ap);
1698 
1699  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1700  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1701 
1702  return 1;
1703}
1704
1705static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1706{
1707  va_list ap;
1708  char *destsn;
1709  fu16_t reason;
1710 
1711  va_start(ap, fr);
1712  reason = (fu16_t)va_arg(ap, unsigned int);
1713  destsn = va_arg(ap, char *);
1714  va_end(ap);
1715 
1716  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1717  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1718
1719  if (reason==4) {
1720    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1721  }
1722 
1723  return 1;
1724}
1725
1726static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1727{
1728  va_list ap;
1729  char *destsn;
1730  fu16_t reason;
1731 
1732  va_start(ap, fr);
1733  reason = (fu16_t)va_arg(ap, unsigned int);
1734  destsn = va_arg(ap, char *);
1735  va_end(ap);
1736 
1737  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1738  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1739 
1740  return 1;
1741}
1742
1743static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1744{
1745  static char *missedreasons[] = {
1746    "Invalid (0)",
1747    "Message too large",
1748    "Rate exceeded",
1749    "Evil Sender",
1750    "Evil Receiver"
1751  };
1752  static int missedreasonslen = 5;
1753 
1754  va_list ap;
1755  fu16_t chan, nummissed, reason;
1756  aim_userinfo_t *userinfo;
1757 
1758  va_start(ap, fr);
1759  chan = (fu16_t)va_arg(ap, unsigned int);
1760  userinfo = va_arg(ap, aim_userinfo_t *);
1761  nummissed = (fu16_t)va_arg(ap, unsigned int);
1762  reason = (fu16_t)va_arg(ap, unsigned int);
1763  va_end(ap);
1764 
1765  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");
1766 
1767  return 1;
1768}
1769
1770/*
1771 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1772 */
1773static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1774{
1775  va_list ap;
1776  fu16_t type;
1777  char *sn = NULL;
1778 
1779  va_start(ap, fr);
1780  type = (fu16_t)va_arg(ap, unsigned int);
1781  sn = va_arg(ap, char *);
1782  va_end(ap);
1783 
1784  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1785 
1786  return 1;
1787}
1788
1789static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1790{
1791  static char *codes[5] = {
1792    "invalid",
1793    "change",
1794    "warning",
1795    "limit",
1796    "limit cleared"
1797  };
1798  va_list ap;
1799  fu16_t code, rateclass;
1800  fu32_t windowsize, clear, alert, limit, disconnect;
1801  fu32_t currentavg, maxavg;
1802 
1803  va_start(ap, fr); 
1804 
1805  /* See code explanations below */
1806  code = (fu16_t)va_arg(ap, unsigned int);
1807 
1808  /*
1809   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1810   */
1811  rateclass = (fu16_t)va_arg(ap, unsigned int);
1812 
1813  /*
1814   * Not sure what this is exactly.  I think its the temporal
1815   * relation factor (ie, how to make the rest of the numbers
1816   * make sense in the real world).
1817   */
1818  windowsize = va_arg(ap, fu32_t);
1819 
1820  /* Explained below */
1821  clear = va_arg(ap, fu32_t);
1822  alert = va_arg(ap, fu32_t);
1823  limit = va_arg(ap, fu32_t);
1824  disconnect = va_arg(ap, fu32_t);
1825  currentavg = va_arg(ap, fu32_t);
1826  maxavg = va_arg(ap, fu32_t);
1827 
1828  va_end(ap);
1829 
1830  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)",
1831                        (code < 5)?codes[code]:"invalid",
1832                        rateclass,
1833                        currentavg, maxavg,
1834                        alert, clear,
1835                        limit, disconnect,
1836                        windowsize);
1837  return 1;
1838}
1839
1840static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1841{
1842  va_list ap;
1843  fu16_t newevil;
1844  aim_userinfo_t *userinfo;
1845 
1846  va_start(ap, fr);
1847  newevil = (fu16_t)va_arg(ap, unsigned int);
1848  userinfo = va_arg(ap, aim_userinfo_t *);
1849  va_end(ap);
1850 
1851  /*
1852   * Evil Notifications that are lacking userinfo->sn are anon-warns
1853   * if they are an evil increases, but are not warnings at all if its
1854   * a decrease (its the natural backoff happening).
1855   *
1856   * newevil is passed as an int representing the new evil value times
1857   * ten.
1858   */
1859  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1860 
1861  return 1;
1862}
1863
1864static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1865{
1866  va_list ap;
1867  char *address, *SNs;
1868  int num, i;
1869  owl_list list;
1870 
1871  va_start(ap, fr);
1872  address = va_arg(ap, char *);
1873  num = va_arg(ap, int);
1874  SNs = va_arg(ap, char *);
1875  va_end(ap);
1876
1877  owl_list_create(&list);
1878 
1879  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1880  for (i=0; i<num; i++) {
1881    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1882    owl_list_append_element(&list, &SNs[i*(MAXSNLEN+1)]);
1883  }
1884  owl_function_aimsearch_results(address, &list);
1885  owl_list_free_simple(&list);
1886  return(1);
1887}
1888
1889static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1890{
1891  va_list ap;
1892  char *address;
1893 
1894  va_start(ap, fr);
1895  address = va_arg(ap, char *);
1896  va_end(ap);
1897
1898  owl_function_error("No results searching for %s", address);
1899  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1900 
1901  return(1);
1902}
1903
1904static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1905{
1906  va_list ap;
1907  char *msg, *url;
1908  fu16_t width, height, delay;
1909 
1910  va_start(ap, fr);
1911  msg = va_arg(ap, char *);
1912  url = va_arg(ap, char *);
1913  width = va_arg(ap, unsigned int);
1914  height = va_arg(ap, unsigned int);
1915  delay = va_arg(ap, unsigned int);
1916  va_end(ap);
1917 
1918  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1919 
1920  return 1;
1921}
1922
1923static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1924{
1925  aim_sendpauseack(sess, fr->conn);
1926  return 1;
1927}
1928
1929static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1930{
1931  va_list ap;
1932  aim_conn_t *bosconn;
1933  char *bosip;
1934  fu8_t *cookie;
1935 
1936  va_start(ap, fr);
1937  bosip = va_arg(ap, char *);
1938  cookie = va_arg(ap, fu8_t *);
1939  va_end(ap);
1940 
1941  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1942  aim_conn_kill(sess, &fr->conn);
1943 
1944  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1945    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1946    return 1;
1947  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1948    owl_function_debugmsg("migrate: could not connect to BOS");
1949    aim_conn_kill(sess, &bosconn);
1950    return 1;
1951  }
1952 
1953  /* Login will happen all over again. */
1954  addcb_bos(sess, bosconn);
1955  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1956  return 1;
1957}
1958
1959static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1960{
1961  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1962  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1963  aim_ssi_reqdata(sess);
1964 
1965  return(1);
1966}
1967
1968static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1969{
1970  va_list ap;
1971  fu8_t fmtver;
1972  fu16_t itemcount;
1973  fu32_t stamp;
1974  struct aim_ssi_item *list;
1975  /*
1976  struct aim_ssi_item *curitem;
1977  struct aim_ssi_item *l;
1978  */
1979 
1980  va_start(ap, fr);
1981  fmtver = va_arg(ap, unsigned int);
1982  itemcount = va_arg(ap, unsigned int);
1983  stamp = va_arg(ap, fu32_t);
1984  list = va_arg(ap, struct aim_ssi_item *);
1985  va_end(ap);
1986 
1987  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %ld)", fmtver, itemcount, stamp);
1988  /*
1989  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1990    for (l = list; l; l = l->next) {
1991      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1992    }
1993  }
1994  */
1995  aim_ssi_enable(sess);
1996 
1997  return 1;
1998}
1999
2000static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
2001{
2002  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
2003  /* aim_ssi_enable(sess, fr->conn); */
2004  aim_ssi_enable(sess);
2005  return 1;
2006}
2007
2008static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
2009{
2010  va_list ap;
2011  struct aim_icq_offlinemsg *msg;
2012 
2013  va_start(ap, fr);
2014  msg = va_arg(ap, struct aim_icq_offlinemsg *);
2015  va_end(ap);
2016 
2017  if (msg->type == 0x0001) {
2018    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);
2019  } else {
2020    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
2021  }
2022  return 1;
2023}
2024
2025static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
2026{
2027  /* Tell the server to delete them. */
2028  owl_function_debugmsg("offlinemsg done: ");
2029  aim_icq_ackofflinemsgs(sess);
2030  return 1;
2031}
2032
2033
2034/******************** chat.c **************************/
2035
2036static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
2037{
2038  va_list ap;
2039  aim_userinfo_t *userinfo;
2040  int count;
2041  /* int i; */
2042 
2043  va_start(ap, fr);
2044  count = va_arg(ap, int);
2045  userinfo = va_arg(ap, aim_userinfo_t *);
2046  va_end(ap);
2047
2048  owl_function_debugmsg("In faimtest_chat_join");
2049  /*
2050  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
2051  for (i = 0; i < count; i++)
2052    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
2053  */
2054  return 1;
2055}
2056
2057static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
2058{
2059  aim_userinfo_t *userinfo;
2060  va_list ap;
2061  int count;
2062  /* int i; */
2063
2064 
2065  va_start(ap, fr);
2066  count = va_arg(ap, int);
2067  userinfo = va_arg(ap, aim_userinfo_t *);
2068  va_end(ap);
2069 
2070  /*
2071    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
2072   
2073    for (i = 0; i < count; i++)
2074    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
2075  */
2076  return 1;
2077}
2078
2079static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
2080{
2081  va_list ap;
2082  aim_userinfo_t *userinfo;
2083  struct aim_chat_roominfo *roominfo;
2084  char *roomname;
2085  int usercount;
2086  char *roomdesc;
2087  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
2088  fu32_t creationtime;
2089  const char *croomname;
2090  /* int i; */
2091 
2092  croomname = aim_chat_getname(fr->conn);
2093 
2094  va_start(ap, fr);
2095  roominfo = va_arg(ap, struct aim_chat_roominfo *);
2096  roomname = va_arg(ap, char *);
2097  usercount = va_arg(ap, int);
2098  userinfo = va_arg(ap, aim_userinfo_t *);
2099  roomdesc = va_arg(ap, char *);
2100  flags = (fu16_t)va_arg(ap, unsigned int);
2101  creationtime = va_arg(ap, fu32_t);
2102  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2103  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
2104  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
2105  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
2106  va_end(ap);
2107
2108  owl_function_debugmsg("In faimtest_chat_infoupdate");
2109  /*
2110  printf("chat: %s:  info update:\n", croomname);
2111  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
2112  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
2113  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
2114  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
2115
2116  for (i = 0; i < usercount; i++)
2117    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
2118 
2119  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
2120         croomname, flags,
2121         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2122         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2123         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2124         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2125  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
2126  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
2127  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
2128  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
2129  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
2130  */
2131 
2132  return(1);
2133}
2134
2135static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
2136{
2137  va_list ap;
2138  aim_userinfo_t *userinfo;
2139  char *msg;
2140  char tmpbuf[1152];
2141 
2142  va_start(ap, fr);
2143  userinfo = va_arg(ap, aim_userinfo_t *);     
2144  msg = va_arg(ap, char *);
2145  va_end(ap);
2146
2147  owl_function_debugmsg("in faimtest_chat_incomingmsg");
2148
2149  /*
2150  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
2151  */
2152 
2153  /*
2154   * Do an echo for testing purposes.  But not for ourselves ("oops!")
2155   */
2156  if (strcmp(userinfo->sn, sess->sn) != 0) {
2157    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
2158    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
2159  }
2160 
2161  return 1;
2162}
2163
2164static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
2165{
2166  fu16_t type;
2167  va_list ap;
2168 
2169  va_start(ap, fr);
2170  type = (fu16_t)va_arg(ap, unsigned int);
2171
2172  owl_function_debugmsg("in faimtest_chatnav_info");
2173 
2174  if (type == 0x0002) {
2175    int maxrooms;
2176    struct aim_chat_exchangeinfo *exchanges;
2177    int exchangecount;
2178    /* int i; */
2179   
2180    maxrooms = va_arg(ap, int);
2181    exchangecount = va_arg(ap, int);
2182    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2183    va_end(ap);
2184
2185    /*
2186    printf("chat info: Chat Rights:\n");
2187    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2188    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
2189    for (i = 0; i < exchangecount; i++) {
2190      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
2191             exchanges[i].number,
2192             exchanges[i].name,
2193             exchanges[i].charset1,
2194             exchanges[i].lang1,
2195             exchanges[i].flags,
2196             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2197             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2198             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2199             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2200    }
2201    */
2202  } else if (type == 0x0008) {
2203    char *fqcn, *name, *ck;
2204    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2205    fu8_t createperms;
2206    fu32_t createtime;
2207   
2208    fqcn = va_arg(ap, char *);
2209    instance = (fu16_t)va_arg(ap, unsigned int);
2210    exchange = (fu16_t)va_arg(ap, unsigned int);
2211    flags = (fu16_t)va_arg(ap, unsigned int);
2212    createtime = va_arg(ap, fu32_t);
2213    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2214    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
2215    createperms = (fu8_t)va_arg(ap, unsigned int);
2216    unknown = (fu16_t)va_arg(ap, unsigned int);
2217    name = va_arg(ap, char *);
2218    ck = va_arg(ap, char *);
2219    va_end(ap);
2220   
2221    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
2222   
2223  } else {
2224    va_end(ap);
2225    /* printf("chatnav info: unknown type (%04x)\n", type); */
2226  }
2227 
2228  return 1;
2229}
2230
2231static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
2232{
2233  owl_function_debugmsg("faimtest_conninitdone_chat:");
2234
2235  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
2236  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
2237  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
2238  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
2239  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
2240 
2241  aim_clientready(sess, fr->conn);
2242 
2243  owl_function_debugmsg("Chat ready");
2244
2245  /*
2246    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
2247    chatcon->id = id;
2248    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
2249  */
2250  return(1);
2251}
2252
2253static int conninitdone_chatnav(aim_session_t *sess, aim_frame_t *fr, ...)
2254{
2255  owl_function_debugmsg("faimtest_conninitdone_chatnav:");
2256
2257  /* aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, gaim_parse_genericerr, 0); */
2258  /* aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0); */
2259
2260  aim_clientready(sess, fr->conn);
2261
2262  aim_chatnav_reqrights(sess, fr->conn);
2263
2264  return(1);
2265}
2266
2267void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2268{
2269  aim_conn_t *tstconn;
2270
2271  owl_function_debugmsg("in faimtest_chatnav_redirect");
2272 
2273  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
2274  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2275    /* printf("unable to connect to chat(nav) server\n"); */
2276    if (tstconn)
2277      aim_conn_kill(sess, &tstconn);
2278    return;
2279  }
2280 
2281  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2282  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2283  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2284  /* printf("chatnav: connected\n"); */
2285  return;
2286}
2287
2288/* XXX this needs instance too */
2289void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2290{
2291  aim_conn_t *tstconn;
2292
2293  owl_function_debugmsg("in chat_redirect");
2294 
2295  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2296  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2297    /* printf("unable to connect to chat server\n"); */
2298    if (tstconn) aim_conn_kill(sess, &tstconn);
2299    return; 
2300  }             
2301  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2302 
2303  /*
2304   * We must do this to attach the stored name to the connection!
2305   */
2306  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2307  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2308  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2309  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2310  return;       
2311}
2312
2313
2314/**********************************************************************************/
2315
2316#if 0
2317static int faimtest_ssi_rerequestdata(aim_session_t *sess, aim_frame_t *fr, ...)
2318{
2319  aim_ssi_reqdata(sess);
2320  return(0);
2321}
2322
2323static int faimtest_ssi_parseerr(aim_session_t *sess, aim_frame_t *fr, ...)
2324{
2325  /* GaimConnection *gc = sess->aux_data; */
2326  /*    OscarData *od = gc->proto_data; */
2327  va_list ap;
2328  fu16_t reason;
2329
2330  va_start(ap, fr);
2331  reason = (fu16_t)va_arg(ap, unsigned int);
2332  va_end(ap);
2333
2334  owl_function_debugmsg("faimtest_ssi_parseerr: ssi: SNAC error %hu", reason);
2335
2336  if (reason == 0x0005) {
2337    owl_function_error("faimtest_ssi_parseerr: unable to retrieve buddy list");
2338  }
2339
2340  /* Activate SSI */
2341  /* Sending the enable causes other people to be able to see you, and you to see them */
2342  /* Make sure your privacy setting/invisibility is set how you want it before this! */
2343  owl_function_debugmsg("faimtest_ssi_parseerr: ssi: activating server-stored buddy list");
2344  aim_ssi_enable(sess);
2345 
2346  return(1);
2347}
2348
2349static int faimtest_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...)
2350{
2351  /* GaimConnection *gc = sess->aux_data; */
2352  /* OscarData *od = (OscarData *)gc->proto_data; */
2353  int numtypes, i;
2354  fu16_t *maxitems;
2355  va_list ap;
2356
2357  va_start(ap, fr);
2358  numtypes = va_arg(ap, int);
2359  maxitems = va_arg(ap, fu16_t *);
2360  va_end(ap);
2361
2362  owl_function_debugmsg("faimtest_ssi_parserights: ");
2363  for (i=0; i<numtypes; i++) {
2364    owl_function_debugmsg(" max type 0x%04x=%hd,", i, maxitems[i]);
2365  }
2366
2367  /*
2368  if (numtypes >= 0) od->rights.maxbuddies = maxitems[0];
2369  if (numtypes >= 1) od->rights.maxgroups = maxitems[1];
2370  if (numtypes >= 2) od->rights.maxpermits = maxitems[2];
2371  if (numtypes >= 3) od->rights.maxdenies = maxitems[3];
2372  */
2373 
2374  return(1);
2375}
2376
2377static int faimtest_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...)
2378{
2379  /* GaimConnection *gc = sess->aux_data; */
2380  /* GaimAccount *account = gaim_connection_get_account(gc); */
2381  /* OscarData *od = (OscarData *)gc->proto_data; */
2382  struct aim_ssi_item *curitem;
2383  int tmp;
2384  int export = FALSE;
2385  /* XXX - use these?
2386     va_list ap;
2387     
2388     va_start(ap, fr);
2389     fmtver = (fu16_t)va_arg(ap, int);
2390     numitems = (fu16_t)va_arg(ap, int);
2391     items = va_arg(ap, struct aim_ssi_item);
2392     timestamp = va_arg(ap, fu32_t);
2393     va_end(ap); */
2394 
2395  owl_function_debugmsg("faimtest_ssi_parselist: syncing local list and server list");
2396
2397  /* Clean the buddy list */
2398  aim_ssi_cleanlist(sess);
2399
2400  /* Add from server list to local list */
2401  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
2402    if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
2403      switch (curitem->type) {
2404      case 0x0000: { /* Buddy */
2405        if (curitem->name) {
2406          char *gname = aim_ssi_itemlist_findparentname(sess->ssi.local, curitem->name);
2407          char *gname_utf8 = gname ? gaim_utf8_try_convert(gname) : NULL;
2408          char *alias = aim_ssi_getalias(sess->ssi.local, gname, curitem->name);
2409          char *alias_utf8 = alias ? gaim_utf8_try_convert(alias) : NULL;
2410          GaimBuddy *buddy = gaim_find_buddy(gc->account, curitem->name);
2411          /* Should gname be freed here? -- elb */
2412          /* Not with the current code, but that might be cleaner -- med */
2413          free(alias);
2414          if (buddy) {
2415            /* Get server stored alias */
2416            if (alias_utf8) {
2417              g_free(buddy->alias);
2418              buddy->alias = g_strdup(alias_utf8);
2419            }
2420          } else {
2421            GaimGroup *g;
2422            buddy = gaim_buddy_new(gc->account, curitem->name, alias_utf8);
2423           
2424            if (!(g = gaim_find_group(gname_utf8 ? gname_utf8 : _("Orphans")))) {
2425              g = gaim_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
2426              gaim_blist_add_group(g, NULL);
2427            }
2428           
2429            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2430                       "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname_utf8 ? gname_utf8 : _("Orphans"));
2431            gaim_blist_add_buddy(buddy, NULL, g, NULL);
2432            export = TRUE;
2433          }
2434          g_free(gname_utf8);
2435          g_free(alias_utf8);
2436        }
2437      } break;
2438     
2439      case 0x0001: { /* Group */
2440        /* Shouldn't add empty groups */
2441      } break;
2442     
2443      case 0x0002: { /* Permit buddy */
2444        if (curitem->name) {
2445          /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
2446          GSList *list;
2447          for (list=account->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
2448          if (!list) {
2449            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2450                       "ssi: adding permit buddy %s to local list\n", curitem->name);
2451            gaim_privacy_permit_add(account, curitem->name, TRUE);
2452            export = TRUE;
2453          }
2454        }
2455      } break;
2456     
2457      case 0x0003: { /* Deny buddy */
2458        if (curitem->name) {
2459          GSList *list;
2460          for (list=account->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
2461          if (!list) {
2462            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2463                       "ssi: adding deny buddy %s to local list\n", curitem->name);
2464            gaim_privacy_deny_add(account, curitem->name, TRUE);
2465            export = TRUE;
2466          }
2467        }
2468      } break;
2469     
2470      case 0x0004: { /* Permit/deny setting */
2471        if (curitem->data) {
2472          fu8_t permdeny;
2473          if ((permdeny = aim_ssi_getpermdeny(sess->ssi.local)) && (permdeny != account->perm_deny)) {
2474            gaim_debug(GAIM_DEBUG_INFO, "oscar",
2475                       "ssi: changing permdeny from %d to %hhu\n", account->perm_deny, permdeny);
2476            account->perm_deny = permdeny;
2477            if (od->icq && account->perm_deny == 0x03) {
2478              serv_set_away(gc, "Invisible", "");
2479            }
2480            export = TRUE;
2481          }
2482        }
2483      } break;
2484     
2485      case 0x0005: { /* Presence setting */
2486        /* We don't want to change Gaim's setting because it applies to all accounts */
2487      } break;
2488      } /* End of switch on curitem->type */
2489  } /* End of for loop */
2490 
2491  /* If changes were made, then flush buddy list to file */
2492  if (export)
2493    gaim_blist_save();
2494 
2495  { /* Add from local list to server list */
2496    GaimBlistNode *gnode, *cnode, *bnode;
2497    GaimGroup *group;
2498    GaimBuddy *buddy;
2499    GaimBuddyList *blist;
2500    GSList *cur;
2501   
2502    /* Buddies */
2503    if ((blist = gaim_get_blist()))
2504      for (gnode = blist->root; gnode; gnode = gnode->next) {
2505        if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
2506          continue;
2507        group = (GaimGroup *)gnode;
2508        for (cnode = gnode->child; cnode; cnode = cnode->next) {
2509          if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
2510            continue;
2511          for (bnode = cnode->child; bnode; bnode = bnode->next) {
2512            if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
2513              continue;
2514            buddy = (GaimBuddy *)bnode;
2515            if (buddy->account == gc->account) {
2516              const char *servernick = gaim_buddy_get_setting(buddy, "servernick");
2517              if (servernick)
2518                serv_got_alias(gc, buddy->name, servernick);
2519             
2520              if (aim_ssi_itemlist_exists(sess->ssi.local, buddy->name)) {
2521                /* Store local alias on server */
2522                char *alias = aim_ssi_getalias(sess->ssi.local, group->name, buddy->name);
2523                if (!alias && buddy->alias && strlen(buddy->alias))
2524                  aim_ssi_aliasbuddy(sess, group->name, buddy->name, buddy->alias);
2525                free(alias);
2526              } else {
2527                gaim_debug(GAIM_DEBUG_INFO, "oscar",
2528                           "ssi: adding buddy %s from local list to server list\n", buddy->name);
2529                aim_ssi_addbuddy(sess, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
2530              }
2531            }
2532          }
2533        }
2534      }
2535   
2536    /* Permit list */
2537    if (gc->account->permit) {
2538      for (cur=gc->account->permit; cur; cur=cur->next)
2539        if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
2540          gaim_debug(GAIM_DEBUG_INFO, "oscar",
2541                     "ssi: adding permit %s from local list to server list\n", (char *)cur->data);
2542          aim_ssi_addpermit(sess, cur->data);
2543        }
2544    }
2545   
2546    /* Deny list */
2547    if (gc->account->deny) {
2548      for (cur=gc->account->deny; cur; cur=cur->next)
2549        if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
2550          gaim_debug(GAIM_DEBUG_INFO, "oscar",
2551                     "ssi: adding deny %s from local list to server list\n", (char *)cur->data);
2552          aim_ssi_adddeny(sess, cur->data);
2553        }
2554    }
2555    /* Presence settings (idle time visibility) */
2556    if ((tmp = aim_ssi_getpresence(sess->ssi.local)) != 0xFFFFFFFF)
2557      if (!(tmp & 0x400))
2558        aim_ssi_setpresence(sess, tmp | 0x400);
2559  } /* end adding buddies from local list to server list */
2560 
2561  /* Set our ICQ status */
2562  if  (od->icq && !gc->away) {
2563    aim_setextstatus(sess, AIM_ICQ_STATE_NORMAL);
2564  }
2565 
2566  /* Activate SSI */
2567  /* Sending the enable causes other people to be able to see you, and you to see them */
2568  /* Make sure your privacy setting/invisibility is set how you want it before this! */
2569  gaim_debug(GAIM_DEBUG_INFO, "oscar", "ssi: activating server-stored buddy list\n");
2570  aim_ssi_enable(sess);
2571 
2572  return 1;
2573}
2574
2575static int gaim_ssi_parseack(aim_session_t *sess, aim_frame_t *fr, ...)
2576{
2577  GaimConnection *gc = sess->aux_data;
2578  va_list ap;
2579  struct aim_ssi_tmp *retval;
2580 
2581  va_start(ap, fr);
2582  retval = va_arg(ap, struct aim_ssi_tmp *);
2583  va_end(ap);
2584 
2585  while (retval) {
2586    gaim_debug(GAIM_DEBUG_MISC, "oscar",
2587               "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");
2588   
2589    if (retval->ack != 0xffff)
2590      switch (retval->ack) {
2591      case 0x0000: { /* added successfully */
2592      } break;
2593     
2594      case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */
2595        gchar *buf;
2596        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)")));
2597        gaim_notify_error(gc, NULL, _("Unable To Add"), buf);
2598        g_free(buf);
2599      }
2600       
2601      case 0x000e: { /* buddy requires authorization */
2602        if ((retval->action == AIM_CB_SSI_ADD) && (retval->name))
2603          gaim_auth_sendrequest(gc, retval->name);
2604      } break;
2605     
2606      default: { /* La la la */
2607        gchar *buf;
2608        gaim_debug(GAIM_DEBUG_ERROR, "oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
2609        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)")));
2610        gaim_notify_error(gc, NULL, _("Unable To Add"), buf);
2611        g_free(buf);
2612        /* XXX - Should remove buddy from local list */
2613      } break;
2614      }
2615   
2616    retval = retval->next;
2617  }
2618 
2619  return 1;
2620}
2621
2622static int gaim_ssi_authgiven(aim_session_t *sess, aim_frame_t *fr, ...)
2623{
2624  GaimConnection *gc = sess->aux_data;
2625  va_list ap;
2626  char *sn, *msg;
2627  gchar *dialog_msg, *nombre;
2628  struct name_data *data;
2629  GaimBuddy *buddy;
2630 
2631  va_start(ap, fr);
2632  sn = va_arg(ap, char *);
2633  msg = va_arg(ap, char *);
2634  va_end(ap);
2635 
2636  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2637             "ssi: %s has given you permission to add him to your buddy list\n", sn);
2638 
2639  buddy = gaim_find_buddy(gc->account, sn);
2640  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2641    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2642  else
2643    nombre = g_strdup(sn);
2644 
2645  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);
2646  data = g_new(struct name_data, 1);
2647  data->gc = gc;
2648  data->name = g_strdup(sn);
2649  data->nick = NULL;
2650 
2651  gaim_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
2652                      0, data,
2653                      G_CALLBACK(gaim_icq_buddyadd),
2654                      G_CALLBACK(oscar_free_name_data));
2655 
2656  g_free(dialog_msg);
2657  g_free(nombre);
2658 
2659  return 1;
2660}
2661
2662static int gaim_ssi_authrequest(aim_session_t *sess, aim_frame_t *fr, ...)
2663{
2664  GaimConnection *gc = sess->aux_data;
2665  va_list ap;
2666  char *sn, *msg;
2667  gchar *dialog_msg, *nombre;
2668  struct name_data *data;
2669  GaimBuddy *buddy;
2670 
2671  va_start(ap, fr);
2672  sn = va_arg(ap, char *);
2673  msg = va_arg(ap, char *);
2674  va_end(ap);
2675 
2676  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2677             "ssi: received authorization request from %s\n", sn);
2678 
2679  buddy = gaim_find_buddy(gc->account, sn);
2680  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2681    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2682  else
2683    nombre = g_strdup(sn);
2684 
2685  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."));
2686  data = g_new(struct name_data, 1);
2687  data->gc = gc;
2688  data->name = g_strdup(sn);
2689  data->nick = NULL;
2690 
2691  gaim_request_action(gc, NULL, _("Authorization Request"), dialog_msg,
2692                      0, data, 2,
2693                      _("Authorize"), G_CALLBACK(gaim_auth_grant),
2694                      _("Deny"), G_CALLBACK(gaim_auth_dontgrant_msgprompt));
2695 
2696  g_free(dialog_msg);
2697  g_free(nombre);
2698 
2699  return 1;
2700}
2701
2702static int gaim_ssi_authreply(aim_session_t *sess, aim_frame_t *fr, ...)
2703{
2704  GaimConnection *gc = sess->aux_data;
2705  va_list ap;
2706  char *sn, *msg;
2707  gchar *dialog_msg, *nombre;
2708  fu8_t reply;
2709  GaimBuddy *buddy;
2710 
2711  va_start(ap, fr);
2712  sn = va_arg(ap, char *);
2713  reply = (fu8_t)va_arg(ap, int);
2714  msg = va_arg(ap, char *);
2715  va_end(ap);
2716 
2717  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2718             "ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", sn, reply);
2719 
2720  buddy = gaim_find_buddy(gc->account, sn);
2721  if (buddy && (gaim_get_buddy_alias_only(buddy)))
2722    nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
2723  else
2724    nombre = g_strdup(sn);
2725 
2726  if (reply) {
2727    /* Granted */
2728    dialog_msg = g_strdup_printf(_("The user %s has granted your request to add them to your buddy list."), nombre);
2729    gaim_notify_info(gc, NULL, _("Authorization Granted"), dialog_msg);
2730  } else {
2731    /* Denied */
2732    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."));
2733    gaim_notify_info(gc, NULL, _("Authorization Denied"), dialog_msg);
2734  }
2735  g_free(dialog_msg);
2736  g_free(nombre);
2737 
2738  return 1;
2739}
2740
2741static int gaim_ssi_gotadded(aim_session_t *sess, aim_frame_t *fr, ...)
2742{
2743  GaimConnection *gc = sess->aux_data;
2744  va_list ap;
2745  char *sn;
2746  GaimBuddy *buddy;
2747 
2748  va_start(ap, fr);
2749  sn = va_arg(ap, char *);
2750  va_end(ap);
2751 
2752  buddy = gaim_find_buddy(gc->account, sn);
2753  gaim_debug(GAIM_DEBUG_INFO, "oscar",
2754             "ssi: %s added you to their buddy list\n", sn);
2755  gaim_account_notify_added(gc->account, NULL, sn, (buddy ? gaim_get_buddy_alias_only(buddy) : NULL), NULL);
2756 
2757  return 1;
2758}
2759#endif
Note: See TracBrowser for help on using the repository browser.