root/climm/src/xmpp_base.c

Revision 2856, 67.4 kB (checked in by kuhlmann, 6 months ago)

fix svn properties to get correct svn id; update reference in de climmcmds accordingly

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Implements the XMPP protocol using libiksemel >= 1.2.
3  *
4  * climm Copyright (C) © 2001-2009 RÃŒdiger Kuhlmann
5  *
6  * climm is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 dated June, 1991.
9  *
10  * climm is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
13  * License for more details.
14  *
15  * In addition, as a special exception permission is granted to link the
16  * code of this release of climm with the OpenSSL project's "OpenSSL"
17  * library, and distribute the linked executables.  You must obey the GNU
18  * General Public License in all respects for all of the code used other
19  * than "OpenSSL".  If you modify this file, you may extend this exception
20  * to your version of the file, but you are not obligated to do so.  If you
21  * do not wish to do so, delete this exception statement from your version
22  * of this file.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this package; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  * 02111-1307, USA.
28  *
29  * $Id$
30  */
31
32 //#define IKS_TRANS_USER_DATA Server
33 //#define IKS_FILTER_USER_DATA Server
34 //#define IKS_SOCK_USER_DATA Connection
35 #define IKS_TRANS_USER_DATA void
36 #define IKS_FILTER_USER_DATA void
37 #define IKS_SOCK_USER_DATA void
38
39 #include "climm.h"
40 #include <sys/types.h>
41 #include <errno.h>
42 #if HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #if HAVE_WINSOCK2_H
46 #include <winsock2.h>
47 #endif
48 #include <fcntl.h>
49 #include <assert.h>
50
51 #if ENABLE_XMPP
52
53 #include <iksemel.h>
54
55 #include "xmpp_base.h"
56 #include "connection.h"
57 #include "contact.h"
58 #include "conv.h"
59 #include "oscar_dc.h"
60 #include "util_io.h"
61 #include "im_response.h"
62 #include "im_request.h"
63 #include "util_ui.h"
64 #include "util_rl.h"
65 #include "buildmark.h"
66 #include "preferences.h"
67 #include "oscar_dc_file.h"
68 #include "io/io_dns.h"
69 #include "os.h"
70 #include "util_parse.h"
71
72 static jump_conn_f XMPPCallbackDispatch;
73
74 static int  iks_climm_TConnect (iksparser *prs, IKS_SOCK_USER_DATA **socketptr, const char *server, int port)
75 {
76     Server *serv = iks_stream_user_data (prs);
77     Connection *conn = serv->conn;
78     *((Connection **)socketptr) = conn;
79     return IKS_OK;
80 }
81
82 static void iks_climm_TClose (IKS_SOCK_USER_DATA *conn)
83 {
84     UtilIOClose ((Connection *)conn);
85 }
86
87 static int iks_climm_TSend (IKS_SOCK_USER_DATA *conn, const char *data, size_t len)
88 {
89     io_err_t rc = UtilIOWrite ((Connection *)conn, data, len);
90     if (rc != IO_OK)
91         return IKS_NET_RWERR;
92     return IKS_OK;
93 }
94
95 static int iks_climm_TRecv (IKS_SOCK_USER_DATA *conn, char *data, size_t len, int timeout)
96 {
97     int rc = UtilIORead ((Connection *)conn, data, len);
98     if (rc > 0)
99         return rc;
100     if (rc == IO_OK || rc == IO_CONNECTED)
101         return 0;
102     return -1;
103 }
104
105 static const ikstransport iks_climm_transport = {
106     IKS_TRANSPORT_V1,
107     iks_climm_TConnect,
108     iks_climm_TSend,
109     iks_climm_TRecv,
110     iks_climm_TClose,
111     NULL,
112 };
113
114 static void XMPPCallBackTimeout (Event *event)
115 {
116     Connection *conn = event->conn;
117
118     if (!conn)
119     {
120         EventD (event);
121         return;
122     }
123     assert (conn->serv);
124     assert (conn->serv->type == TYPE_XMPP_SERVER);
125     if (~conn->connect & CONNECT_OK)
126         rl_print ("# XMPP timeout\n");
127     EventD (event);
128 }
129
130 void XmppStreamError (Server *serv, const char *text)
131 {
132     rl_printf ("Stream level error occurred: %s [%s]\n", text, UtilIOErr (serv->conn) ? UtilIOErr (serv->conn) : "");
133     XMPPLogout (serv);
134 }
135
136 Event *XMPPLogin (Server *serv)
137 {
138     const char *scrserv, *sp;
139     char *semi;
140     Event *event;
141     time_t now = time (NULL);
142
143     assert (serv->type == TYPE_XMPP_SERVER);
144
145     if (!serv->screen || !serv->passwd)
146         return NULL;
147     if (!strchr (serv->screen, '@'))
148     {
149         const char *jid = s_sprintf ("%s@jabber.com", serv->screen);
150         s_repl (&serv->screen, jid);
151     }
152     scrserv = strchr (serv->screen, '@') + 1;
153     if (!serv->conn->server || !strcmp (scrserv, serv->conn->server))
154     {
155         const char *rrdns = io_dns_resolve (s_sprintf ("_xmpp-client._tcp.%s", scrserv));
156         s_repl (&serv->conn->server, rrdns ? rrdns : scrserv);
157     }
158
159     XMPPLogout (serv);
160
161     s_repl (&serv->xmpp_stamp, "YYYYmmddHHMMSS");
162     strftime (serv->xmpp_stamp, 15, "%Y%m%d%H%M%S", gmtime (&now));
163     s_repl (&serv->xmpp_privacy_list, NULL);
164     s_repl (&serv->xmpp_privacy_items, NULL);
165
166     semi = strchr (serv->conn->server, ';');
167     if (semi)
168         *semi = 0;
169     sp = s_sprintf ("%s", s_wordquote (strchr (serv->conn->server, ':') ? serv->conn->server : s_sprintf ("%s:%lu", serv->conn->server, serv->conn->port)));
170     rl_printf (i18n (2620, "Opening XMPP connection for %s at %s...\n"),
171         s_wordquote (serv->screen), sp);
172     if (semi)
173         *semi = ';';
174
175     if (!serv->conn->port)
176         serv->conn->port = ~0;
177
178     serv->conn->dispatch = &XMPPCallbackDispatch;
179     serv->conn->connect = 0;
180
181     if ((event = QueueDequeue2 (serv->conn, QUEUE_DEP_WAITLOGIN, 0, NULL)))
182     {
183         event->attempts++;
184         event->due = time (NULL) + 10 * event->attempts + 10;
185         event->callback = &XMPPCallBackTimeout;
186         QueueEnqueue (event);
187     }
188     else
189         event = QueueEnqueueData (serv->conn, QUEUE_DEP_WAITLOGIN, 0, time (NULL) + 5,
190                                   NULL, serv->conn->cont, NULL, &XMPPCallBackTimeout);
191
192     UtilIOConnectTCP (serv->conn);
193     return event;
194 }
195
196 static void XmppSaveLog (IKS_TRANS_USER_DATA *userv, const char *text, size_t size, int in)
197 {
198     Server *serv = (Server *)userv;
199     const char *data;
200     char *textnonl;
201     size_t rc;
202     int i;
203
204     data = s_sprintf ("%s%s %s%s ",
205         iks_is_secure (serv->xmpp_parser) ? "SSL """, s_now,
206         in & 1 ? "<<<" : ">>>", in & 2 ? " residual:" : "");
207
208     if (in)
209         DebugH (DEB_XMPPIN, "%s", data);
210     else
211         DebugH (DEB_XMPPOUT, "%s", data);
212
213     if (!ServerPrefVal (serv, CO_LOGSTREAM))
214         return;
215
216     if (serv->logfd < 0)
217     {
218         const char *dir, *file;
219         dir = s_sprintf ("%sdebug", PrefUserDir (prG));
220         mkdir (dir, 0700);
221         dir = s_sprintf ("%sdebug" _OS_PATHSEPSTR "packets.xmpp.%s", PrefUserDir (prG), serv->screen);
222         mkdir (dir, 0700);
223         file = s_sprintf ("%sdebug" _OS_PATHSEPSTR "packets.xmpp.%s/%lu", PrefUserDir (prG), serv->screen, time (NULL));
224 #if !defined(O_SYNC)
225 #define O_SYNC 0
226 #endif
227         serv->logfd = open (file, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, 0600);
228     }
229     if (serv->logfd < 0)
230         return;
231
232     rc = write (serv->logfd, data, strlen (data));
233
234     textnonl = strdup (text);
235     for (i = 0; textnonl[i]; i++)
236         if (textnonl[i] == '\n' || textnonl[i] == '\r')
237             textnonl[i] = ' ';
238     rc = write (serv->logfd, textnonl, strlen (textnonl));
239     rc = write (serv->logfd, "\n", 1);
240     free (textnonl);
241 }
242
243 static void GetBothContacts (iksid *j, Server *conn, Contact **b, Contact **f, char crea)
244 {
245     Contact *bb, *ff, **t;
246     char *jb = j->partial;
247     char *jr = j->resource;
248
249     if ((bb = ContactFindScreen (conn->contacts, jb)))
250     {
251         if (!(ff = ContactFindScreenP (conn->contacts, bb, jr ? jr : "")))
252         {
253             ff = ContactScreenP (conn, bb, jr ? jr : "");
254         }
255     }
256     else
257     {
258         bb = ContactScreen (conn, jb);
259         if (crea)
260             ContactCreate (conn, bb);
261         ff = ContactScreenP (conn, bb, jr ? jr : "");
262     }
263     assert (bb);
264     if (ff)
265     {
266         /* make ff the firstchild or the firstchild->next of bb */
267         if (!bb->firstchild)
268             bb->firstchild = ff;
269         else if (bb->firstchild != ff && bb->firstchild->next != ff)
270         {
271             for (t = &bb->firstchild; *t; t = &((*t)->next))
272                 if (*t == ff)
273                 {
274                     *t = ff->next;
275                     ff->next = bb->firstchild->next;
276                     bb->firstchild->next = ff;
277                     t = NULL;
278                     break;
279                 }
280             if (t)
281             {
282                 ff->next = bb->firstchild->next;
283                 bb->firstchild->next = ff;
284             }
285         }
286     }
287     else
288         ff = bb;
289     *b = bb;
290     *f = ff;
291 }
292
293 static iks *find_with_ns_attrib (iks *tag, const char *childname, const char *childnamespace)
294 {
295     iks *p, *a;
296     for (p = iks_first_tag (tag); p; p = iks_next_tag(p))
297     {
298         for (a = iks_attrib (p); a; a  = iks_next (a))
299         {
300             if (iks_type (a) != IKS_ATTRIBUTE)
301                 continue;
302             if (strncmp (iks_name (a), "xmlns", 5))
303                 continue;
304             if (strcmp (iks_cdata  (a), childnamespace))
305                 continue;
306             if (!iks_name (a)[5] || iks_name (a)[5] == ':')
307                 return p;
308         }
309     }
310     return NULL;
311 }
312
313 #define foreach_subtag(iter,parent,name) \
314     iks *iter; \
315     for (iter = iks_first_tag (parent); iter; iter = iks_next_tag (iter)) \
316         if (iks_type (iter) == IKS_TAG && !strcmp (iks_name (iter), name))
317
318
319 static enum ikshowtype StatusToIksstatus (status_t *status)
320 {
321     switch (*status)
322     {
323         case ims_online:   return IKS_SHOW_AVAILABLE;   break;
324         case ims_ffc:      return IKS_SHOW_CHAT;        break;
325         case ims_away:     return IKS_SHOW_AWAY;        break;
326         case ims_occ:      *status = ims_dnd;
327         case ims_dnd:      return IKS_SHOW_DND;         break;
328         case ims_na:       return IKS_SHOW_XA;          break;
329         case ims_offline:  *status = ims_inv;
330         default:           return IKS_SHOW_UNAVAILABLE; break;
331     }
332 }
333
334 /****************** send stuff ******************/
335
336 static void XmppSendIqGmail (Server *serv, int64_t newer, const char *newertid, const char *query)
337 {
338     iks *x = iks_new ("iq"), *q;
339     iks_insert_attrib (x, "type", "get");
340     iks_insert_attrib (x, "to", serv->xmpp_id->partial);
341     iks_insert_attrib (x, "id", s_sprintf ("%s-%s-%x", query ? "mailq" : "mail", serv->xmpp_stamp, serv->xmpp_sequence++));
342
343     q = iks_insert (x, "query");
344     iks_insert_attrib (q, "xmlns", "google:mail:notify");
345     if (newer != 0)
346         iks_insert_attrib (q, "newer-than-time", s_sprintf ("%llu", newer));
347     if (newertid && *newertid)
348         iks_insert_attrib (q, "newer-than-tid", newertid);
349     if (query && *query)
350         iks_insert_attrib (q, "q", query);
351     iks_send (serv->xmpp_parser, x);
352     iks_delete (x);
353 }
354
355 static void XmppSendIqTime (Server *serv)
356 {
357     iks *x = iks_new ("iq");
358     iks_insert_attrib (x, "type", "get");
359     iks_insert_attrib (iks_insert (x, "time"), "xmlns", "urn:xmpp:time");
360     iks_insert_attrib (x, "id", s_sprintf ("time-%s-%x", serv->xmpp_stamp, serv->xmpp_sequence++));
361     iks_insert_attrib (x, "to", serv->xmpp_id->server);
362     iks_send (serv->xmpp_parser, x);
363     iks_delete (x);
364 }
365
366 static iks *xmpp_make_iq_privacy (Server *serv, xmpp_priv_t ntype, const char *list)
367 {
368     iks *child, *x, *l = NULL;
369     const char *id;
370     const char *type = ntype == p_active ? "active" : ntype == p_default ? "default" : ntype == p_show || ntype == p_show_quiet ? "list" : NULL;
371     id = s_sprintf ("priv-%d-%s-%x", ntype, serv->xmpp_stamp, ++serv->xmpp_sequence);
372     x = iks_new ("iq");
373     iks_insert_attrib (x, "type", ntype == p_active || ntype == p_default ? "set" : "get");
374     iks_insert_attrib (x, "id", id);
375     iks_insert_attrib (x, "from", serv->xmpp_id->full);
376     child = iks_insert (x, "query");
377     iks_insert_attrib (child, "xmlns", "jabber:iq:privacy");
378     if (type)
379         l = iks_insert (child, type);
380     if (l && list)
381         iks_insert_attrib (l, "name", list);
382     return x;
383 }
384
385 static void XMPPSendIqPrivacy (Server *serv, xmpp_priv_t ntype, const char *list)
386 {
387     iks *x = xmpp_make_iq_privacy (serv, ntype, list);
388     iks_send (serv->xmpp_parser, x);
389     iks_delete (x);
390 }
391
392 static int xmpp_uint_compare (const char *a, const char *b)
393 {
394     if (*a == '+')
395         a++;
396     if (*b == '+')
397         b++;
398     while (*a == '0')
399         a++;
400     while (*b == '0')
401         b++;
402     if (strlen (a) < strlen (b))
403         return -1;
404     if (strlen (a) > strlen (b))
405         return 1;
406     while (*a && *b)
407     {
408         if (*a < *b)
409             return -1;
410         if (*a > *b)
411             return -1;
412         a++;
413         b++;
414     }
415     return 0;
416 }
417
418 static char *xmpp_uint_add (const char *a, const char *b)
419 {
420     int la = strlen (a), lb = strlen (b), lo = la + lb + 1;
421     char *op = malloc (la + lb + 2), *ret;
422     int o = 0;
423     op[lo] = 0;
424    
425     while (la && lb)
426     {
427         la--;
428         lb--;
429         o += (a[la] - '0') + (b[lb] - '0');
430         op[--lo] = (o % 10) + '0';
431         o /= 10;
432     }
433     if (lb)
434     {
435         la = lb;
436         a = b;
437     }
438     while (la)
439     {
440         la--;
441         o += (a[la] - '0');
442         op[--lo] = (o % 10) + '0';
443         o /= 10;
444     }
445     if (o)
446         op[--lo] = o + '0';
447     ret = strdup (op + lo);
448     free (op);
449     return ret;
450 }
451
452 static void XMPPSendIqPrivacyEdit (Server *serv, xmpp_priv_t ntype, const char *list, const char *edit)
453 {
454     iks *child, *x, *l = NULL, *old = NULL, *xx;
455     UDWORD ig = 0;
456     UDWORD count = 0;
457     const char *insertiontstr, *id;
458     char *insertionstr;
459     int allow;
460
461     id = s_sprintf ("priv-%d-%s-%x", ntype, serv->xmpp_stamp, ++serv->xmpp_sequence);
462     x = iks_new ("iq");
463     iks_insert_attrib (x, "type", "set");
464     iks_insert_attrib (x, "id", id);
465     iks_insert_attrib (x, "from", serv->xmpp_id->full);
466     child = iks_insert (x, "query");
467     iks_insert_attrib (child, "xmlns", "jabber:iq:privacy");
468     l = iks_insert (child, "list");
469     iks_insert_attrib (l, "name", list);
470    
471     xx = xmpp_make_iq_privacy (serv, p_show, list);
472
473     if (ntype == p_edit)
474     {
475         insertiontstr = s_parseint_s (&edit, &ig, DEFAULT_SEP, 0);
476         if (!insertiontstr || *insertiontstr == 'x' || *insertiontstr == '-')
477             insertiontstr = "0";
478         insertionstr = strdup (insertiontstr);
479         old = iks_tree (serv->xmpp_privacy_items, 0, NULL);
480         { foreach_subtag (item_i, old, "item")
481         {
482             const char *iorder  = iks_find_attrib (item_i, "order");
483             if (iorder && xmpp_uint_compare (iorder, insertionstr) < 0)
484                 iks_insert_node (l, iks_copy_within (item_i, iks_stack (l)));
485         }}
486     }
487    
488     while ((s_parsekey (&edit, "allow") && (allow=1)) || (s_parsekey (&edit, "deny") && (allow=2)))
489     {
490         strc_t par;
491         iks *ni = iks_insert (l, "item");
492         char *newsum = xmpp_uint_add (insertionstr, s_sprintf ("%lu", count));
493         iks_insert_attrib (ni, "order", newsum);
494         free (newsum);
495         iks_insert_attrib (ni, "action", allow == 1 ? "allow" : "deny");
496         if (!s_parsekey (&edit, "all"))
497             while (1)
498             {
499                 if (s_parsekey_s (&edit, "msg", MULTI_SEP))
500                     iks_insert (ni, "message");
501                 else if (s_parsekey_s (&edit, "pin", MULTI_SEP))
502                     iks_insert (ni, "presence-in");
503                 else if (s_parsekey_s (&edit, "pout", MULTI_SEP))
504                     iks_insert (ni, "presence-out");
505                 else if (s_parsekey_s (&edit, "iq", MULTI_SEP))
506                     iks_insert (ni, "iq");
507                 else
508                     break;
509             }
510         if (s_parsekey (&edit, "subscription") || s_parsekey (&edit, "sub"))
511         {
512             iks_insert_attrib (ni, "type", "subscription");
513             if (s_parsekey (&edit, "both"))
514                 iks_insert_attrib (ni, "value", "both");
515             else if (s_parsekey (&edit, "to"))
516                 iks_insert_attrib (ni, "value", "to");
517             else if (s_parsekey (&edit, "from"))
518                 iks_insert_attrib (ni, "value", "from");
519             else {
520                 s_parsekey (&edit, "none");
521                 iks_insert_attrib (ni, "value", "none");
522             }
523         }
524         else if (s_parsekey (&edit, "group") && (par = s_parse (&edit)))
525         {
526             iks_insert_attrib (ni, "type", "group");
527             iks_insert_attrib (ni, "value", par->txt);
528         }
529         else if ((s_parsekey (&edit, "jid") || 1) && (par = s_parse (&edit)))
530         {
531             iks_insert_attrib (ni, "type", "jid");
532             iks_insert_attrib (ni, "value", par->txt);
533         }
534         count++;
535     }
536    
537     if (ntype == p_edit)
538     {
539         char *shift, *skipstr;
540         const char *skiptstr;
541         if (s_parsekey (&edit, "delete") && (skiptstr = s_parseint_s (&edit, &ig, DEFAULT_SEP, 0)))
542         {
543             char *ninsertionstr = xmpp_uint_add (insertionstr, skiptstr);
544             free (insertionstr);
545             insertionstr = ninsertionstr;
546             skipstr = strdup (skiptstr);
547         }
548         else
549             skipstr = strdup ("0");
550         shift = xmpp_uint_add (skipstr, s_sprintf ("%lu", count));
551         { foreach_subtag (item_i, old, "item")
552         {
553             const char *iorder  = iks_find_attrib (item_i, "order");
554             if (iorder && xmpp_uint_compare (iorder, insertionstr) >= 0)
555             {
556                 iks *node = iks_copy_within (item_i, iks_stack (l));
557                 char *newsum = xmpp_uint_add (iorder, shift);
558                 iks_insert_attrib (node, "order", newsum);
559                 free (newsum);
560                 iks_insert_node (l, node);
561             }
562         }}
563         free (shift);
564         free (skipstr);
565     }
566     free (insertionstr);
567
568     iks_send (serv->xmpp_parser, x);
569     iks_delete (x);
570
571     iks_send (serv->xmpp_parser, xx);
572     iks_delete (xx);
573 }
574
575 static void sendIqGmailReqs (Event *event)
576 {
577     Server *serv;
578     if (!event->conn)
579     {
580         EventD (event);
581         return;
582     }
583     serv = event->conn->serv;
584     XmppSendIqGmail (serv, serv->xmpp_gmail_new_newer, serv->xmpp_gmail_new_newertid, NULL);
585     event->due += 300;
586     QueueEnqueue (event);
587 }
588
589 static void sendIqTimeReqs (Event *event)
590 {
591     if (!event->conn)
592     {
593         EventD (event);
594         return;
595     }
596     XmppSendIqTime (event->conn->serv);
597     event->due += 300;
598     QueueEnqueue (event);
599 }
600
601 /****************** IqHandler **********/
602
603 static int XmppHandleIqGmail (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
604 {
605     Server *serv = (Server *)fserv;
606     Contact *cont = serv->conn->cont;
607     iks *mb = find_with_ns_attrib (pak->x, "mailbox", "google:mail:notify");
608     char *n_s, *foundnewer;
609     const char *ntid = "";
610     int n = 0, ismail = 0;
611
612     if (!mb)
613         return IKS_FILTER_PASS;
614
615     n_s = iks_find_attrib (mb, "total-matched");
616     if (n_s)
617         n = atoi (n_s);
618
619     if (pak->id && !strncmp (pak->id, "mail-", 5))
620     {
621         ismail = 1;
622         if (n || !strcmp (pak->id + strlen (pak->id) - 2, "-0"))
623             rl_printf (i18n (2738, "Found %d new mails for %s.\n"), n, serv->xmpp_id->partial);
624     }
625     else
626         rl_printf (i18n (2739, "Found %d mails for %s.\n"), n, serv->xmpp_id->partial);
627     if (!n)
628         return IKS_FILTER_EAT;
629
630     {
631     foreach_subtag (mb_c, mb, "mail-thread-info")
632     {
633         char *sub = iks_find_cdata (mb_c, "subject");
634         char *snip = iks_find_cdata (mb_c, "snippet");
635         char *dato = iks_find_attrib (mb_c, "date");
636         time_t t = atoll (dato) / 1000ULL;
637         ntid = iks_find_attrib (mb_c, "tid");
638         rl_printf ("%s ", s_time (&t));
639         rl_printf ("%s%s %s%s%s", COLMESSAGE, sub ? sub : "", COLQUOTE, COLSINGLE, snip ? snip : "");
640         rl_print ("\n");
641         {
642         foreach_subtag (mb_s_c, iks_find (mb_c, "senders"), "sender")
643         {
644             if (!ismail || (iks_find_attrib (mb_s_c, "unread") && !strcmp (iks_find_attrib (mb_s_c, "unread"), "1")))
645             {
646                 char *email = iks_find_attrib (mb_s_c, "address");
647                 char *name = iks_find_attrib (mb_s_c, "name");
648                 rl_printf ("            %s%s%s <%s%s%s>\n", COLQUOTE, name ? name : "", COLNONE, COLCONTACT, email ? email : "", COLNONE);
649             }
650         }}
651     }}
652     foundnewer = iks_find_attrib (mb, "result-time");
653     if (ismail)
654     {
655         serv->xmpp_gmail_new_newer = atoll (foundnewer);
656         s_repl (&serv->xmpp_gmail_new_newertid, ntid);
657     }
658     else
659     {
660         serv->xmpp_gmail_newer = atoll (foundnewer);
661         s_repl (&serv->xmpp_gmail_newertid, ntid);
662     }
663     return IKS_FILTER_EAT;
664 }
665
666 static int XmppHandleIqDisco (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
667 {
668     Server *serv = (Server *)fserv;
669     if (pak->subtype == IKS_TYPE_RESULT)
670     {
671         /*  what did we ask for? */
672         if (!pak->from || pak->from->resource || pak->from->user || strcmp (pak->from->server, serv->xmpp_id->server))
673            return IKS_FILTER_PASS;
674
675         /* disco is from server */
676         if (iks_find_with_attrib (iks_find (pak->x, "query"), "feature", "var", "google:mail:notify"))
677         {
678             /* have Gmail, so start requesting */
679             XmppSendIqGmail (serv, 0, NULL, NULL);
680             QueueEnqueueData2 (serv->conn, QUEUE_XMPP_GMAIL, 0, 300, NULL, &sendIqGmailReqs, NULL);
681             iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqGmail , serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "google:mail:notify", IKS_RULE_DONE);
682             return IKS_FILTER_EAT;
683         }
684     }
685     else if (pak->subtype == IKS_TYPE_GET)
686     {
687         iks *x = iks_new ("iq"), *q, *f, *i;
688         iks_insert_attrib (x, "type", "result");
689         iks_insert_attrib (x, "id", pak->id);
690         iks_insert_attrib (x, "to", pak->from->full);
691         q = iks_insert (x, "query");
692         iks_insert_attrib (q, "xmlns", "http://jabber.org/protocol/disco#info");
693         iks_insert_attrib (q, "node", iks_find_attrib (pak->query, "node"));
694         f = iks_insert (q, "feature");
695         iks_insert_attrib (f, "var", "http://jabber.org/protocol/disco#info");
696         f = iks_insert (q, "feature");
697         iks_insert_attrib (f, "var", "http://jabber.org/protocol/chatstates");
698         f = iks_insert (q, "feature");
699         iks_insert_attrib (f, "var", "jabber:iq:version");
700         f = iks_insert (q, "feature");
701         iks_insert_attrib (f, "var", "jabber:iq:last");
702         i =  iks_insert (q, "identity");
703         iks_insert_attrib (i, "category", "client");
704         iks_insert_attrib (i, "type", "console");
705         iks_insert_attrib (i, "name", "climm");
706         iks_send (serv->xmpp_parser, x);
707         iks_delete (x);
708         return IKS_FILTER_EAT;
709     }
710
711     return IKS_FILTER_PASS;
712 }
713
714 static int XmppHandleIqXEP12 (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
715 {
716     Server *serv = (Server *)fserv;
717     if (pak->subtype == IKS_TYPE_GET)
718     {
719         iks *x = iks_new ("iq"), *q;
720         iks_insert_attrib (x, "type", "result");
721         iks_insert_attrib (x, "id", pak->id);
722         iks_insert_attrib (x, "to", pak->from->full);
723         q = iks_insert (x, "query");
724         iks_insert_attrib (q, "xmlns", "jabber:iq:last");
725         iks_insert_attrib (q, "seconds", s_sprintf ("%ld", uiG.idle_val ? os_DetermineIdleTime (time (NULL), uiG.idle_val) : 0));
726         iks_send (serv->xmpp_parser, x);
727         iks_delete (x);
728         return IKS_FILTER_EAT;
729     }
730     return IKS_FILTER_PASS;
731 }
732
733 static int XmppHandleIqXEP92 (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
734 {
735     Server *serv = (Server *)fserv;
736     if (pak->subtype == IKS_TYPE_GET)
737     {
738         iks *x = iks_new ("iq"), *q;
739         iks_insert_attrib (x, "type", "result");
740         iks_insert_attrib (x, "id", pak->id);
741         iks_insert_attrib (x, "to", pak->from->full);
742         q = iks_insert (x, "query");
743         iks_insert_attrib (q, "xmlns", "jabber:iq:version");
744         iks_insert_cdata (iks_insert (q, "name"), "climm", 0);
745         iks_insert_cdata (iks_insert (q, "version"), BuildVersionStr, 0);
746         iks_insert_cdata (iks_insert (q, "os"), BuildPlatformStr, 0);
747         iks_send (serv->xmpp_parser, x);
748         iks_delete (x);
749         return IKS_FILTER_EAT;
750     }
751     return IKS_FILTER_PASS;
752 }
753
754 static int XmppHandleIqRoster (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
755 {
756     Server *serv = (Server *)fserv;
757     ContactGroup *cg;
758     Contact *contr, *contb;
759     int i;
760    
761     if (pak->subtype == IKS_TYPE_RESULT)
762     {
763         Contact *cont;
764         for (i = 0, cg = serv->contacts; (cont = ContactIndex (cg, i)); i++)
765         {
766             OptSetVal(&cont->copts, CO_ISSBL, 0);
767             OptSetVal(&cont->copts, CO_TO_SBL, 0);
768             OptSetVal(&cont->copts, CO_FROM_SBL, 0);
769             OptSetVal(&cont->copts, CO_ASK_SBL, 0);
770         }
771     }
772     { foreach_subtag(item_c, pak->query, "item")
773     {
774         char *jid = iks_find_attrib (item_c, "jid");
775         char *subs = iks_find_attrib (item_c, "subscription");
776         char *name = iks_find_attrib (item_c, "name");
777         char *ask = iks_find_attrib (item_c, "ask");
778         iksid *jjid;
779        
780         if (!jid || !subs)
781             continue;
782        
783         jjid = iks_id_new (iks_stack (pak->x), jid);
784         GetBothContacts (jjid, serv, &contb, &contr, 1);
785            
786         OptSetVal(&contb->copts, CO_ISSBL, 1);
787         OptSetVal(&contb->copts, CO_TO_SBL, !strcmp (subs, "both") || !strcmp (subs, "to"));
788         OptSetVal(&contb->copts, CO_FROM_SBL, !strcmp (subs, "both") || !strcmp (subs, "from"));
789         OptSetVal(&contb->copts, CO_ASK_SBL, ask && !strcmp (ask, "subscribe"));
790        
791         if (name && !ContactFindScreen (serv->contacts, name))
792             ContactAddAlias (contb, name);
793        
794         { foreach_subtag(group, item_c, "group")
795         {
796             char *g = iks_cdata (group);
797             if (g && *g)
798             {
799                 cg = ContactGroupFind (serv, 0, g);
800                 if (!cg)
801                     cg = ContactGroupC (serv, 0, g);
802                 if (!ContactHas (cg, contb))
803                     ContactAdd (cg, contb);
804             }
805         }}
806     }}
807     return IKS_FILTER_EAT;
808 }
809
810 static int XmppHandleIqPrivacy (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
811 {
812     Server *serv = (Server *)fserv;
813     iks *c;
814     const char *name = NULL;
815     int type = 0;
816    
817     if (strlen (pak->id) > 5 && pak->id[5] >= '1' && pak->id[5] <= '8')
818         type = pak->id[5] - '0';
819    
820     if (pak->subtype == IKS_TYPE_RESULT && type)
821     {
822         if (type == p_list || type == p_list_quiet)
823         {
824             const char *active = NULL, *def = NULL;
825             int items = 0;
826             if ((c = iks_find (pak->query, "active")))
827                 active = iks_find_attrib (c, "name");
828             if ((c = iks_find (pak->query, "default")))
829                 def    = iks_find_attrib (c, "name");
830             s_repl (&serv->xmpp_privacy_list, NULL);
831             s_repl (&serv->xmpp_privacy_items, NULL);
832             if (type == p_list_quiet)
833                 return IKS_FILTER_EAT;
834             if (active)
835                 rl_printf (i18n (2761, "Active privacy list: %s.\n"), s_wordquote (active));
836             else
837                 rl_printf (i18n (2762, "No active privacy list.\n"));
838             if (def)
839                 rl_printf (i18n (2763, "Default privacy list: %s.\n"), s_wordquote (def));
840             else
841                 rl_printf (i18n (2764, "No default privacy list.\n"));
842             rl_print (i18n (2765, "Available privacy lists: "));
843             { foreach_subtag(item_c, pak->query, "list")
844             {
845                 if (!(name = iks_find_attrib (item_c, "name")))
846                     continue;
847                 rl_printf (items++ ? ", %s" : "%s", s_wordquote (name));
848             }}
849             rl_printf (".\n");
850             return IKS_FILTER_EAT;
851         }
852         else if (type == p_show || type == p_show_quiet)
853         {
854             { foreach_subtag(item_c, pak->query, "list")
855             {
856                 if (!(name = iks_find_attrib (item_c, "name")))
857                     continue;
858                 s_repl (&serv->xmpp_privacy_list, name);
859                 s_repl (&serv->xmpp_privacy_items, iks_string (iks_stack (item_c), item_c));
860                 if (type == p_show_quiet)
861                     return IKS_FILTER_EAT;
862                 rl_printf (i18n (2766, "Listing privacy list: %s.\n"), s_wordquote (name));
863                 { foreach_subtag(item_i, item_c, "item")
864                 {
865                     const char *itype   = iks_find_attrib (item_i, "type");
866                     const char *ivalue  = iks_find_attrib (item_i, "value");
867                     const char *iaction = iks_find_attrib (item_i, "action");
868                     const char *iorder  = iks_find_attrib (item_i, "order");
869                     iks *b_ms = iks_find (item_i, "message");
870                     iks *b_pi = iks_find (item_i, "presence-in");
871                     iks *b_po = iks_find (item_i, "presence-out");
872                     iks *b_iq = iks_find (item_i, "iq");
873                     const char *affects;
874                     if (b_ms || b_pi || b_po || b_iq)
875                     {
876                         affects = s_sprintf ("%s%s%s%s", b_ms ? "msg," : "", b_pi ? "pi" : "", b_po ? "po," : "", b_iq ? "iq," : "");
877                         affects = s_sprintf ("%*s", strlen (affects) - 1, affects);
878                     }
879                     else
880                         affects = "all";
881                    
882                     rl_printf ("%-4s %-5s %-5s %-5s %s\n", iorder ? iorder : 0, iaction ? iaction : "", affects, itype ? itype : "", ivalue ? ivalue : "");
883                 }}
884             }}
885             return IKS_FILTER_EAT;
886         }
887         else if (type == p_active || type == p_default)
888         {
889             s_repl (&serv->xmpp_privacy_list, NULL);
890             s_repl (&serv->xmpp_privacy_items, NULL);
891             XMPPPrivacy (serv, p_list, NULL, NULL);
892             return IKS_FILTER_EAT;
893         }
894     }
895     else if (pak->subtype == IKS_TYPE_SET)
896     {
897         if ((c = iks_find (pak->query, "list")))
898             name = iks_find_attrib (c, "name");
899         s_repl (&serv->xmpp_privacy_list, NULL);
900         s_repl (&serv->xmpp_privacy_items, NULL);
901         rl_printf (i18n (2767, "Server updates privacy list %s.\n"), s_wordquote (name));
902         return IKS_FILTER_EAT;
903     }
904     return 0;
905 }
906
907 static int XmppHandleIqTime (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
908 {
909     return IKS_FILTER_EAT;
910 }
911
912 static int XmppHandleIqDefault (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
913 {
914     Server *serv = (Server *)fserv;
915     iks *x, *e, *t, *c;
916     x = iks_new ("iq");
917     iks_insert_attrib (x, "type", "error");
918     iks_insert_attrib (x, "id", pak->id);
919     e = iks_insert (x, "error");
920     iks_insert_attrib  (e, "type", "cancel");
921     t = iks_insert (e, "feature-not-implemented");
922     iks_insert_attrib  (t, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
923     c = iks_tree (iks_string (iks_stack (x), iks_first_tag (x)), 0, NULL);
924     iks_insert_node (x, c);
925     iks_send (serv->xmpp_parser, x);
926     iks_delete (c);
927     iks_delete (x);
928     return IKS_FILTER_PASS;
929 }
930
931 /*********** other handlers *************/
932
933 static int __SkipChar (const char **s, char c)
934 {
935     if (**s == c && **s)
936         (*s)++;
937     if (**s)
938         return *((*s)++) - '0';
939     return 0;
940 }
941
942 static time_t ParseUTCDate (const char *s)
943 {
944    struct tm tm;
945    tm.tm_year =  __SkipChar (&s, 0) * 1000;
946    tm.tm_year += __SkipChar (&s, 0) * 100;
947    tm.tm_year += __SkipChar (&s, 0) * 10;
948    tm.tm_year += __SkipChar (&s, 0) - 1900;
949    tm.tm_mon  =  __SkipChar (&s, '-') * 10;
950    tm.tm_mon  += __SkipChar (&s, 0) - 1;
951    tm.tm_mday =  __SkipChar (&s, '-') * 10;
952    tm.tm_mday += __SkipChar (&s, 0);
953    tm.tm_hour =  __SkipChar (&s, 'T') * 10;
954    tm.tm_hour += __SkipChar (&s, 0);
955    tm.tm_min  =  __SkipChar (&s, ':') * 10;
956    tm.tm_min  += __SkipChar (&s, 0);
957    tm.tm_sec  =  __SkipChar (&s, ':') * 10;
958    if (!*s)
959        return -1;
960    tm.tm_sec  += __SkipChar (&s, 0);
961    if (*s)
962        return -1;
963     return timegm (&tm);
964 }
965
966 static time_t XmppHandleXEP91 (iks *x)
967 {
968     time_t date = NOW;
969     iks *delay;
970     if ((delay = find_with_ns_attrib (x, "x", "jabber:x:delay")))
971     {
972         struct tm;
973         char *stamp;
974         // char *dfrom =
975         iks_find_attrib (delay, "from");
976         stamp = iks_find_attrib (delay, "stamp");
977         date = ParseUTCDate (stamp);
978 //        if (date != NOW)
979 //            DropAttrib (delay, "stamp");
980 //        DropAttrib (delay, "from");
981 //        CheckInvalid (delay);
982     }
983     return date;
984 }
985
986 static void XmppHandleXEP115 (iks *x, Contact *contr)
987 {
988     iks *caps;
989     if ((caps = find_with_ns_attrib (x, "c", "http://jabber.org/protocol/caps")))
990     {
991         char *node = iks_find_attrib (caps, "node");
992         char *ver = iks_find_attrib (caps, "ver");
993         char *ext = iks_find_attrib (caps, "ext");
994         if (!strcmp (node, "http://www.climm.org/xmpp/caps"))
995             node = "climm";
996         else if (!strcmp (node, "http://mail.google.com/xmpp/client/caps"))
997             node = "GoogleMail";
998         else if (!strcmp (node, "http://www.google.com/xmpp/client/caps"))
999             node = "GoogleTalk";
1000         else if (!strcmp (node, "http://www.android.com/gtalk/client/caps"))
1001             node = "Android";
1002         else if (!strcmp (node, "http://pidgin.im/caps"))
1003             node = "Pidgin";
1004         else if (!strcmp (node, "http://gaim.sf.net/caps"))
1005             node = "Gaim";
1006         else if (!strcmp (node, "http://kopete.kde.org/jabber/caps"))
1007             node = "Kopete";
1008         else if (!strcmp (node, "http://psi-im.org/caps"))
1009             node = "Psi";
1010         else if (!strcmp (node, "http://miranda-im.org/caps"))
1011             node = "Miranda";
1012         else if (!strcmp (node, "apple:ichat:caps") || !strcmp (node, "http://www.apple.com/ichat/caps"))
1013             node = "iChat";
1014         else if (!strcmp (node, "http://telepathy.freedesktop.org/caps"))
1015             node = "Telepathy";
1016         else if (!strcmp (node, "http://talkgadget.google.com/client/caps"))
1017             node = "TalkGadget";
1018         else if (!strcmp (node, "http://trillian.im/caps"))
1019             node = "Trillian";
1020         s_repl (&contr->cap_string, ext);
1021         s_repl (&contr->version, s_sprintf ("%s %s", node, ver));
1022 //        DropAttrib (caps, "ver");
1023 //        DropAttrib (caps, "ext");
1024 //        DropAttrib (caps, "node");
1025 //        CheckInvalid (caps);
1026     }
1027 }
1028
1029 static void XmppHandleXEP22a (Server *serv, iks *x, Contact *cfrom)
1030 {
1031     char *refid;
1032     int ref = -1;
1033     int_msg_t type;
1034     iks *ch;
1035
1036     if ((refid = iks_find_cdata (x, "id")))
1037     {
1038 //        DropCData (tid);
1039 //        CheckInvalid (tid);
1040     }
1041     if (refid && !strncmp (refid, "xmpp-", 5) && !strncmp (refid + 5, serv->xmpp_stamp, 14)
1042         && strlen (refid) > 19 && refid[19] == '-')
1043         sscanf (refid + 20, "%x", &ref);
1044
1045     if ((ch =  iks_find (x, "offline")))
1046     {
1047         type = INT_MSGOFF;
1048 //        CheckInvalid (dotag);
1049     }
1050     else if ((ch = iks_find (x, "paused")))
1051     {
1052 //        CheckInvalid (dotag);
1053         IMIntMsg (cfrom, NOW, ims_offline, INT_MSGNOCOMP, "");
1054         ref = -1;
1055     }
1056     else if ((ch = iks_find (x, "delivered")))
1057     {
1058         type = INT_MSGACK_TYPE2;
1059 //        CheckInvalid (dotag);
1060     }
1061     else if ((ch = iks_find (x, "displayed")))
1062     {
1063         type = INT_MSGDISPL;
1064 //        CheckInvalid (dotag);
1065     }
1066     else if ((ch = iks_find (x, "composing")))
1067     {
1068 //        CheckInvalid (dotag);
1069         IMIntMsg (cfrom, NOW, ims_offline, INT_MSGCOMP, "");
1070         ref = -1;
1071     }
1072     else
1073         ref = -1;
1074
1075     if (ref != -1)
1076     {
1077         Event *event = QueueDequeue (serv->conn, QUEUE_XMPP_RESEND_ACK, ref);
1078         if (event)
1079         {
1080             Message *msg = (Message *)event->data;
1081             assert (msg);
1082             if (msg->send_message && !msg->otrinjected)
1083             {
1084                 msg->type = type;
1085                 IMIntMsgMsg (msg, NOW, ims_offline);
1086             }
1087             event->attempts += 5;
1088             QueueEnqueue (event);
1089         }
1090     }
1091 //    CheckInvalid (XEP22);
1092 }
1093
1094 static void XmppHandleXEP22c (Server *serv, iksid *from, char *tof, char *id, char *type)
1095 {
1096     iks *msg  = iks_make_msg (IKS_TYPE_NONE, from->full, NULL), *x;
1097     iks_insert_attrib (msg, "id", s_sprintf ("ack-%s-%x", serv->xmpp_stamp, ++serv->xmpp_sequence));
1098     x = iks_insert (msg, "x");
1099     iks_insert_attrib (x, "xmlns", "jabber:x:event");
1100     iks_insert (x, type);
1101     iks_insert_cdata (iks_insert (x, "id"), id, 0);
1102     iks_send (serv->xmpp_parser, msg);
1103     iks_delete (msg);
1104 }
1105
1106 static void XmppHandleXEP22b (Server *serv, iks *x, iksid *from, char *tof, char *id)
1107 {
1108     iks *ch;
1109     if ((ch = iks_find (x, "delivered")))
1110     {
1111         XmppHandleXEP22c (serv, from, tof, id, "delivered");
1112 //        CheckInvalid (dotag);
1113     }
1114     if ((ch = iks_find (x, "displayed")))
1115     {
1116         XmppHandleXEP22c (serv, from, tof, id, "displayed");
1117 //        CheckInvalid (dotag);
1118     }
1119     if ((ch = iks_find (x, "composing")))
1120     {
1121 //        CheckInvalid (dotag);
1122     }
1123     if ((ch = iks_find (x, "offline")))
1124     {
1125 //        CheckInvalid (dotag);
1126     }
1127 }
1128
1129 static char XmppHandleXEP22 (Server *serv, iks *t, Contact *cfrom, iksid *from, char *tof, char *id)
1130 {
1131     char ret = 0;
1132     iks *ch;
1133     if ((ch = find_with_ns_attrib (t, "x", "jabber:x:event")))
1134     {
1135         ret = 1;
1136         if (!iks_find (t, "body"))
1137         {
1138             XmppHandleXEP22a (serv, ch, cfrom);
1139             return 1;
1140         }
1141         else
1142             XmppHandleXEP22b (serv, ch, from, tof, id);
1143     }
1144     return 0;
1145 }
1146
1147 static char XmppHandleXEP85 (Server *serv, iks *t, Contact *cfrom, iksid *from, char *tof, char *id)
1148 {
1149     char ret = 0;
1150     iks *ch;
1151     if ((ch = find_with_ns_attrib (t, "addresses", "http://jabber.org/protocol/address")))
1152     {
1153 //        DropAllChildsTree (address, "address");
1154 //        CheckInvalid (address);
1155         ret = 1;
1156     }
1157
1158     if ((ch = find_with_ns_attrib (t, "active", "http://jabber.org/protocol/chatstates")))
1159     {
1160 //        CheckInvalid (active);
1161         ret = 1;
1162     }
1163     if ((ch = find_with_ns_attrib (t, "composing", "http://jabber.org/protocol/chatstates")))
1164     {
1165 //        CheckInvalid (composing);
1166         IMIntMsg (cfrom, NOW, ims_offline, INT_MSGCOMP, "");
1167         ret = 1;
1168     }
1169     if ((ch = find_with_ns_attrib (t, "paused", "http://jabber.org/protocol/chatstates")))
1170     {
1171 //        CheckInvalid (paused);
1172         IMIntMsg (cfrom, NOW, ims_offline, INT_MSGNOCOMP, "");
1173         ret = 1;
1174     }
1175     if ((ch = find_with_ns_attrib (t, "inactive", "http://jabber.org/protocol/chatstates")))
1176     {
1177 //        CheckInvalid (inactive);
1178         ret = 1;
1179     }
1180     if ((ch = find_with_ns_attrib (t, "gone", "http://jabber.org/protocol/chatstates")))
1181     {
1182 //        CheckInvalid (gone);
1183         ret = 1;
1184     }
1185     if (ret && !iks_find (t, "body"))
1186         return 1;
1187     return 0;
1188 }
1189
1190 static int XmppHandleMessage (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1191 {
1192     Server *serv = (Server *)fserv;
1193 //    char *toX = iks_find_attrib (pak->x, "to");
1194 //    iksid *to = iks_id_new (iks_stack (pak->x), toX);
1195
1196 //    Contact *cto = ContactScreen (serv, pak->tof);
1197 //    std::string subtypeval = t->findAttribute ("type");
1198 //    std::string body = t->body();
1199 //    std::string subject = t->subject();
1200 //    std::string html;
1201 //    gloox::Tag *htmltag = find_with_ns_attrib (t, "html", "http://jabber.org/protocol/xhtml-im");
1202 //    if (htmltag)
1203 //        htmltag = find_with_ns_attrib (htmltag, "body", "http://www.w3.org/1999/xhtml");
1204 //    if (htmltag)
1205 //        html = htmltag->cdata();
1206 //    DropAttrib (t, "type");
1207     time_t delay = -1;
1208     Contact *contb, *contr;
1209     Opt *opt;
1210
1211     GetBothContacts (pak->from, serv, &contb, &contr, 0);
1212
1213 //    DropAllChilds (t, "subject");
1214 //    DropAllChilds (t, "thread");
1215 //    handleXEP71 (t);
1216 //    handleGoogleNosave (t);
1217 //    handleGoogleSig (t);
1218 //    handleGoogleChatstate (t);
1219 //    handleXEP136 (t);
1220     delay = XmppHandleXEP91 (pak->x);
1221     XmppHandleXEP115 (pak->x, contr); // entity capabilities (used also for client version)
1222     if (XmppHandleXEP22 (serv, pak->x, contr, pak->from, iks_find_attrib (pak->x, "to"), pak->id))
1223         return IKS_FILTER_EAT;
1224     if (XmppHandleXEP85 (serv, pak->x, contr, pak->from, iks_find_attrib (pak->x, "to"), pak->id))
1225         return IKS_FILTER_EAT;
1226 //    DropAllChilds (t, "body");
1227
1228     opt = OptSetVals (NULL, CO_ORIGIN, CV_ORIGIN_v8, CO_MSGTYPE, MSG_NORM, CO_MSGTEXT, iks_find_cdata (pak->x, "body"), 0);
1229
1230 //    if (!subject.empty())
1231 //        opt = OptSetVals (opt, CO_MSGTYPE, MSG_NORM_SUBJ, CO_SUBJECT, subject.c_str(), 0);
1232 //    if (!strcmp (html.c_str(), body.c_str()))
1233 //        opt = OptSetVals (opt, CO_SAMEHTML, 1);
1234     IMSrvMsgFat (contr, delay, opt);
1235
1236 //    if (gloox::Tag *x = t->findChild ("x"))
1237 //        CheckInvalid (x);
1238     return IKS_FILTER_EAT;
1239 }
1240
1241
1242 static int XmppHandlePresenceErr (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1243 {
1244     Contact *contb, *contr;
1245
1246     Server *serv = (Server *)fserv;
1247     GetBothContacts (pak->from, serv, &contb, &contr, 1);
1248     IMOffline (contr);
1249     return IKS_FILTER_EAT;
1250 }
1251
1252 /*
1253  * React to subscription requests.
1254  */
1255 static int XmppHandleSubscription (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1256 {
1257     Server *serv = (Server *)fserv;
1258     Contact *contb, *contr;
1259     GetBothContacts (pak->from, serv, &contb, &contr, 1);
1260
1261     if (pak->subtype == IKS_TYPE_SUBSCRIBE)
1262         IMSrvMsg (contr, NOW, CV_ORIGIN_v8, MSG_AUTH_REQ, NULL);
1263     else if (pak->subtype == IKS_TYPE_SUBSCRIBED)
1264         IMSrvMsg (contr, NOW, CV_ORIGIN_v8, MSG_AUTH_GRANT, NULL);
1265     else if (pak->subtype == IKS_TYPE_UNSUBSCRIBE)
1266         IMSrvMsg (contr, NOW, CV_ORIGIN_v8, MSG_AUTH_DENY, NULL);
1267     else if (pak->subtype == IKS_TYPE_UNSUBSCRIBED)
1268         IMSrvMsg (contr, NOW, CV_ORIGIN_v8, MSG_AUTH_DONE, NULL);
1269     else
1270         return IKS_FILTER_PASS;
1271     return IKS_FILTER_EAT;
1272 }
1273
1274 static int XmppHandlePresence (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1275 {
1276     Server *serv = (Server *)fserv;
1277 //    ContactGroup *tcg;
1278     Contact *contb, *contr; // , *c;
1279     status_t status;
1280 //    std::string pri;
1281     time_t delay;
1282
1283     GetBothContacts (pak->from, serv, &contb, &contr, 1);
1284
1285 //    if (gloox::Tag *priority = s->findChild ("priority"))
1286 //    {
1287 //        pri = priority->cdata();
1288 //        DropCData (priority);
1289 //        CheckInvalid (priority);
1290 //    }
1291
1292     delay = XmppHandleXEP91 (pak->x);
1293     // FIXME: do something with it!
1294
1295     XmppHandleXEP115 (pak->x, contr); // entity capabilities (used also for client version)
1296 //    handleXEP153 (s, contb); // vcard-based avatar, nickname
1297 //    handleXEP27 (s);         // OpenPGP signature (obsolete)
1298 //    handleXEP8 (s);          // iq-based avatar (obsolete)
1299
1300     if (pak->subtype == IKS_TYPE_UNAVAILABLE)
1301     {
1302         status = ims_offline;
1303 //        DropAttrib (s, "type");
1304         IMOffline (contr);
1305         return IKS_FILTER_EAT;
1306     }
1307     else if (pak->show == IKS_SHOW_CHAT)      status = ims_ffc;
1308     else if (pak->show == IKS_SHOW_AWAY)      status = ims_away;
1309     else if (pak->show == IKS_SHOW_DND)       status = ims_dnd;
1310     else if (pak->show == IKS_SHOW_XA)        status = ims_na;
1311     else if (pak->show == IKS_SHOW_AVAILABLE) status = ims_online;
1312     else assert (0);
1313
1314     if (!ContactPrefVal (contb, CO_TO_SBL))
1315         XMPPAuthorize (serv, contb, auth_req, "auto re-sync");
1316
1317     IMOnline (contr, status, imf_none, pak->show, iks_find_cdata (pak->x, "status"));
1318     return IKS_FILTER_EAT;
1319 }
1320
1321
1322 static int XmppUnknown (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1323 {
1324     Server *serv = (Server *)fserv;
1325     XmppSaveLog (serv, iks_string (iks_stack (pak->x), pak->x), 0, 2);
1326     return IKS_FILTER_EAT;
1327 }
1328
1329 /***************** end handlers *******************/
1330
1331
1332 static void XmppLoggedIn (Server *serv)
1333 {
1334     iks *x;
1335
1336     if (serv->xmpp_filter)
1337         iks_filter_delete (serv->xmpp_filter);
1338     serv->xmpp_filter = iks_filter_new ();
1339     iks_filter_add_rule (serv->xmpp_filter, XmppUnknown, serv, IKS_RULE_DONE);
1340     iks_filter_add_rule (serv->xmpp_filter, XmppHandlePresence, serv, IKS_RULE_TYPE, IKS_PAK_PRESENCE, IKS_RULE_DONE);
1341     iks_filter_add_rule (serv->xmpp_filter, XmppHandleSubscription, serv, IKS_RULE_TYPE, IKS_PAK_S10N, IKS_RULE_DONE);
1342     iks_filter_add_rule (serv->xmpp_filter, XmppHandlePresenceErr, serv, IKS_RULE_TYPE, IKS_PAK_S10N, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1343     iks_filter_add_rule (serv->xmpp_filter, XmppHandleMessage, serv, IKS_RULE_TYPE, IKS_PAK_MESSAGE, IKS_RULE_DONE);
1344
1345     serv->conn->connect = CONNECT_OK | CONNECT_SELECT_R;
1346
1347     XMPPSetstatus (serv, NULL, serv->status, serv->conn->cont->status_message);
1348
1349     x = iks_make_iq (IKS_TYPE_GET, IKS_NS_ROSTER);
1350     iks_insert_attrib (x, "id", s_sprintf ("roster-%s-%x", serv->xmpp_stamp, serv->xmpp_sequence++));
1351     iks_send (serv->xmpp_parser, x);
1352     iks_delete (x);
1353     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqRoster, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_ROSTER, IKS_RULE_DONE);
1354     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqRoster, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, IKS_NS_ROSTER, IKS_RULE_DONE);
1355
1356     QueueEnqueueData2 (serv->conn, QUEUE_SRV_KEEPALIVE, 0, 300, NULL, &sendIqTimeReqs, NULL);
1357     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqTime, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "urn:xmpp:time", IKS_RULE_DONE);
1358
1359     x = iks_make_iq (IKS_TYPE_GET, "http://jabber.org/protocol/disco#info");
1360     iks_insert_attrib (x, "id", s_sprintf ("disco-%s-%x", serv->xmpp_stamp, serv->xmpp_sequence++));
1361     iks_insert_attrib (x, "to", serv->xmpp_id->server);
1362     iks_send (serv->xmpp_parser, x);
1363     iks_delete (x);
1364     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqDisco, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
1365
1366     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqXEP92, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "jabber:iq:version", IKS_RULE_DONE);
1367     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqXEP12, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "jabber:iq:last", IKS_RULE_DONE);
1368     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqPrivacy, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "jabber:iq:privacy", IKS_RULE_DONE);
1369
1370     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqDefault, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_DONE);
1371     iks_filter_add_rule (serv->xmpp_filter, XmppHandleIqDefault, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_DONE);
1372    
1373     {
1374         const char *list = ServerPrefStr (serv, CO_XMPP_PRIV);
1375         if (list)
1376             XMPPSendIqPrivacy (serv, p_active, list);
1377     }
1378 }
1379
1380 static int XmppSessionResult (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1381 {
1382     Server *serv = (Server *)fserv;
1383     if (pak->subtype != IKS_TYPE_RESULT)
1384         XmppStreamError (serv, s_sprintf ("Couldn't get session %s.", iks_string (iks_stack (pak->x), pak->x)));
1385     else
1386         XmppLoggedIn (serv);
1387     return IKS_FILTER_EAT;
1388 }
1389
1390 static int XmppUserResult (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1391 {
1392     Server *serv = (Server *)fserv;
1393     rl_printf ("Message %s resulted in:\n%s\n", pak->id, iks_string (iks_stack (pak->x), pak->x));
1394     return IKS_FILTER_EAT;
1395 }
1396
1397 static int XmppBindResult (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
1398 {
1399     Server *serv = (Server *)fserv;
1400     if (pak->subtype == IKS_TYPE_RESULT)
1401     {
1402         iks *bind = iks_find_with_attrib (pak->x, "bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
1403         char *newjid;
1404         if  (bind && (newjid = iks_find_cdata (bind, "jid")))
1405         {
1406             iksid *newid = iks_id_new (iks_parser_stack (serv->xmpp_parser), newjid);
1407             if (strchr (serv->screen,  '/'))
1408                 s_repl (&serv->screen, s_sprintf ("%s/%s", newid->partial, strchr (serv->screen,  '/')  + 1));
1409             else
1410                 s_repl (&serv->screen, newid->partial);
1411             if (strcmp (serv->xmpp_id->partial, newid->partial))
1412                 rl_printf ("Server changed JID from %s to %s.\n", serv->xmpp_id->partial, newid->partial);
1413             serv->xmpp_id = newid;
1414         }
1415     } else
1416         XmppStreamError (serv, s_sprintf ("Couldn't bind. %s", iks_string (iks_stack (pak->x), pak->x)));
1417     return IKS_FILTER_EAT;
1418 }
1419
1420 #if LIBIKS_VERSION < 0x0103 || defined(ENABLE_AUTOPACKAGE)
1421 static char *base64_encode (const char *data, int count)
1422 {
1423     char *base64 = iks_base64_encode (data, count);
1424     char *b64 = strdup (base64);
1425     int len = strlen (b64);
1426     iks_free (base64);
1427     while ((len % 3) && b64[len - 1] == '=')
1428       len--;
1429     b64[len] = 0;
1430     return b64;
1431 }
1432
1433 void replace_iks_start_sasl (iksparser *prs, char *user, char *password)
1434 {
1435     char *base64 = base64_encode (s_sprintf ("%c%s%c%s", 0, user, 0, password), strlen (user) + strlen (password) + 2);
1436     iks_send_raw (prs, s_sprintf ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">%s</auth>", base64));
1437     free (base64);
1438 }
1439 #endif
1440
1441 static int XmppStreamHook (IKS_TRANS_USER_DATA *userv, int type, iks *node)
1442 {
1443     Server *serv = (Server *)userv;
1444     iksparser *prs = serv->xmpp_parser;
1445     switch (type)
1446     {
1447         case IKS_NODE_STOP:
1448             XmppStreamError (serv, s_sprintf ("server disconnect [%s]", iks_name (iks_first_tag (node))));
1449             if (node) iks_delete (node);
1450             return IKS_NET_DROPPED;
1451         case IKS_NODE_ERROR:
1452             if (!strcmp (iks_name (iks_first_tag (node)), "conflict"))
1453                 OptSetVal (&serv->copts, CO_AUTOTAGRES, 1);
1454             XmppStreamError (serv, s_sprintf ("stream error [%s]", iks_name (iks_first_tag (node))));
1455             if (node) iks_delete (node);
1456             return IKS_NET_DROPPED;
1457         case IKS_NODE_START:
1458             // nothing to do with it
1459             break;
1460         case IKS_NODE_NORMAL:
1461             if (!strcmp ("stream:features", iks_name (node)))
1462             {
1463                 int feat = iks_stream_features (node);
1464                 if (feat & IKS_STREAM_STARTTLS && UtilIOSSLSupported() == IO_SSL_OK)
1465                     iks_send_raw (prs, "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
1466                 else if (feat & IKS_STREAM_SASL_MD5)
1467                     iks_start_sasl (prs, IKS_SASL_DIGEST_MD5, serv->xmpp_id->user, serv->passwd);
1468                 else if (feat & IKS_STREAM_SASL_PLAIN)
1469 #if LIBIKS_VERSION < 0x0103 || defined(USE_AUTOPACKAGE)
1470                     replace_iks_start_sasl (prs, serv->xmpp_id->user, serv->passwd);
1471 #else
1472                     iks_start_sasl (prs, IKS_SASL_PLAIN, serv->xmpp_id->user, serv->passwd);
1473 #endif
1474                 else
1475                 {
1476                     if (feat & (IKS_STREAM_BIND | IKS_STREAM_SESSION))
1477                     {
1478                         if (serv->xmpp_filter)
1479                             iks_filter_delete (serv->xmpp_filter);
1480                         serv->xmpp_filter = iks_filter_new ();
1481                         iks_filter_add_rule (serv->xmpp_filter, XmppUnknown, serv, IKS_RULE_DONE);
1482                         if (feat & IKS_STREAM_BIND)
1483                         {
1484                             iks *t = iks_make_resource_bind (serv->xmpp_id);
1485                             iks_insert_attrib (t, "id", "bind");
1486                             iks_filter_add_rule (serv->xmpp_filter, XmppBindResult, serv,
1487                                 IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_ID, "bind", IKS_RULE_DONE);
1488                             iks_send (prs, t);
1489                             iks_delete (t);
1490                         }
1491                         if (feat & IKS_STREAM_SESSION)
1492                         {
1493                             iks *t = iks_make_session ();
1494                             iks_insert_attrib (t, "id", "auth");
1495                             iks_filter_add_rule (serv->xmpp_filter, XmppSessionResult, serv,
1496                                 IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1497                             iks_send (prs, t);
1498                             iks_delete (t);
1499                         }
1500                     }
1501                     else
1502                         XmppLoggedIn (serv);
1503                 }
1504             }
1505             else if (strcmp ("failure", iks_name (node)) == 0)
1506                 XmppStreamError (serv, "sasl authentication failed");
1507             else if (strcmp ("success", iks_name (node)) == 0)
1508                 iks_send_header (prs, serv->xmpp_id->server);
1509             else if (strcmp ("proceed", iks_name (node)) == 0)
1510             {
1511                 io_ssl_err_t rce = UtilIOSSLOpen (serv->conn, 2);
1512                 if (rce != IO_SSL_OK)
1513                 {
1514                     XmppStreamError (serv, s_sprintf ("ssl error %d %s", rce, UtilIOErr (serv->conn)));
1515                     return IKS_NET_RWERR;
1516                 }
1517                 serv->conn->connect &= ~CONNECT_OK & ~4;
1518                 return IKS_OK;
1519             }
1520             else
1521             {
1522                 ikspak *pak = iks_packet (node);
1523                 iks_filter_packet (serv->xmpp_filter, pak);
1524             }
1525     }
1526     if (node) iks_delete (node);
1527     return IKS_OK;
1528 }
1529
1530 static void XMPPCallbackDispatch (Connection *conn)
1531 {
1532     iksparser *prs = conn->serv->xmpp_parser;
1533     io_err_t rce;
1534     char *semi;
1535     const char *sp;
1536     int rc;
1537
1538     if (!(conn->connect & (CONNECT_OK | 4)))
1539     {
1540         rc = UtilIORead (conn, NULL, 0);
1541         rce = UtilIOShowError (conn, rc);
1542         switch (rce) {
1543             case IO_RW:
1544                 semi = strchr (conn->server, ';');
1545                 if (!semi)
1546                     return;
1547                 memmove (conn->server, semi + 1, strlen (semi));
1548                 semi = strchr (conn->server, ';');
1549                 if (semi)
1550                     *semi = 0;
1551                 sp = s_sprintf ("%s", s_wordquote (strchr (conn->server, ':') ? conn->server : s_sprintf ("%s:%lu", conn->server, conn->port)));
1552                 rl_printf (i18n (2620, "Opening XMPP connection for %s at %s...\n"),
1553                     s_wordquote (conn->serv->screen), sp);
1554                 if (semi)
1555                     *semi = ';';
1556                 UtilIOConnectTCP (conn);
1557                 return;
1558             case IO_OK:
1559                 return;
1560             case IO_CONNECTED:
1561                 rl_print ("");
1562                 if (prG->verbose || (conn->serv && conn == conn->serv->conn))
1563                     if (rl_pos () > 0)
1564                          rl_print (i18n (1634, "ok.\n"));
1565
1566                 if (conn->port == 443 || conn->port == 5223)
1567                 {
1568                     io_ssl_err_t rce = UtilIOSSLOpen (conn, 2);
1569                     if (rce != IO_SSL_OK)
1570                     {
1571                         XmppStreamError (conn->serv, s_sprintf ("ssl error %d %s", rce, UtilIOErr (conn)));
1572                         EventD (QueueDequeue2 (conn, QUEUE_DEP_WAITLOGIN, 0, NULL));
1573                         return;
1574                     }
1575                 }
1576
1577                 if (!conn->serv->xmpp_parser)
1578                 {
1579                     prs = iks_stream_new (IKS_NS_CLIENT, conn->serv, &XmppStreamHook);
1580                     conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs), conn->serv->screen);
1581                     if (!conn->serv->xmpp_id->resource)
1582                         conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs),
1583                             s_sprintf ("%s@%s/climm", conn->serv->xmpp_id->user, conn->serv->xmpp_id->server));
1584                     if (ServerPrefVal (conn->serv, CO_TAGRESSOURCE) || ServerPrefVal (conn->serv, CO_AUTOTAGRES))
1585                         conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs),
1586                             s_sprintf ("%s/%s%04X%04X", conn->serv->xmpp_id->partial, conn->serv->xmpp_id->resource, rand() % 0xffff, rand() % 0xffff));
1587                     iks_set_log_hook (prs, XmppSaveLog);
1588                 }
1589                 conn->serv->xmpp_parser = prs;
1590                 rc = iks_connect_with (prs, conn->server, conn->port, conn->serv->xmpp_id->server, &iks_climm_transport);
1591                 if (rc != IKS_OK)
1592                 {
1593                     XmppStreamError (conn->serv, "could not send stream header");
1594                     return;
1595                 }
1596                 conn->connect |= 4;
1597                 return;
1598             default:
1599                 assert (0);
1600         }
1601     }
1602     rc = iks_recv (prs, 0);
1603     if (rc != IKS_OK && conn->dispatcher)
1604         XmppStreamError (conn->serv, s_sprintf ("failing with error code %d", rc));
1605     if (!conn->dispatcher)
1606         IMCallBackReconn (conn);
1607 }
1608
1609 void XMPPLogout (Server *serv)
1610 {
1611     if (serv->xmpp_parser)
1612     {
1613         iksparser *prs = serv->xmpp_parser;
1614         serv->xmpp_parser = NULL;
1615         iks_disconnect (prs);
1616         iks_parser_delete (prs);
1617         serv->xmpp_id = NULL;
1618         serv->xmpp_filter = NULL;
1619     }
1620     QueueCancel (serv->conn);
1621     UtilIOClose (serv->conn);
1622 }
1623
1624 /* **************** */
1625
1626 static void SnacCallbackXmpp (Event *event)
1627 {
1628     Message *msg = (Message *)event->data;
1629
1630     assert (event);
1631     assert (msg);
1632     assert (event->cont);
1633
1634     if (event->attempts < 5)
1635     {
1636         if (msg->send_message && !msg->otrinjected)
1637         {
1638             msg->type = INT_MSGACK_V8;
1639 //            IMIntMsgMsg (msg, NOW, ims_offline);
1640         }
1641         event->attempts = 20;
1642         event->due = time (NULL) + 600;
1643         QueueEnqueue (event);
1644     }
1645     else
1646     {
1647         MsgD (msg);
1648         event->data = NULL;
1649         EventD (event);
1650     }
1651 }
1652
1653 static void SnacCallbackXmppCancel (Event *event)
1654 {
1655     Message *msg = (Message *)event->data;
1656     if (msg->send_message && !msg->otrinjected)
1657         rl_printf (i18n (2234, "Message %s discarded - lost session.\n"),
1658     msg->plain_message ? msg->plain_message : msg->send_message);
1659     MsgD (msg);
1660     event->data = NULL;
1661     EventD (event);
1662 }
1663
1664 UBYTE XMPPSendmsg (Server *serv, Contact *cont, Message *msg)
1665 {
1666     iks *x, *xx;
1667     Event *event;
1668
1669     assert (cont);
1670     assert (msg->send_message);
1671
1672     if (~serv->conn->connect & CONNECT_OK)
1673         return RET_DEFER;
1674     if (msg->type != MSG_NORM)
1675         return RET_DEFER;
1676
1677     x = iks_make_msg (IKS_TYPE_CHAT, cont->screen, msg->send_message);
1678     iks_insert_attrib (x, "id", s_sprintf ("xmpp-%s-%x", serv->xmpp_stamp, ++serv->xmpp_sequence));
1679     iks_insert_attrib (x, "from", serv->xmpp_id->full);
1680     xx = iks_insert (x, "x");
1681     iks_insert_attrib (xx, "xmlns", "jabber:x:event");
1682     iks_insert (xx, "offline");
1683     iks_insert (xx, "delivered");
1684     iks_insert (xx, "displayed");
1685     iks_insert (xx, "composing");
1686     iks_send (serv->xmpp_parser, x);
1687     iks_delete (x);
1688
1689     event = QueueEnqueueData2 (serv->conn, QUEUE_XMPP_RESEND_ACK, serv->xmpp_sequence, 120, msg, &SnacCallbackXmpp, &SnacCallbackXmppCancel);
1690     event->cont = cont;
1691
1692     return RET_OK;
1693 }
1694
1695 void XMPPSetstatus (Server *serv, Contact *cont, status_t status, const char *msg)
1696 {
1697     enum ikshowtype p = StatusToIksstatus (&status);
1698     iks *x = iks_make_pres (p, msg);
1699     if (p != IKS_SHOW_UNAVAILABLE)
1700     {
1701         iks *caps = iks_insert (x, "c");
1702         iks_insert_attrib (caps, "xmlns", "http://jabber.org/protocol/caps");
1703         iks_insert_attrib (caps, "node", "http://www.climm.org/xmpp/caps");
1704         iks_insert_attrib (caps, "ver", BuildVersionStr);
1705         iks_insert_cdata (iks_insert (x, "priority"), "5", 0);
1706     }
1707     if (cont)
1708         iks_insert_attrib (x, "to", cont->screen);
1709     else
1710     {
1711         s_repl (&serv->conn->cont->status_message, msg);
1712         serv->status = status;
1713         serv->nativestatus = p;
1714     }
1715     iks_send (serv->xmpp_parser, x);
1716     iks_delete (x);
1717 }
1718
1719 UBYTE XMPPSendIq (Server *serv, int8_t which, const char *screen, const char *msg)
1720 {
1721     int err;
1722     iks *child = iks_tree (msg, 0, &err), *x;
1723     const char *id;
1724     if (!child)
1725         return RET_FAIL;
1726     id = s_sprintf ("user-%s-%x", serv->xmpp_stamp, ++serv->xmpp_sequence);
1727     iks_filter_add_rule (serv->xmpp_filter, XmppUserResult, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_ID, id, IKS_RULE_DONE);
1728     x = iks_new_within ("iq", iks_stack (child));
1729     iks_insert_attrib (x, "type", which ? "set" : "get");
1730     iks_insert_attrib (x, "id", id);
1731     iks_insert_attrib (x, "from", serv->xmpp_id->full);
1732     if (screen && *screen)
1733         iks_insert_attrib (x, "to", screen);
1734     iks_insert_node (x, child);
1735     iks_send (serv->xmpp_parser, x);
1736     iks_delete (x);
1737     return RET_OK;
1738 }
1739
1740 void XMPPAuthorize (Server *serv, Contact *cont, auth_t how, const char *msg)
1741 {
1742     iks *x;
1743     while (cont->parent && cont->parent->serv == cont->serv)
1744         cont = cont->parent;
1745
1746     x = iks_make_s10n (how == auth_grant ? IKS_TYPE_SUBSCRIBED
1747                      : how == auth_deny  ? IKS_TYPE_UNSUBSCRIBED
1748                      : how == auth_req   ? IKS_TYPE_SUBSCRIBE
1749                                          : IKS_TYPE_UNSUBSCRIBE,
1750                        cont->screen, msg);
1751     iks_send (serv->xmpp_parser, x);
1752     iks_delete (x);
1753 }
1754
1755 void XMPPGoogleMail (Server *serv, time_t since, const char *query)
1756 {
1757     assert (query);
1758     if (since == 1)
1759         XmppSendIqGmail (serv, serv->xmpp_gmail_newer, serv->xmpp_gmail_newertid, serv->xmpp_gmail_query);
1760     else
1761         XmppSendIqGmail (serv, since * 1000ULL, NULL, query);
1762     s_repl (&serv->xmpp_gmail_query, query);
1763 }
1764
1765 void XMPPPrivacy (Server *serv, xmpp_priv_t type, const char *list, const char *edit)
1766 {
1767     if (type == p_edit)
1768     {
1769         if (!list)
1770             return;
1771         if (!serv->xmpp_privacy_list || strcmp (list, serv->xmpp_privacy_list))
1772         {
1773             s_repl (&serv->xmpp_privacy_list, NULL);
1774             s_repl (&serv->xmpp_privacy_items, NULL);
1775         }
1776         if (!serv->xmpp_privacy_items)
1777         {
1778             XMPPPrivacy (serv, p_show_quiet, list, NULL);
1779             rl_printf (i18n (2768, "Fetching privacy list (was not cached), please try again.\n"));
1780             return;
1781         }
1782     }
1783     if (type == p_edit || type == p_set)
1784         XMPPSendIqPrivacyEdit (serv, type, list, edit ? edit : "");
1785     else
1786         XMPPSendIqPrivacy (serv, type, list);
1787 }
1788
1789 #if 0
1790 class CLIMMXMPP: public gloox::ConnectionListener, public gloox::MessageHandler,
1791     private :
1792         void handleXEP8 (gloox::Tag *t);
1793         void handleXEP27 (gloox::Tag *t);
1794         void handleXEP71 (gloox::Tag *t);
1795         void handleXEP153 (gloox::Tag *t, Contact *contr);
1796         void handleGoogleNosave (gloox::Tag *t);
1797         void handleGoogleSig (gloox::Tag *t);
1798         void handleGoogleChatstate (gloox::Tag *t);
1799         void handleXEP136 (gloox::Tag *t);
1800         virtual void handleSubscription (gloox::Stanza *stanza);
1801 };
1802
1803 static bool DropChild (gloox::Tag *s, gloox::Tag *c)
1804 {
1805     if (s->children().size())
1806         s->setCData ("");
1807     s->children().remove (c);
1808     delete c;
1809 }
1810
1811 static bool DropAttrib (gloox::Tag *s, const std::string &a)
1812 {
1813     if (s->children().size())
1814         s->setCData ("");
1815 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1816     s->attributes().remove (gloox::Tag::Attribute (a, s->findAttribute (a)));
1817 #else
1818     s->attributes().erase (a);
1819 #endif
1820 }
1821
1822 static bool DropCData (gloox::Tag *s)
1823 {
1824     s->setCData ("");
1825 }
1826
1827 static bool CheckInvalid (gloox::Tag *s)
1828 {
1829     if (!s->attributes().size() && !s->children().size() && s->cdata().empty())
1830     {
1831         if (s->parent())
1832             DropChild (s->parent(), s);
1833         return true;
1834     }
1835     return false;
1836 }
1837
1838 static void DropAllChilds (gloox::Tag *s, const std::string &a)
1839 {
1840     gloox::Tag::TagList::const_iterator it;
1841     for (it = s->children().begin(); it != s->children().end(); ++it)
1842     {
1843         if ((*it)->name() == a)
1844         {
1845             gloox::Tag *b = *it;
1846             DropCData (b);
1847             DropAttrib (b, "xml:lang");
1848             if (CheckInvalid (b))
1849                 return (DropAllChilds (s, a));
1850         }
1851     }
1852 }
1853
1854 static void DropAllChildsTree (gloox::Tag *s, const std::string &a)
1855 {
1856     gloox::Tag::TagList::const_iterator it;
1857     if (a.empty ())
1858     {
1859         s->attributes().clear();
1860         for (it = s->children().begin(); it != s->children().end(); it = s->children().begin())
1861         {
1862             gloox::Tag *b = *it;
1863             DropCData (b);
1864             DropAllChildsTree (b, "");
1865             CheckInvalid (b);
1866         }
1867     }
1868     else
1869     {
1870         for (it = s->children().begin(); it != s->children().end(); ++it)
1871         {
1872             while ((*it)->name() == a)
1873             {
1874                 gloox::Tag *b = *it;
1875                 DropCData (b);
1876                 DropAllChildsTree (b, "");
1877                 CheckInvalid (b);
1878                 it = s->children().begin();
1879             }
1880         }
1881     }
1882 }
1883
1884 void CLIMMXMPP::handleXEP8 (gloox::Tag *t)
1885 {
1886     if (gloox::Tag *avatar = find_with_ns_attrib (t, "x", "jabber:x:avatar"))
1887     {
1888         if (gloox::Tag *hash = avatar->findChild ("hash"))
1889         {
1890             DropCData (hash);
1891             CheckInvalid (hash);
1892         }
1893         CheckInvalid (avatar);
1894     }
1895 }
1896
1897 void CLIMMXMPP::handleXEP27 (gloox::Tag *t)
1898 {
1899     if (gloox::Tag *sig = find_with_ns_attrib (t, "x", "jabber:x:signed"))
1900     {
1901         DropCData (sig);
1902         CheckInvalid (sig);
1903     }
1904 }
1905
1906 void CLIMMXMPP::handleXEP71 (gloox::Tag *t)
1907 {
1908     if (gloox::Tag *xhtmlim = find_with_ns_attrib (t, "html", "http://jabber.org/protocol/xhtml-im"))
1909     {
1910         DropAllChildsTree (xhtmlim, "body");
1911         CheckInvalid (xhtmlim);
1912     }
1913 }
1914
1915 void CLIMMXMPP::handleXEP136 (gloox::Tag *t)
1916 {
1917     if (gloox::Tag *arc = find_with_ns_attrib (t, "record", "http://jabber.org/protocol/archive"))
1918     {
1919         DropAttrib (arc, "otr");
1920         CheckInvalid (arc);
1921     }
1922 }
1923
1924 void CLIMMXMPP::handleXEP153 (gloox::Tag *t, Contact *contr)
1925 {
1926     if (gloox::Tag *vcard = find_with_ns_attrib (t, "x", "vcard-temp:x:update"))
1927     {
1928         if (gloox::Tag *photo = vcard->findChild ("photo"))
1929         {
1930             DropCData (photo);
1931             CheckInvalid (photo);
1932         }
1933         if (gloox::Tag *nick = vcard->findChild ("nickname"))
1934         {
1935             std::string nickname = nick->cdata();
1936             ContactAddAlias (contr, nickname.c_str());
1937             DropCData (nick);
1938             CheckInvalid (nick);
1939         }
1940         CheckInvalid (vcard);
1941     }
1942 }
1943
1944 void CLIMMXMPP::handleGoogleNosave (gloox::Tag *t)
1945 {
1946     if (gloox::Tag *nosave = find_with_ns_attrib (t, "x", "google:nosave"))
1947     {
1948         DropAttrib (nosave, "value");
1949         CheckInvalid (nosave);
1950     }
1951 }
1952
1953 void CLIMMXMPP::handleGoogleSig (gloox::Tag *t)
1954 {
1955     if (gloox::Tag *sig = find_with_ns_attrib (t, "google-mail-signature", "google:metadata"))
1956     {
1957         DropCData (sig);
1958         CheckInvalid (sig);
1959     }
1960 }
1961
1962 void CLIMMXMPP::handleGoogleChatstate(gloox::Tag *t)
1963 {
1964     if (gloox::Tag *chat = find_with_ns_attrib (t, "active", "http://jabber.org/protocol/chatstates"))
1965         CheckInvalid (chat);
1966 }
1967
1968
1969 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1970 void CLIMMXMPP::handleMessage (gloox::Stanza *s, gloox::MessageSession *session)
1971 #else
1972 void CLIMMXMPP::handleMessage (gloox::Stanza *s)
1973 #endif
1974 {
1975     assert (s);
1976     assert (s->type() == gloox::StanzaMessage);
1977
1978 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1979     gloox::Stanza *t = new gloox::Stanza (s);
1980 #else
1981     gloox::Stanza *t = s->clone();
1982 #endif
1983
1984     if (t->subtype() == gloox::StanzaMessageError)
1985         DropAllChildsTree (t, "");
1986     else
1987         handleMessage2 (t, s->from(), s->to().full(), s->id(), s->subtype ());
1988
1989     DropAttrib (t, "from");
1990     DropAttrib (t, "to");
1991     DropAttrib (t, "id");
1992     DropAttrib (t, "xml:lang");
1993     if (t->hasAttribute ("xmlns", "jabber:client"))
1994         DropAttrib (t, "xmlns");
1995     if (!CheckInvalid (t))
1996     {
1997         std::string txml = t->xml();
1998         CLIMMXMPPSave (m_serv, txml.c_str(), 3);
1999     }
2000     delete t;
2001 }
2002
2003 void CLIMMXMPP::handlePresence (gloox::Stanza *s)
2004 {
2005     assert (s);
2006     assert (s->type() == gloox::StanzaPresence);
2007
2008 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
2009     gloox::Stanza *t = new gloox::Stanza(s);
2010 #else
2011     gloox::Stanza *t = s->clone();
2012 #endif
2013
2014     if (t->subtype() == gloox::StanzaPresenceError)
2015         DropAllChildsTree (t, "");
2016     else
2017         handlePresence2 (t, s->from(), s->to(), s->status());
2018
2019     DropAttrib (t, "from");
2020     DropAttrib (t, "to");
2021     DropAttrib (t, "id");
2022     DropAttrib (t, "xml:lang");
2023     if (t->hasAttribute ("xmlns", "jabber:client"))
2024         DropAttrib (t, "xmlns");
2025     DropAllChilds (t, "status");
2026
2027     if (!CheckInvalid (t))
2028     {
2029         std::string txml = t->xml();
2030         CLIMMXMPPSave (m_serv, txml.c_str(), 3);
2031     }
2032     delete t;
2033 }
2034
2035 void CLIMMXMPP::handleSubscription (gloox::Stanza *s)
2036 {
2037     assert (s);
2038     assert (s->type() == gloox::StanzaS10n);
2039     rl_printf ("handleSubscription from:<%s> to:<%s> type:<%d> id:<%s> status:<%s> prio:<%d> body:<%s> subj:<%s> thread:<%s> pres:<%d> xml:<%s>\n",
2040                s->from().full().c_str(), s->to().full().c_str(), s->subtype(),
2041                s->id().c_str(), s->status().c_str(), s->priority(),
2042                s->body().c_str(), s->subject().c_str(),
2043 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
2044                s->thread().c_str(), s->presence(),
2045 #else
2046                s->thread().c_str(), s->show(),
2047 #endif
2048                s->xml().c_str());
2049 }
2050 #endif
2051
2052 #endif
Note: See TracBrowser for help on using the browser.