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