1 /*
2  * Implements the XMPP protocol using libiksemel >= 1.2.
3  *
4  * climm Copyright (C) © 2001-2010 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: xmpp_base.c 2883 2010-03-20 13:56:35Z kuhlmann $
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 
iks_climm_TConnect(iksparser * prs,IKS_SOCK_USER_DATA ** socketptr,const char * server,int port)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 
iks_climm_TClose(IKS_SOCK_USER_DATA * conn)82 static void iks_climm_TClose (IKS_SOCK_USER_DATA *conn)
83 {
84     UtilIOClose ((Connection *)conn);
85 }
86 
iks_climm_TSend(IKS_SOCK_USER_DATA * conn,const char * data,size_t len)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 
iks_climm_TRecv(IKS_SOCK_USER_DATA * conn,char * data,size_t len,int timeout)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 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 
XMPPCallBackTimeout(Event * event)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 
XmppStreamError(Server * serv,const char * text)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 
XMPPLogin(Server * serv)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 
XmppSaveLog(IKS_TRANS_USER_DATA * userv,const char * text,size_t size,int in)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 
GetBothContacts(iksid * j,Server * conn,Contact ** b,Contact ** f,char crea)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 
find_with_ns_attrib(iks * tag,const char * childname,const char * childnamespace)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 
StatusToIksstatus(status_t * status)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 
XmppSendIqGmail(Server * serv,int64_t newer,const char * newertid,const char * query)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 
XmppSendIqTime(Server * serv)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 
xmpp_make_iq_privacy(Server * serv,xmpp_priv_t ntype,const char * list)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 
XMPPSendIqPrivacy(Server * serv,xmpp_priv_t ntype,const char * list)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 
xmpp_uint_compare(const char * a,const char * b)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 
xmpp_uint_add(const char * a,const char * b)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 
XMPPSendIqPrivacyEdit(Server * serv,xmpp_priv_t ntype,const char * list,const char * edit)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 = strdup ("1");
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 
sendIqGmailReqs(Event * event)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 
sendIqTimeReqs(Event * event)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 
XmppHandleIqGmail(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandleIqDisco(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandleIqXEP12(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandleIqXEP92(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandleIqRoster(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandleIqPrivacy(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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", (int)(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 
XmppHandleIqTime(IKS_FILTER_USER_DATA * fserv,ikspak * pak)907 static int XmppHandleIqTime (IKS_FILTER_USER_DATA *fserv, ikspak *pak)
908 {
909     return IKS_FILTER_EAT;
910 }
911 
XmppHandleIqDefault(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
__SkipChar(const char ** s,char c)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 
ParseUTCDate(const char * s)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 
XmppHandleXEP91(iks * x)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 
XmppHandleXEP115(iks * x,Contact * contr)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 
XmppHandleXEP22a(Server * serv,iks * x,Contact * cfrom)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 
XmppHandleXEP22c(Server * serv,iksid * from,char * tof,char * id,char * type)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 
XmppHandleXEP22b(Server * serv,iks * x,iksid * from,char * tof,char * id)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 
XmppHandleXEP22(Server * serv,iks * t,Contact * cfrom,iksid * from,char * tof,char * id)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 
XmppHandleXEP85(Server * serv,iks * t,Contact * cfrom,iksid * from,char * tof,char * id)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 
XmppHandleMessage(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandlePresenceErr(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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  */
XmppHandleSubscription(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppHandlePresence(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppUnknown(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppLoggedIn(Server * serv)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 
XmppSessionResult(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppUserResult(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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 
XmppBindResult(IKS_FILTER_USER_DATA * fserv,ikspak * pak)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)
base64_encode(const char * data,int count)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 
replace_iks_start_sasl(iksparser * prs,char * user,char * password)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 
XmppStreamHook(IKS_TRANS_USER_DATA * userv,int type,iks * node)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             {
1507                 s_repl (&serv->passwd, NULL);
1508                 XmppStreamError (serv, "sasl authentication failed");
1509             }
1510             else if (strcmp ("success", iks_name (node)) == 0)
1511                 iks_send_header (prs, serv->xmpp_id->server);
1512             else if (strcmp ("proceed", iks_name (node)) == 0)
1513             {
1514                 io_ssl_err_t rce = UtilIOSSLOpen (serv->conn, 2);
1515                 if (rce != IO_SSL_OK)
1516                 {
1517                     XmppStreamError (serv, s_sprintf ("ssl error %d %s", rce, UtilIOErr (serv->conn)));
1518                     return IKS_NET_RWERR;
1519                 }
1520                 serv->conn->connect &= ~CONNECT_OK & ~4;
1521                 return IKS_OK;
1522             }
1523             else
1524             {
1525                 ikspak *pak = iks_packet (node);
1526                 iks_filter_packet (serv->xmpp_filter, pak);
1527             }
1528     }
1529     if (node) iks_delete (node);
1530     return IKS_OK;
1531 }
1532 
XMPPCallbackDispatch(Connection * conn)1533 static void XMPPCallbackDispatch (Connection *conn)
1534 {
1535     iksparser *prs = conn->serv->xmpp_parser;
1536     io_err_t rce;
1537     char *semi;
1538     const char *sp;
1539     int rc;
1540 
1541     if (!(conn->connect & (CONNECT_OK | 4)))
1542     {
1543         rc = UtilIORead (conn, NULL, 0);
1544         rce = UtilIOShowError (conn, rc);
1545         switch (rce) {
1546             case IO_RW:
1547                 semi = strchr (conn->server, ';');
1548                 if (!semi)
1549                     return;
1550                 memmove (conn->server, semi + 1, strlen (semi));
1551                 semi = strchr (conn->server, ';');
1552                 if (semi)
1553                     *semi = 0;
1554                 sp = s_sprintf ("%s", s_wordquote (strchr (conn->server, ':') ? conn->server : s_sprintf ("%s:%lu", conn->server, conn->port)));
1555                 rl_printf (i18n (2620, "Opening XMPP connection for %s at %s...\n"),
1556                     s_wordquote (conn->serv->screen), sp);
1557                 if (semi)
1558                     *semi = ';';
1559                 UtilIOConnectTCP (conn);
1560                 return;
1561             case IO_OK:
1562                 return;
1563             case IO_CONNECTED:
1564                 rl_print ("");
1565                 if (prG->verbose || (conn->serv && conn == conn->serv->conn))
1566                     if (rl_pos () > 0)
1567                          rl_print (i18n (1634, "ok.\n"));
1568 
1569                 if (conn->port == 443 || conn->port == 5223)
1570                 {
1571                     io_ssl_err_t rce = UtilIOSSLOpen (conn, 2);
1572                     if (rce != IO_SSL_OK)
1573                     {
1574                         XmppStreamError (conn->serv, s_sprintf ("ssl error %d %s", rce, UtilIOErr (conn)));
1575                         EventD (QueueDequeue2 (conn, QUEUE_DEP_WAITLOGIN, 0, NULL));
1576                         return;
1577                     }
1578                 }
1579 
1580                 if (!conn->serv->xmpp_parser)
1581                 {
1582                     prs = iks_stream_new (IKS_NS_CLIENT, conn->serv, &XmppStreamHook);
1583                     conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs), conn->serv->screen);
1584                     if (!conn->serv->xmpp_id->resource)
1585                         conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs),
1586                             s_sprintf ("%s@%s/climm", conn->serv->xmpp_id->user, conn->serv->xmpp_id->server));
1587                     if (ServerPrefVal (conn->serv, CO_TAGRESSOURCE) || ServerPrefVal (conn->serv, CO_AUTOTAGRES))
1588                         conn->serv->xmpp_id = iks_id_new (iks_parser_stack (prs),
1589                             s_sprintf ("%s/%s%04X%04X", conn->serv->xmpp_id->partial, conn->serv->xmpp_id->resource, rand() % 0xffff, rand() % 0xffff));
1590                     iks_set_log_hook (prs, XmppSaveLog);
1591                 }
1592                 conn->serv->xmpp_parser = prs;
1593                 rc = iks_connect_with (prs, conn->server, conn->port, conn->serv->xmpp_id->server, &iks_climm_transport);
1594                 if (rc != IKS_OK)
1595                 {
1596                     XmppStreamError (conn->serv, "could not send stream header");
1597                     return;
1598                 }
1599                 conn->connect |= 4;
1600                 return;
1601             default:
1602                 assert (0);
1603         }
1604     }
1605     conn->connect |= 0x40;
1606     rc = iks_recv (prs, 0);
1607     conn->connect &= ~0x40;
1608     if (rc != IKS_OK && conn->dispatcher)
1609         XmppStreamError (conn->serv, s_sprintf ("failing with error code %d", rc));
1610     if (!conn->dispatcher)
1611         IMCallBackReconn (conn);
1612 }
1613 
XMPPLogout(Server * serv)1614 void XMPPLogout (Server *serv)
1615 {
1616     if (serv->xmpp_parser && ~serv->conn->connect & 0x40)
1617     {
1618         iksparser *prs = serv->xmpp_parser;
1619         serv->xmpp_parser = NULL;
1620         iks_disconnect (prs);
1621         iks_parser_delete (prs);
1622         serv->xmpp_id = NULL;
1623         serv->xmpp_filter = NULL;
1624     }
1625     QueueCancel (serv->conn);
1626     UtilIOClose (serv->conn);
1627 }
1628 
1629 /* **************** */
1630 
SnacCallbackXmpp(Event * event)1631 static void SnacCallbackXmpp (Event *event)
1632 {
1633     Message *msg = (Message *)event->data;
1634 
1635     assert (event);
1636     assert (msg);
1637     assert (event->cont);
1638 
1639     if (event->attempts < 5)
1640     {
1641         if (msg->send_message && !msg->otrinjected)
1642         {
1643             msg->type = INT_MSGACK_V8;
1644 //            IMIntMsgMsg (msg, NOW, ims_offline);
1645         }
1646         event->attempts = 20;
1647         event->due = time (NULL) + 600;
1648         QueueEnqueue (event);
1649     }
1650     else
1651     {
1652         MsgD (msg);
1653         event->data = NULL;
1654         EventD (event);
1655     }
1656 }
1657 
SnacCallbackXmppCancel(Event * event)1658 static void SnacCallbackXmppCancel (Event *event)
1659 {
1660     Message *msg = (Message *)event->data;
1661     if (msg->send_message && !msg->otrinjected)
1662         rl_printf (i18n (2234, "Message %s discarded - lost session.\n"),
1663     msg->plain_message ? msg->plain_message : msg->send_message);
1664     MsgD (msg);
1665     event->data = NULL;
1666     EventD (event);
1667 }
1668 
XMPPSendmsg(Server * serv,Contact * cont,Message * msg)1669 UBYTE XMPPSendmsg (Server *serv, Contact *cont, Message *msg)
1670 {
1671     iks *x, *xx;
1672     Event *event;
1673 
1674     assert (cont);
1675     assert (msg->send_message);
1676 
1677     if (~serv->conn->connect & CONNECT_OK)
1678         return RET_DEFER;
1679     if (msg->type != MSG_NORM)
1680         return RET_DEFER;
1681 
1682     x = iks_make_msg (IKS_TYPE_CHAT, cont->screen, msg->send_message);
1683     iks_insert_attrib (x, "id", s_sprintf ("xmpp-%s-%x", serv->xmpp_stamp, ++serv->xmpp_sequence));
1684     iks_insert_attrib (x, "from", serv->xmpp_id->full);
1685     xx = iks_insert (x, "x");
1686     iks_insert_attrib (xx, "xmlns", "jabber:x:event");
1687     iks_insert (xx, "offline");
1688     iks_insert (xx, "delivered");
1689     iks_insert (xx, "displayed");
1690     iks_insert (xx, "composing");
1691     iks_send (serv->xmpp_parser, x);
1692     iks_delete (x);
1693 
1694     event = QueueEnqueueData2 (serv->conn, QUEUE_XMPP_RESEND_ACK, serv->xmpp_sequence, 120, msg, &SnacCallbackXmpp, &SnacCallbackXmppCancel);
1695     event->cont = cont;
1696 
1697     return RET_OK;
1698 }
1699 
XMPPSetstatus(Server * serv,Contact * cont,status_t status,const char * msg)1700 void XMPPSetstatus (Server *serv, Contact *cont, status_t status, const char *msg)
1701 {
1702     enum ikshowtype p = StatusToIksstatus (&status);
1703     iks *x = iks_make_pres (p, msg);
1704     if (p != IKS_SHOW_UNAVAILABLE)
1705     {
1706         iks *caps = iks_insert (x, "c");
1707         iks_insert_attrib (caps, "xmlns", "http://jabber.org/protocol/caps");
1708         iks_insert_attrib (caps, "node", "http://www.climm.org/xmpp/caps");
1709         iks_insert_attrib (caps, "ver", BuildVersionStr);
1710         iks_insert_cdata (iks_insert (x, "priority"), "5", 0);
1711     }
1712     if (cont)
1713         iks_insert_attrib (x, "to", cont->screen);
1714     else
1715     {
1716         if (serv->conn->cont->status_message != msg)
1717             s_repl (&serv->conn->cont->status_message, msg);
1718         serv->status = status;
1719         serv->nativestatus = p;
1720     }
1721     iks_send (serv->xmpp_parser, x);
1722     iks_delete (x);
1723 }
1724 
XMPPSendIq(Server * serv,int8_t which,const char * screen,const char * msg)1725 UBYTE XMPPSendIq (Server *serv, int8_t which, const char *screen, const char *msg)
1726 {
1727     int err;
1728     iks *child = iks_tree (msg, 0, &err), *x;
1729     const char *id;
1730     if (!child)
1731         return RET_FAIL;
1732     id = s_sprintf ("user-%s-%x", serv->xmpp_stamp, ++serv->xmpp_sequence);
1733     iks_filter_add_rule (serv->xmpp_filter, XmppUserResult, serv, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_ID, id, IKS_RULE_DONE);
1734     x = iks_new_within ("iq", iks_stack (child));
1735     iks_insert_attrib (x, "type", which ? "set" : "get");
1736     iks_insert_attrib (x, "id", id);
1737     iks_insert_attrib (x, "from", serv->xmpp_id->full);
1738     if (screen && *screen)
1739         iks_insert_attrib (x, "to", screen);
1740     iks_insert_node (x, child);
1741     iks_send (serv->xmpp_parser, x);
1742     iks_delete (x);
1743     return RET_OK;
1744 }
1745 
XMPPAuthorize(Server * serv,Contact * cont,auth_t how,const char * msg)1746 void XMPPAuthorize (Server *serv, Contact *cont, auth_t how, const char *msg)
1747 {
1748     iks *x;
1749     while (cont->parent && cont->parent->serv == cont->serv)
1750         cont = cont->parent;
1751 
1752     x = iks_make_s10n (how == auth_grant ? IKS_TYPE_SUBSCRIBED
1753                      : how == auth_deny  ? IKS_TYPE_UNSUBSCRIBED
1754                      : how == auth_req   ? IKS_TYPE_SUBSCRIBE
1755                                          : IKS_TYPE_UNSUBSCRIBE,
1756                        cont->screen, msg);
1757     iks_send (serv->xmpp_parser, x);
1758     iks_delete (x);
1759 }
1760 
XMPPGoogleMail(Server * serv,time_t since,const char * query)1761 void XMPPGoogleMail (Server *serv, time_t since, const char *query)
1762 {
1763     assert (query);
1764     if (since == 1)
1765         XmppSendIqGmail (serv, serv->xmpp_gmail_newer, serv->xmpp_gmail_newertid, serv->xmpp_gmail_query);
1766     else
1767         XmppSendIqGmail (serv, since * 1000ULL, NULL, query);
1768     s_repl (&serv->xmpp_gmail_query, query);
1769 }
1770 
XMPPPrivacy(Server * serv,xmpp_priv_t type,const char * list,const char * edit)1771 void XMPPPrivacy (Server *serv, xmpp_priv_t type, const char *list, const char *edit)
1772 {
1773     if (type == p_edit)
1774     {
1775         if (!list)
1776             return;
1777         if (!serv->xmpp_privacy_list || strcmp (list, serv->xmpp_privacy_list))
1778         {
1779             s_repl (&serv->xmpp_privacy_list, NULL);
1780             s_repl (&serv->xmpp_privacy_items, NULL);
1781         }
1782         if (!serv->xmpp_privacy_items)
1783         {
1784             XMPPPrivacy (serv, p_show_quiet, list, NULL);
1785             rl_printf (i18n (2768, "Fetching privacy list (was not cached), please try again.\n"));
1786             return;
1787         }
1788     }
1789     if (type == p_edit || type == p_set)
1790         XMPPSendIqPrivacyEdit (serv, type, list, edit ? edit : "");
1791     else
1792         XMPPSendIqPrivacy (serv, type, list);
1793 }
1794 
1795 #if 0
1796 class CLIMMXMPP: public gloox::ConnectionListener, public gloox::MessageHandler,
1797     private :
1798         void handleXEP8 (gloox::Tag *t);
1799         void handleXEP27 (gloox::Tag *t);
1800         void handleXEP71 (gloox::Tag *t);
1801         void handleXEP153 (gloox::Tag *t, Contact *contr);
1802         void handleGoogleNosave (gloox::Tag *t);
1803         void handleGoogleSig (gloox::Tag *t);
1804         void handleGoogleChatstate (gloox::Tag *t);
1805         void handleXEP136 (gloox::Tag *t);
1806         virtual void handleSubscription (gloox::Stanza *stanza);
1807 };
1808 
1809 static bool DropChild (gloox::Tag *s, gloox::Tag *c)
1810 {
1811     if (s->children().size())
1812         s->setCData ("");
1813     s->children().remove (c);
1814     delete c;
1815 }
1816 
1817 static bool DropAttrib (gloox::Tag *s, const std::string &a)
1818 {
1819     if (s->children().size())
1820         s->setCData ("");
1821 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1822     s->attributes().remove (gloox::Tag::Attribute (a, s->findAttribute (a)));
1823 #else
1824     s->attributes().erase (a);
1825 #endif
1826 }
1827 
1828 static bool DropCData (gloox::Tag *s)
1829 {
1830     s->setCData ("");
1831 }
1832 
1833 static bool CheckInvalid (gloox::Tag *s)
1834 {
1835     if (!s->attributes().size() && !s->children().size() && s->cdata().empty())
1836     {
1837         if (s->parent())
1838             DropChild (s->parent(), s);
1839         return true;
1840     }
1841     return false;
1842 }
1843 
1844 static void DropAllChilds (gloox::Tag *s, const std::string &a)
1845 {
1846     gloox::Tag::TagList::const_iterator it;
1847     for (it = s->children().begin(); it != s->children().end(); ++it)
1848     {
1849         if ((*it)->name() == a)
1850         {
1851             gloox::Tag *b = *it;
1852             DropCData (b);
1853             DropAttrib (b, "xml:lang");
1854             if (CheckInvalid (b))
1855                 return (DropAllChilds (s, a));
1856         }
1857     }
1858 }
1859 
1860 static void DropAllChildsTree (gloox::Tag *s, const std::string &a)
1861 {
1862     gloox::Tag::TagList::const_iterator it;
1863     if (a.empty ())
1864     {
1865         s->attributes().clear();
1866         for (it = s->children().begin(); it != s->children().end(); it = s->children().begin())
1867         {
1868             gloox::Tag *b = *it;
1869             DropCData (b);
1870             DropAllChildsTree (b, "");
1871             CheckInvalid (b);
1872         }
1873     }
1874     else
1875     {
1876         for (it = s->children().begin(); it != s->children().end(); ++it)
1877         {
1878             while ((*it)->name() == a)
1879             {
1880                 gloox::Tag *b = *it;
1881                 DropCData (b);
1882                 DropAllChildsTree (b, "");
1883                 CheckInvalid (b);
1884                 it = s->children().begin();
1885             }
1886         }
1887     }
1888 }
1889 
1890 void CLIMMXMPP::handleXEP8 (gloox::Tag *t)
1891 {
1892     if (gloox::Tag *avatar = find_with_ns_attrib (t, "x", "jabber:x:avatar"))
1893     {
1894         if (gloox::Tag *hash = avatar->findChild ("hash"))
1895         {
1896             DropCData (hash);
1897             CheckInvalid (hash);
1898         }
1899         CheckInvalid (avatar);
1900     }
1901 }
1902 
1903 void CLIMMXMPP::handleXEP27 (gloox::Tag *t)
1904 {
1905     if (gloox::Tag *sig = find_with_ns_attrib (t, "x", "jabber:x:signed"))
1906     {
1907         DropCData (sig);
1908         CheckInvalid (sig);
1909     }
1910 }
1911 
1912 void CLIMMXMPP::handleXEP71 (gloox::Tag *t)
1913 {
1914     if (gloox::Tag *xhtmlim = find_with_ns_attrib (t, "html", "http://jabber.org/protocol/xhtml-im"))
1915     {
1916         DropAllChildsTree (xhtmlim, "body");
1917         CheckInvalid (xhtmlim);
1918     }
1919 }
1920 
1921 void CLIMMXMPP::handleXEP136 (gloox::Tag *t)
1922 {
1923     if (gloox::Tag *arc = find_with_ns_attrib (t, "record", "http://jabber.org/protocol/archive"))
1924     {
1925         DropAttrib (arc, "otr");
1926         CheckInvalid (arc);
1927     }
1928 }
1929 
1930 void CLIMMXMPP::handleXEP153 (gloox::Tag *t, Contact *contr)
1931 {
1932     if (gloox::Tag *vcard = find_with_ns_attrib (t, "x", "vcard-temp:x:update"))
1933     {
1934         if (gloox::Tag *photo = vcard->findChild ("photo"))
1935         {
1936             DropCData (photo);
1937             CheckInvalid (photo);
1938         }
1939         if (gloox::Tag *nick = vcard->findChild ("nickname"))
1940         {
1941             std::string nickname = nick->cdata();
1942             ContactAddAlias (contr, nickname.c_str());
1943             DropCData (nick);
1944             CheckInvalid (nick);
1945         }
1946         CheckInvalid (vcard);
1947     }
1948 }
1949 
1950 void CLIMMXMPP::handleGoogleNosave (gloox::Tag *t)
1951 {
1952     if (gloox::Tag *nosave = find_with_ns_attrib (t, "x", "google:nosave"))
1953     {
1954         DropAttrib (nosave, "value");
1955         CheckInvalid (nosave);
1956     }
1957 }
1958 
1959 void CLIMMXMPP::handleGoogleSig (gloox::Tag *t)
1960 {
1961     if (gloox::Tag *sig = find_with_ns_attrib (t, "google-mail-signature", "google:metadata"))
1962     {
1963         DropCData (sig);
1964         CheckInvalid (sig);
1965     }
1966 }
1967 
1968 void CLIMMXMPP::handleGoogleChatstate(gloox::Tag *t)
1969 {
1970     if (gloox::Tag *chat = find_with_ns_attrib (t, "active", "http://jabber.org/protocol/chatstates"))
1971         CheckInvalid (chat);
1972 }
1973 
1974 
1975 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1976 void CLIMMXMPP::handleMessage (gloox::Stanza *s, gloox::MessageSession *session)
1977 #else
1978 void CLIMMXMPP::handleMessage (gloox::Stanza *s)
1979 #endif
1980 {
1981     assert (s);
1982     assert (s->type() == gloox::StanzaMessage);
1983 
1984 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
1985     gloox::Stanza *t = new gloox::Stanza (s);
1986 #else
1987     gloox::Stanza *t = s->clone();
1988 #endif
1989 
1990     if (t->subtype() == gloox::StanzaMessageError)
1991         DropAllChildsTree (t, "");
1992     else
1993         handleMessage2 (t, s->from(), s->to().full(), s->id(), s->subtype ());
1994 
1995     DropAttrib (t, "from");
1996     DropAttrib (t, "to");
1997     DropAttrib (t, "id");
1998     DropAttrib (t, "xml:lang");
1999     if (t->hasAttribute ("xmlns", "jabber:client"))
2000         DropAttrib (t, "xmlns");
2001     if (!CheckInvalid (t))
2002     {
2003         std::string txml = t->xml();
2004         CLIMMXMPPSave (m_serv, txml.c_str(), 3);
2005     }
2006     delete t;
2007 }
2008 
2009 void CLIMMXMPP::handlePresence (gloox::Stanza *s)
2010 {
2011     assert (s);
2012     assert (s->type() == gloox::StanzaPresence);
2013 
2014 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
2015     gloox::Stanza *t = new gloox::Stanza(s);
2016 #else
2017     gloox::Stanza *t = s->clone();
2018 #endif
2019 
2020     if (t->subtype() == gloox::StanzaPresenceError)
2021         DropAllChildsTree (t, "");
2022     else
2023         handlePresence2 (t, s->from(), s->to(), s->status());
2024 
2025     DropAttrib (t, "from");
2026     DropAttrib (t, "to");
2027     DropAttrib (t, "id");
2028     DropAttrib (t, "xml:lang");
2029     if (t->hasAttribute ("xmlns", "jabber:client"))
2030         DropAttrib (t, "xmlns");
2031     DropAllChilds (t, "status");
2032 
2033     if (!CheckInvalid (t))
2034     {
2035         std::string txml = t->xml();
2036         CLIMMXMPPSave (m_serv, txml.c_str(), 3);
2037     }
2038     delete t;
2039 }
2040 
2041 void CLIMMXMPP::handleSubscription (gloox::Stanza *s)
2042 {
2043     assert (s);
2044     assert (s->type() == gloox::StanzaS10n);
2045     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",
2046                s->from().full().c_str(), s->to().full().c_str(), s->subtype(),
2047                s->id().c_str(), s->status().c_str(), s->priority(),
2048                s->body().c_str(), s->subject().c_str(),
2049 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
2050                s->thread().c_str(), s->presence(),
2051 #else
2052                s->thread().c_str(), s->show(),
2053 #endif
2054                s->xml().c_str());
2055 }
2056 #endif
2057 
2058 #endif
2059