1e130e77152574d2b10f4c5676491ed3fbf027a4
[asterisk/asterisk.git] / res / res_xmpp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief XMPP client and component module.
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * Iksemel http://code.google.com/p/iksemel/
26  *
27  * A reference module for interfacting Asterisk directly as a client or component with
28  * an XMPP/Jabber compliant server.
29  *
30  * This module is based upon the original res_jabber as done by Matt O'Gorman.
31  *
32  */
33
34 /*! \li \ref res_xmpp.c uses the configuration file \ref xmpp.conf and \ref jabber.conf
35  * \addtogroup configuration_file Configuration Files
36  */
37
38 /*!
39  * \page xmpp.conf xmpp.conf
40  * \verbinclude xmpp.conf.sample
41  */
42
43 /*** MODULEINFO
44         <depend>iksemel</depend>
45         <use type="external">openssl</use>
46         <support_level>core</support_level>
47  ***/
48
49 #include "asterisk.h"
50
51 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
52
53 #include <ctype.h>
54 #include <iksemel.h>
55
56 #include "asterisk/xmpp.h"
57 #include "asterisk/module.h"
58 #include "asterisk/manager.h"
59 #include "asterisk/app.h"
60 #include "asterisk/message.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/event.h"
63 #include "asterisk/cli.h"
64 #include "asterisk/config_options.h"
65
66 /*** DOCUMENTATION
67         <application name="JabberSend" language="en_US">
68                 <synopsis>
69                         Sends an XMPP message to a buddy.
70                 </synopsis>
71                 <syntax>
72                         <parameter name="account" required="true">
73                                 <para>The local named account to listen on (specified in
74                                 xmpp.conf)</para>
75                         </parameter>
76                         <parameter name="jid" required="true">
77                                 <para>Jabber ID of the buddy to send the message to. It can be a
78                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
79                         </parameter>
80                         <parameter name="message" required="true">
81                                 <para>The message to send.</para>
82                         </parameter>
83                 </syntax>
84                 <description>
85                         <para>Sends the content of <replaceable>message</replaceable> as text message
86                         from the given <replaceable>account</replaceable> to the buddy identified by
87                         <replaceable>jid</replaceable></para>
88                         <para>Example: JabberSend(asterisk,bob@domain.com,Hello world) sends "Hello world"
89                         to <replaceable>bob@domain.com</replaceable> as an XMPP message from the account
90                         <replaceable>asterisk</replaceable>, configured in xmpp.conf.</para>
91                 </description>
92                 <see-also>
93                         <ref type="function">JABBER_STATUS</ref>
94                         <ref type="function">JABBER_RECEIVE</ref>
95                 </see-also>
96         </application>
97         <function name="JABBER_RECEIVE" language="en_US">
98                 <synopsis>
99                         Reads XMPP messages.
100                 </synopsis>
101                 <syntax>
102                         <parameter name="account" required="true">
103                                 <para>The local named account to listen on (specified in
104                                 xmpp.conf)</para>
105                         </parameter>
106                         <parameter name="jid" required="true">
107                                 <para>Jabber ID of the buddy to receive message from. It can be a
108                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
109                         </parameter>
110                         <parameter name="timeout">
111                                 <para>In seconds, defaults to <literal>20</literal>.</para>
112                         </parameter>
113                 </syntax>
114                 <description>
115                         <para>Receives a text message on the given <replaceable>account</replaceable>
116                         from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
117                         <para>Example: ${JABBER_RECEIVE(asterisk,bob@domain.com)} returns an XMPP message
118                         sent from <replaceable>bob@domain.com</replaceable> (or nothing in case of a time out), to
119                         the <replaceable>asterisk</replaceable> XMPP account configured in xmpp.conf.</para>
120                 </description>
121                 <see-also>
122                         <ref type="function">JABBER_STATUS</ref>
123                         <ref type="application">JabberSend</ref>
124                 </see-also>
125         </function>
126         <function name="JABBER_STATUS" language="en_US">
127                 <synopsis>
128                         Retrieves a buddy's status.
129                 </synopsis>
130                 <syntax>
131                         <parameter name="account" required="true">
132                                 <para>The local named account to listen on (specified in
133                                 xmpp.conf)</para>
134                         </parameter>
135                         <parameter name="jid" required="true">
136                                 <para>Jabber ID of the buddy to receive message from. It can be a
137                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
138                         </parameter>
139                 </syntax>
140                 <description>
141                         <para>Retrieves the numeric status associated with the buddy identified
142                         by <replaceable>jid</replaceable>.
143                         If the buddy does not exist in the buddylist, returns 7.</para>
144                         <para>Status will be 1-7.</para>
145                         <para>1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline</para>
146                         <para>If not in roster variable will be set to 7.</para>
147                         <para>Example: ${JABBER_STATUS(asterisk,bob@domain.com)} returns 1 if
148                         <replaceable>bob@domain.com</replaceable> is online. <replaceable>asterisk</replaceable> is
149                         the associated XMPP account configured in xmpp.conf.</para>
150                 </description>
151                 <see-also>
152                         <ref type="function">JABBER_RECEIVE</ref>
153                         <ref type="application">JabberSend</ref>
154                 </see-also>
155         </function>
156         <application name="JabberSendGroup" language="en_US">
157                 <synopsis>
158                         Send a Jabber Message to a specified chat room
159                 </synopsis>
160                 <syntax>
161                         <parameter name="Jabber" required="true">
162                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
163                         </parameter>
164                         <parameter name="RoomJID" required="true">
165                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
166                         </parameter>
167                         <parameter name="Message" required="true">
168                                 <para>Message to be sent to the chat room.</para>
169                         </parameter>
170                         <parameter name="Nickname" required="false">
171                                 <para>The nickname Asterisk uses in the chat room.</para>
172                         </parameter>
173                 </syntax>
174                 <description>
175                         <para>Allows user to send a message to a chat room via XMPP.</para>
176                         <note><para>To be able to send messages to a chat room, a user must have previously joined it. Use the <replaceable>JabberJoin</replaceable> function to do so.</para></note>
177                 </description>
178         </application>
179         <application name="JabberJoin" language="en_US">
180                 <synopsis>
181                         Join a chat room
182                 </synopsis>
183                 <syntax>
184                         <parameter name="Jabber" required="true">
185                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
186                         </parameter>
187                         <parameter name="RoomJID" required="true">
188                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
189                         </parameter>
190                         <parameter name="Nickname" required="false">
191                                 <para>The nickname Asterisk will use in the chat room.</para>
192                                 <note><para>If a different nickname is supplied to an already joined room, the old nick will be changed to the new one.</para></note>
193                         </parameter>
194                 </syntax>
195                 <description>
196                         <para>Allows Asterisk to join a chat room.</para>
197                 </description>
198         </application>
199         <application name="JabberLeave" language="en_US">
200                 <synopsis>
201                         Leave a chat room
202                 </synopsis>
203                 <syntax>
204                         <parameter name="Jabber" required="true">
205                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
206                         </parameter>
207                         <parameter name="RoomJID" required="true">
208                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
209                         </parameter>
210                         <parameter name="Nickname" required="false">
211                                 <para>The nickname Asterisk uses in the chat room.</para>
212                         </parameter>
213                 </syntax>
214                 <description>
215                         <para>Allows Asterisk to leave a chat room.</para>
216                 </description>
217         </application>
218         <application name="JabberStatus" language="en_US">
219                 <synopsis>
220                         Retrieve the status of a jabber list member
221                 </synopsis>
222                 <syntax>
223                         <parameter name="Jabber" required="true">
224                                 <para>Client or transport Asterisk users to connect to Jabber.</para>
225                         </parameter>
226                         <parameter name="JID" required="true">
227                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
228                         </parameter>
229                         <parameter name="Variable" required="true">
230                                 <para>Variable to store the status of requested user.</para>
231                         </parameter>
232                 </syntax>
233                 <description>
234                         <para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
235                         <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
236                         The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
237                         <enumlist>
238                                 <enum name="1">
239                                         <para>Online.</para>
240                                 </enum>
241                                 <enum name="2">
242                                         <para>Chatty.</para>
243                                 </enum>
244                                 <enum name="3">
245                                         <para>Away.</para>
246                                 </enum>
247                                 <enum name="4">
248                                         <para>Extended Away.</para>
249                                 </enum>
250                                 <enum name="5">
251                                         <para>Do Not Disturb.</para>
252                                 </enum>
253                                 <enum name="6">
254                                         <para>Offline.</para>
255                                 </enum>
256                                 <enum name="7">
257                                         <para>Not In Roster.</para>
258                                 </enum>
259                         </enumlist>
260                 </description>
261         </application>
262         <manager name="JabberSend" language="en_US">
263                 <synopsis>
264                         Sends a message to a Jabber Client.
265                 </synopsis>
266                 <syntax>
267                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
268                         <parameter name="Jabber" required="true">
269                                 <para>Client or transport Asterisk uses to connect to JABBER.</para>
270                         </parameter>
271                         <parameter name="JID" required="true">
272                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
273                         </parameter>
274                         <parameter name="Message" required="true">
275                                 <para>Message to be sent to the buddy.</para>
276                         </parameter>
277                 </syntax>
278                 <description>
279                         <para>Sends a message to a Jabber Client.</para>
280                 </description>
281         </manager>
282         <info name="XMPPMessageToInfo" language="en_US" tech="XMPP">
283                 <para>Specifying a prefix of <literal>xmpp:</literal> will send the
284                 message as an XMPP chat message.</para>
285         </info>
286         <info name="XMPPMessageFromInfo" language="en_US" tech="XMPP">
287                 <para>Specifying a prefix of <literal>xmpp:</literal> will specify the
288                 account defined in <literal>xmpp.conf</literal> to send the message from.
289                 Note that this field is required for XMPP messages.</para>
290         </info>
291 ***/
292
293 /*! \brief Supported general configuration flags */
294 enum {
295         XMPP_AUTOPRUNE = (1 << 0),
296         XMPP_AUTOREGISTER = (1 << 1),
297         XMPP_AUTOACCEPT = (1 << 2),
298         XMPP_DEBUG = (1 << 3),
299         XMPP_USETLS = (1 << 4),
300         XMPP_USESASL = (1 << 5),
301         XMPP_FORCESSL = (1 << 6),
302         XMPP_KEEPALIVE = (1 << 7),
303         XMPP_COMPONENT = (1 << 8),
304         XMPP_SEND_TO_DIALPLAN = (1 << 9),
305         XMPP_DISTRIBUTE_EVENTS = (1 << 10),
306 };
307
308 /*! \brief Supported pubsub configuration flags */
309 enum {
310         XMPP_XEP0248 = (1 << 0),
311         XMPP_PUBSUB = (1 << 1),
312         XMPP_PUBSUB_AUTOCREATE = (1 << 2),
313 };
314
315 /*! \brief Number of buckets for client connections */
316 #define CLIENT_BUCKETS 53
317
318 /*! \brief Number of buckets for buddies (per client) */
319 #define BUDDY_BUCKETS 53
320
321 /*! \brief Number of buckets for resources (per buddy) */
322 #define RESOURCE_BUCKETS 53
323
324 /*! \brief Namespace for TLS support */
325 #define XMPP_TLS_NS "urn:ietf:params:xml:ns:xmpp-tls"
326
327 /*! \brief Status for a disappearing buddy */
328 #define STATUS_DISAPPEAR 6
329
330 /*! \brief Global debug status */
331 static int debug;
332
333 /*! \brief XMPP Global Configuration */
334 struct ast_xmpp_global_config {
335         struct ast_flags general; /*!< General configuration options */
336         struct ast_flags pubsub;  /*!< Pubsub related configuration options */
337 };
338
339 /*! \brief XMPP Client Configuration */
340 struct ast_xmpp_client_config {
341         AST_DECLARE_STRING_FIELDS(
342                 AST_STRING_FIELD(name);        /*!< Name of the client connection */
343                 AST_STRING_FIELD(user);        /*!< Username to use for authentication */
344                 AST_STRING_FIELD(password);    /*!< Password to use for authentication */
345                 AST_STRING_FIELD(server);      /*!< Server hostname */
346                 AST_STRING_FIELD(statusmsg);   /*!< Status message for presence */
347                 AST_STRING_FIELD(pubsubnode);  /*!< Pubsub node */
348                 AST_STRING_FIELD(context);     /*!< Context for incoming messages */
349                 );
350         int port;                       /*!< Port to use when connecting to server */
351         int message_timeout;            /*!< Timeout for messages */
352         int priority;                   /*!< Resource priority */
353         struct ast_flags flags;         /*!< Various options that have been set */
354         enum ikshowtype status;         /*!< Presence status */
355         struct ast_xmpp_client *client; /*!< Pointer to the client */
356         struct ao2_container *buddies;  /*!< Configured buddies */
357 };
358
359 struct xmpp_config {
360         struct ast_xmpp_global_config *global; /*!< Global configuration options */
361         struct ao2_container *clients;         /*!< Configured clients */
362 };
363
364 static AO2_GLOBAL_OBJ_STATIC(globals);
365
366 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
367 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
368 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
369 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
370
371 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
372 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
373
374 /*! \brief Defined handlers for XMPP client states */
375 static const struct xmpp_state_handler {
376         int state;
377         int component;
378         int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
379 } xmpp_state_handlers[] = {
380         { XMPP_STATE_REQUEST_TLS, 0, xmpp_client_request_tls, },
381         { XMPP_STATE_REQUESTED_TLS, 0, xmpp_client_requested_tls, },
382         { XMPP_STATE_AUTHENTICATE, 0, xmpp_client_authenticate, },
383         { XMPP_STATE_AUTHENTICATING, 0, xmpp_client_authenticating, },
384         { XMPP_STATE_AUTHENTICATE, 1, xmpp_component_authenticate, },
385         { XMPP_STATE_AUTHENTICATING, 1, xmpp_component_authenticating, },
386 };
387
388 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
389 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
390 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
391
392 /*! \brief Defined handlers for different PAK types */
393 static const struct xmpp_pak_handler {
394         int type;
395         int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
396 } xmpp_pak_handlers[] = {
397         { IKS_PAK_MESSAGE, xmpp_pak_message, },
398         { IKS_PAK_PRESENCE, xmpp_pak_presence, },
399         { IKS_PAK_S10N, xmpp_pak_s10n, },
400 };
401
402 static const char *app_ajisend = "JabberSend";
403 static const char *app_ajisendgroup = "JabberSendGroup";
404 static const char *app_ajistatus = "JabberStatus";
405 static const char *app_ajijoin = "JabberJoin";
406 static const char *app_ajileave = "JabberLeave";
407
408 static ast_cond_t message_received_condition;
409 static ast_mutex_t messagelock;
410
411 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags);
412
413 /*! \brief Destructor function for configuration */
414 static void ast_xmpp_client_config_destructor(void *obj)
415 {
416         struct ast_xmpp_client_config *cfg = obj;
417         ast_string_field_free_memory(cfg);
418         ao2_cleanup(cfg->client);
419         ao2_cleanup(cfg->buddies);
420 }
421
422 /*! \brief Destroy function for XMPP messages */
423 static void xmpp_message_destroy(struct ast_xmpp_message *message)
424 {
425         if (message->from) {
426                 ast_free(message->from);
427         }
428         if (message->message) {
429                 ast_free(message->message);
430         }
431
432         ast_free(message);
433 }
434
435 /*! \brief Destructor callback function for XMPP client */
436 static void xmpp_client_destructor(void *obj)
437 {
438         struct ast_xmpp_client *client = obj;
439         struct ast_xmpp_message *message;
440
441         ast_xmpp_client_disconnect(client);
442
443         if (client->stack) {
444                 iks_stack_delete(client->stack);
445         }
446
447         ao2_cleanup(client->buddies);
448
449         while ((message = AST_LIST_REMOVE_HEAD(&client->messages, list))) {
450                 xmpp_message_destroy(message);
451         }
452         AST_LIST_HEAD_DESTROY(&client->messages);
453 }
454
455 /*! \brief Hashing function for XMPP buddy */
456 static int xmpp_buddy_hash(const void *obj, const int flags)
457 {
458         const struct ast_xmpp_buddy *buddy = obj;
459         const char *id = obj;
460
461         return ast_str_hash(flags & OBJ_KEY ? id : buddy->id);
462 }
463
464 /*! \brief Comparator function for XMPP buddy */
465 static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
466 {
467         struct ast_xmpp_buddy *buddy1 = obj, *buddy2 = arg;
468         const char *id = arg;
469
470         return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
471 }
472
473 /*! \brief Allocator function for ast_xmpp_client */
474 static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
475 {
476         struct ast_xmpp_client *client;
477
478         if (!(client = ao2_alloc(sizeof(*client), xmpp_client_destructor))) {
479                 return NULL;
480         }
481
482         AST_LIST_HEAD_INIT(&client->messages);
483         client->thread = AST_PTHREADT_NULL;
484
485         if (!(client->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
486                 ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
487                 ao2_ref(client, -1);
488                 return NULL;
489         }
490
491         if (ast_string_field_init(client, 512)) {
492                 ast_log(LOG_ERROR, "Could not initialize stringfields for '%s'\n", name);
493                 ao2_ref(client, -1);
494                 return NULL;
495         }
496
497         if (!(client->stack = iks_stack_new(8192, 8192))) {
498                 ast_log(LOG_ERROR, "Could not create an Iksemel stack for '%s'\n", name);
499                 ao2_ref(client, -1);
500                 return NULL;
501         }
502
503         ast_string_field_set(client, name, name);
504
505         client->timeout = 50;
506         client->state = XMPP_STATE_DISCONNECTED;
507         ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
508
509         return client;
510 }
511
512 /*! \brief Find function for configuration */
513 static void *xmpp_config_find(struct ao2_container *tmp_container, const char *category)
514 {
515         return ao2_find(tmp_container, category, OBJ_KEY);
516 }
517
518 /*! \brief Look up existing client or create a new one */
519 static void *xmpp_client_find_or_create(const char *category)
520 {
521         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
522         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
523
524         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, category))) {
525                 return xmpp_client_alloc(category);
526         }
527
528         ao2_ref(clientcfg->client, +1);
529         return clientcfg->client;
530 }
531
532 /*! \brief Allocator function for configuration */
533 static void *ast_xmpp_client_config_alloc(const char *cat)
534 {
535         struct ast_xmpp_client_config *cfg;
536
537         if (!(cfg = ao2_alloc(sizeof(*cfg), ast_xmpp_client_config_destructor))) {
538                 return NULL;
539         }
540
541         if (ast_string_field_init(cfg, 512)) {
542                 ao2_ref(cfg, -1);
543                 return NULL;
544         }
545
546         if (!(cfg->client = xmpp_client_find_or_create(cat))) {
547                 ao2_ref(cfg, -1);
548                 return NULL;
549         }
550
551         if (!(cfg->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
552                 ao2_ref(cfg, -1);
553                 return NULL;
554         }
555
556         ast_string_field_set(cfg, name, cat);
557
558         return cfg;
559 }
560
561 /*! \brief Destructor for XMPP configuration */
562 static void xmpp_config_destructor(void *obj)
563 {
564         struct xmpp_config *cfg = obj;
565         ao2_cleanup(cfg->global);
566         ao2_cleanup(cfg->clients);
567 }
568
569 /*! \brief Hashing function for configuration */
570 static int xmpp_config_hash(const void *obj, const int flags)
571 {
572         const struct ast_xmpp_client_config *cfg = obj;
573         const char *name = (flags & OBJ_KEY) ? obj : cfg->name;
574         return ast_str_case_hash(name);
575 }
576
577 /*! \brief Comparator function for configuration */
578 static int xmpp_config_cmp(void *obj, void *arg, int flags)
579 {
580         struct ast_xmpp_client_config *one = obj, *two = arg;
581         const char *match = (flags & OBJ_KEY) ? arg : two->name;
582         return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
583 }
584
585 /*! \brief Allocator for XMPP configuration */
586 static void *xmpp_config_alloc(void)
587 {
588         struct xmpp_config *cfg;
589
590         if (!(cfg = ao2_alloc(sizeof(*cfg), xmpp_config_destructor))) {
591                 return NULL;
592         }
593
594         if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
595                 goto error;
596         }
597
598         ast_set_flag(&cfg->global->general, XMPP_AUTOREGISTER | XMPP_AUTOACCEPT | XMPP_USETLS | XMPP_USESASL | XMPP_KEEPALIVE);
599
600         if (!(cfg->clients = ao2_container_alloc(1, xmpp_config_hash, xmpp_config_cmp))) {
601                 goto error;
602         }
603
604         return cfg;
605 error:
606         ao2_ref(cfg, -1);
607         return NULL;
608 }
609
610 static int xmpp_config_prelink(void *newitem)
611 {
612         struct ast_xmpp_client_config *clientcfg = newitem;
613         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
614         RAII_VAR(struct ast_xmpp_client_config *, oldclientcfg, NULL, ao2_cleanup);
615
616         if (ast_strlen_zero(clientcfg->user)) {
617                 ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name);
618                 return -1;
619         } else if (ast_strlen_zero(clientcfg->password)) {
620                 ast_log(LOG_ERROR, "No password specified on client '%s'\n", clientcfg->name);
621                 return -1;
622         } else if (ast_strlen_zero(clientcfg->server)) {
623                 ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name);
624                 return -1;
625         }
626
627         /* If this is a new connection force a reconnect */
628         if (!cfg || !cfg->clients || !(oldclientcfg = xmpp_config_find(cfg->clients, clientcfg->name))) {
629                 clientcfg->client->reconnect = 1;
630                 return 0;
631         }
632
633         /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */
634         if (strcmp(clientcfg->user, oldclientcfg->user) ||
635             strcmp(clientcfg->password, oldclientcfg->password) ||
636             strcmp(clientcfg->server, oldclientcfg->server) ||
637             (clientcfg->port != oldclientcfg->port) ||
638             (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) ||
639             (clientcfg->priority != oldclientcfg->priority)) {
640                 clientcfg->client->reconnect = 1;
641         } else {
642                 clientcfg->client->reconnect = 0;
643         }
644
645         return 0;
646 }
647
648 static void xmpp_config_post_apply(void)
649 {
650         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
651
652         ao2_callback(cfg->clients, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_config_post_apply, NULL);
653 }
654
655 static struct aco_type global_option = {
656         .type = ACO_GLOBAL,
657         .item_offset = offsetof(struct xmpp_config, global),
658         .category_match = ACO_WHITELIST,
659         .category = "^general$",
660 };
661
662 struct aco_type *global_options[] = ACO_TYPES(&global_option);
663
664 static struct aco_type client_option = {
665         .type = ACO_ITEM,
666         .category_match = ACO_BLACKLIST,
667         .category = "^(general)$",
668         .item_alloc = ast_xmpp_client_config_alloc,
669         .item_find = xmpp_config_find,
670         .item_prelink = xmpp_config_prelink,
671         .item_offset = offsetof(struct xmpp_config, clients),
672 };
673
674 struct aco_type *client_options[] = ACO_TYPES(&client_option);
675
676 struct aco_file res_xmpp_conf = {
677         .filename = "xmpp.conf",
678         .alias = "jabber.conf",
679         .types = ACO_TYPES(&global_option, &client_option),
680 };
681
682 CONFIG_INFO_STANDARD(cfg_info, globals, xmpp_config_alloc,
683                      .files = ACO_FILES(&res_xmpp_conf),
684                      .post_apply_config = xmpp_config_post_apply,
685         );
686
687 /*! \brief Destructor callback function for XMPP resource */
688 static void xmpp_resource_destructor(void *obj)
689 {
690         struct ast_xmpp_resource *resource = obj;
691
692         if (resource->description) {
693                 ast_free(resource->description);
694         }
695 }
696
697 /*! \brief Hashing function for XMPP resource */
698 static int xmpp_resource_hash(const void *obj, const int flags)
699 {
700         const struct ast_xmpp_resource *resource = obj;
701
702         return flags & OBJ_KEY ? -1 : resource->priority;
703 }
704
705 /*! \brief Comparator function for XMPP resource */
706 static int xmpp_resource_cmp(void *obj, void *arg, int flags)
707 {
708         struct ast_xmpp_resource *resource1 = obj, *resource2 = arg;
709         const char *resource = arg;
710
711         return !strcmp(resource1->resource, flags & OBJ_KEY ? resource : resource2->resource) ? CMP_MATCH | CMP_STOP : 0;
712 }
713
714 /*! \brief Destructor callback function for XMPP buddy */
715 static void xmpp_buddy_destructor(void *obj)
716 {
717         struct ast_xmpp_buddy *buddy = obj;
718
719         if (buddy->resources) {
720                 ao2_ref(buddy->resources, -1);
721         }
722 }
723
724 /*! \brief Helper function which returns whether an XMPP client connection is secure or not */
725 static int xmpp_is_secure(struct ast_xmpp_client *client)
726 {
727 #ifdef HAVE_OPENSSL
728         return client->stream_flags & SECURE;
729 #else
730         return 0;
731 #endif
732 }
733
734 struct ast_xmpp_client *ast_xmpp_client_find(const char *name)
735 {
736         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
737         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
738
739         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
740                 return NULL;
741         }
742
743         ao2_ref(clientcfg->client, +1);
744         return clientcfg->client;
745 }
746
747 void ast_xmpp_client_unref(struct ast_xmpp_client *client)
748 {
749         ao2_ref(client, -1);
750 }
751
752 void ast_xmpp_client_lock(struct ast_xmpp_client *client)
753 {
754         ao2_lock(client);
755 }
756
757 void ast_xmpp_client_unlock(struct ast_xmpp_client *client)
758 {
759         ao2_unlock(client);
760 }
761
762 /*! \brief Internal function used to send a message to a user or chatroom */
763 static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
764 {
765         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
766         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
767         int res = 0;
768         char from[XMPP_MAX_JIDLEN];
769         iks *message_packet;
770
771         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
772             !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
773                 return -1;
774         }
775
776         if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
777                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
778         } else {
779                 snprintf(from, sizeof(from), "%s", client->jid->full);
780         }
781
782         iks_insert_attrib(message_packet, "from", from);
783
784         res = ast_xmpp_client_send(client, message_packet);
785
786         iks_delete(message_packet);
787
788         return res;
789 }
790
791 int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
792 {
793         return xmpp_client_send_message(client, 0, NULL, user, message);
794 }
795
796 int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
797 {
798         int res = 0;
799         iks *invite, *body = NULL, *namespace = NULL;
800
801         if (!(invite = iks_new("message")) || !(body = iks_new("body")) || !(namespace = iks_new("x"))) {
802                 res = -1;
803                 goto done;
804         }
805
806         iks_insert_attrib(invite, "to", user);
807         ast_xmpp_client_lock(client);
808         iks_insert_attrib(invite, "id", client->mid);
809         ast_xmpp_increment_mid(client->mid);
810         ast_xmpp_client_unlock(client);
811         iks_insert_cdata(body, message, 0);
812         iks_insert_node(invite, body);
813         iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
814         iks_insert_attrib(namespace, "jid", room);
815         iks_insert_node(invite, namespace);
816
817         res = ast_xmpp_client_send(client, invite);
818
819 done:
820         iks_delete(namespace);
821         iks_delete(body);
822         iks_delete(invite);
823
824         return res;
825 }
826
827 static int xmpp_client_set_group_presence(struct ast_xmpp_client *client, const char *room, int level, const char *nick)
828 {
829         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
830         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
831         int res = 0;
832         iks *presence = NULL, *x = NULL;
833         char from[XMPP_MAX_JIDLEN], roomid[XMPP_MAX_JIDLEN];
834
835         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
836             !(presence = iks_make_pres(level, NULL)) || !(x = iks_new("x"))) {
837                 res = -1;
838                 goto done;
839         }
840
841         if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
842                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
843                 snprintf(roomid, sizeof(roomid), "%s/%s", room, nick);
844         } else {
845                 snprintf(from, sizeof(from), "%s", client->jid->full);
846                 snprintf(roomid, sizeof(roomid), "%s/%s", room, S_OR(nick, client->jid->user));
847         }
848
849         iks_insert_attrib(presence, "to", roomid);
850         iks_insert_attrib(presence, "from", from);
851         iks_insert_attrib(x, "xmlns", "http://jabber.org/protocol/muc");
852         iks_insert_node(presence, x);
853
854         res = ast_xmpp_client_send(client, presence);
855
856 done:
857         iks_delete(x);
858         iks_delete(presence);
859
860         return res;
861 }
862
863 int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
864 {
865         return xmpp_client_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nickname);
866 }
867
868 int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
869 {
870         return xmpp_client_send_message(client, 1, nickname, address, message);
871 }
872
873 int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
874 {
875         return xmpp_client_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nickname);
876 }
877
878 void ast_xmpp_increment_mid(char *mid)
879 {
880         int i = 0;
881
882         for (i = strlen(mid) - 1; i >= 0; i--) {
883                 if (mid[i] != 'z') {
884                         mid[i] = mid[i] + 1;
885                         i = 0;
886                 } else {
887                         mid[i] = 'a';
888                 }
889         }
890 }
891
892 /*!
893  * \brief Create an IQ packet
894  * \param client the configured XMPP client we use to connect to a XMPP server
895  * \param type the type of IQ packet to create
896  * \return iks*
897  */
898 static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
899 {
900         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
901         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
902         iks *request;
903
904         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
905             !(request = iks_new("iq"))) {
906                 return NULL;
907         }
908
909         if (!ast_strlen_zero(clientcfg->pubsubnode)) {
910                 iks_insert_attrib(request, "to", clientcfg->pubsubnode);
911         }
912
913         iks_insert_attrib(request, "from", client->jid->full);
914         iks_insert_attrib(request, "type", type);
915         ast_xmpp_client_lock(client);
916         ast_xmpp_increment_mid(client->mid);
917         iks_insert_attrib(request, "id", client->mid);
918         ast_xmpp_client_unlock(client);
919
920         return request;
921 }
922
923 /*!
924  * \brief Build the skeleton of a publish
925  * \param client the configured XMPP client we use to connect to a XMPP server
926  * \param node Name of the node that will be published to
927  * \param event_type
928  * \return iks *
929  */
930 static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node,
931                                                const char *event_type, unsigned int cachable)
932 {
933         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
934         iks *request, *pubsub, *publish, *item;
935
936         if (!cfg || !cfg->global || !(request = xmpp_pubsub_iq_create(client, "set"))) {
937                 return NULL;
938         }
939
940         pubsub = iks_insert(request, "pubsub");
941         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
942         publish = iks_insert(pubsub, "publish");
943         iks_insert_attrib(publish, "node", ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248) ? node : event_type);
944         item = iks_insert(publish, "item");
945         iks_insert_attrib(item, "id", node);
946
947         if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
948                 iks *options, *x, *field_form_type, *field_persist;
949
950                 options = iks_insert(pubsub, "publish-options");
951                 x = iks_insert(options, "x");
952                 iks_insert_attrib(x, "xmlns", "jabber:x:data");
953                 iks_insert_attrib(x, "type", "submit");
954                 field_form_type = iks_insert(x, "field");
955                 iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
956                 iks_insert_attrib(field_form_type, "type", "hidden");
957                 iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
958                 field_persist = iks_insert(x, "field");
959                 iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
960                 iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
961         }
962
963         return item;
964
965 }
966
967 static iks* xmpp_pubsub_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
968 {
969         iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
970                 *field_deliver_payload, *field_persist_items, *field_access_model,
971                 *field_pubsub_collection;
972         configure = iks_insert(pubsub, "configure");
973         x = iks_insert(configure, "x");
974         iks_insert_attrib(x, "xmlns", "jabber:x:data");
975         iks_insert_attrib(x, "type", "submit");
976         field_owner = iks_insert(x, "field");
977         iks_insert_attrib(field_owner, "var", "FORM_TYPE");
978         iks_insert_attrib(field_owner, "type", "hidden");
979         iks_insert_cdata(iks_insert(field_owner, "value"),
980                          "http://jabber.org/protocol/pubsub#owner", 39);
981         if (node_type) {
982                 field_node_type = iks_insert(x, "field");
983                 iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
984                 iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
985         }
986         field_node_config = iks_insert(x, "field");
987         iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
988         iks_insert_attrib(field_node_config, "type", "hidden");
989         iks_insert_cdata(iks_insert(field_node_config, "value"),
990                          "http://jabber.org/protocol/pubsub#node_config", 45);
991         field_deliver_payload = iks_insert(x, "field");
992         iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
993         iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
994         field_persist_items = iks_insert(x, "field");
995         iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
996         iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
997         field_access_model = iks_insert(x, "field");
998         iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
999         iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
1000         if (node_type && !strcasecmp(node_type, "leaf")) {
1001                 field_pubsub_collection = iks_insert(x, "field");
1002                 iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
1003                 iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
1004                                  strlen(collection_name));
1005         }
1006         return configure;
1007 }
1008
1009 /*!
1010  * \brief Add Owner affiliations for pubsub node
1011  * \param client the configured XMPP client we use to connect to a XMPP server
1012  * \param node the name of the node to which to add affiliations
1013  * \return void
1014  */
1015 static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
1016 {
1017         iks *modify_affiliates = xmpp_pubsub_iq_create(client, "set");
1018         iks *pubsub, *affiliations, *affiliate;
1019         struct ao2_iterator i;
1020         struct ast_xmpp_buddy *buddy;
1021
1022         if (!modify_affiliates) {
1023                 ast_log(LOG_ERROR, "Could not create IQ for creating affiliations on client '%s'\n", client->name);
1024                 return;
1025         }
1026
1027         pubsub = iks_insert(modify_affiliates, "pubsub");
1028         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1029         affiliations = iks_insert(pubsub, "affiliations");
1030         iks_insert_attrib(affiliations, "node", node);
1031
1032         i = ao2_iterator_init(client->buddies, 0);
1033         while ((buddy = ao2_iterator_next(&i))) {
1034                 affiliate = iks_insert(affiliations, "affiliation");
1035                 iks_insert_attrib(affiliate, "jid", buddy->id);
1036                 iks_insert_attrib(affiliate, "affiliation", "owner");
1037                 ao2_ref(buddy, -1);
1038         }
1039         ao2_iterator_destroy(&i);
1040
1041         ast_xmpp_client_send(client, modify_affiliates);
1042         iks_delete(modify_affiliates);
1043 }
1044
1045 /*!
1046  * \brief Create a pubsub node
1047  * \param client the configured XMPP client we use to connect to a XMPP server
1048  * \param node_type the type of node to create
1049  * \param name the name of the node to create
1050  * \param collection_name
1051  * \return void
1052  */
1053 static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const
1054                                     char *name, const char *collection_name)
1055 {
1056         iks *node, *pubsub, *create;
1057
1058         if (!(node = xmpp_pubsub_iq_create(client, "set"))) {
1059                 return;
1060         }
1061
1062         pubsub = iks_insert(node, "pubsub");
1063         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1064         create = iks_insert(pubsub, "create");
1065         iks_insert_attrib(create, "node", name);
1066         xmpp_pubsub_build_node_config(pubsub, node_type, collection_name);
1067         ast_xmpp_client_send(client, node);
1068         xmpp_pubsub_create_affiliations(client, name);
1069         iks_delete(node);
1070 }
1071
1072 /*!
1073  * \brief Delete a PubSub node
1074  * \param client the configured XMPP client we use to connect to a XMPP server
1075  * \param node_name the name of the node to delete
1076  * return void
1077  */
1078 static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
1079 {
1080         iks *request, *pubsub, *delete;
1081
1082         if (!(request = xmpp_pubsub_iq_create(client, "set"))) {
1083                 return;
1084         }
1085
1086         pubsub = iks_insert(request, "pubsub");
1087         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1088         delete = iks_insert(pubsub, "delete");
1089         iks_insert_attrib(delete, "node", node_name);
1090         ast_xmpp_client_send(client, request);
1091
1092         iks_delete(delete);
1093         iks_delete(pubsub);
1094         iks_delete(request);
1095 }
1096
1097 /*!
1098  * \brief Create a PubSub collection node.
1099  * \param client the configured XMPP client we use to connect to a XMPP server
1100  * \param collection_name The name to use for this collection
1101  * \return void.
1102  */
1103 static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
1104 {
1105         xmpp_pubsub_create_node(client, "collection", collection_name, NULL);
1106 }
1107
1108
1109 /*!
1110  * \brief Create a PubSub leaf node.
1111  * \param client the configured XMPP client we use to connect to a XMPP server
1112  * \param collection_name
1113  * \param leaf_name The name to use for this collection
1114  * \return void.
1115  */
1116 static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name,
1117                                     const char *leaf_name)
1118 {
1119         xmpp_pubsub_create_node(client, "leaf", leaf_name, collection_name);
1120 }
1121
1122 /*!
1123  * \brief Publish MWI to a PubSub node
1124  * \param client the configured XMPP client we use to connect to a XMPP server
1125  * \param mailbox The Mailbox
1126  * \param context The Context
1127  * \param oldmsgs Old messages
1128  * \param newmsgs New Messages
1129  * \return void
1130  */
1131 static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox,
1132                                     const char *context, const char *oldmsgs, const char *newmsgs)
1133 {
1134         char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT], eid_str[20];
1135         iks *mailbox_node, *request;
1136
1137         snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
1138
1139         if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting", AST_DEVSTATE_CACHABLE))) {
1140                 return;
1141         }
1142
1143         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1144         mailbox_node = iks_insert(request, "mailbox");
1145         iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
1146         iks_insert_attrib(mailbox_node, "eid", eid_str);
1147         iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
1148         iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
1149
1150         ast_xmpp_client_send(client, iks_root(request));
1151
1152         iks_delete(request);
1153 }
1154
1155 /*!
1156  * \brief Publish device state to a PubSub node
1157  * \param client the configured XMPP client we use to connect to a XMPP server
1158  * \param device the name of the device whose state to publish
1159  * \param device_state the state to publish
1160  * \return void
1161  */
1162 static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device,
1163                                              const char *device_state, unsigned int cachable)
1164 {
1165         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1166         iks *request, *state;
1167         char eid_str[20], cachable_str[2];
1168
1169         if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) {
1170                 return;
1171         }
1172
1173         if (ast_test_flag(&cfg->global->pubsub, XMPP_PUBSUB_AUTOCREATE)) {
1174                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1175                         xmpp_pubsub_create_node(client, "leaf", device, "device_state");
1176                 } else {
1177                         xmpp_pubsub_create_node(client, NULL, device, NULL);
1178                 }
1179         }
1180
1181         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1182         state = iks_insert(request, "state");
1183         iks_insert_attrib(state, "xmlns", "http://asterisk.org");
1184         iks_insert_attrib(state, "eid", eid_str);
1185         snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
1186         iks_insert_attrib(state, "cachable", cachable_str);
1187         iks_insert_cdata(state, device_state, strlen(device_state));
1188         ast_xmpp_client_send(client, iks_root(request));
1189         iks_delete(request);
1190 }
1191
1192 /*!
1193  * \brief Callback function for MWI events
1194  * \param ast_event
1195  * \param data void pointer to ast_client structure
1196  * \return void
1197  */
1198 static void xmpp_pubsub_mwi_cb(const struct ast_event *ast_event, void *data)
1199 {
1200         struct ast_xmpp_client *client = data;
1201         const char *mailbox, *context;
1202         char oldmsgs[10], newmsgs[10];
1203
1204         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1205                 /* If the event didn't originate from this server, don't send it back out. */
1206                 ast_debug(1, "Returning here\n");
1207                 return;
1208         }
1209
1210         mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
1211         context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
1212         snprintf(oldmsgs, sizeof(oldmsgs), "%d",
1213                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
1214         snprintf(newmsgs, sizeof(newmsgs), "%d",
1215                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
1216         xmpp_pubsub_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
1217 }
1218
1219 /*!
1220  * \brief Callback function for device state events
1221  * \param ast_event
1222  * \param data void pointer to ast_client structure
1223  * \return void
1224  */
1225 static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *data)
1226 {
1227         struct ast_xmpp_client *client = data;
1228         const char *device, *device_state;
1229         unsigned int cachable;
1230
1231         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1232                 /* If the event didn't originate from this server, don't send it back out. */
1233                 ast_debug(1, "Returning here\n");
1234                 return;
1235         }
1236
1237         device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
1238         device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
1239         cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
1240         xmpp_pubsub_publish_device_state(client, device, device_state, cachable);
1241 }
1242
1243 /*!
1244  * \brief Unsubscribe from a PubSub node
1245  * \param client the configured XMPP client we use to connect to a XMPP server
1246  * \param node the name of the node to which to unsubscribe from
1247  * \return void
1248  */
1249 static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
1250 {
1251         iks *request = xmpp_pubsub_iq_create(client, "set");
1252         iks *pubsub, *unsubscribe;
1253
1254         if (!request) {
1255                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->name);
1256                 return;
1257         }
1258
1259         pubsub = iks_insert(request, "pubsub");
1260         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1261         unsubscribe = iks_insert(pubsub, "unsubscribe");
1262         iks_insert_attrib(unsubscribe, "jid", client->jid->partial);
1263         iks_insert_attrib(unsubscribe, "node", node);
1264
1265         ast_xmpp_client_send(client, request);
1266         iks_delete(request);
1267 }
1268
1269 /*!
1270  * \brief Subscribe to a PubSub node
1271  * \param client the configured XMPP client we use to connect to a XMPP server
1272  * \param node the name of the node to which to subscribe
1273  * \return void
1274  */
1275 static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
1276 {
1277         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1278         iks *request = xmpp_pubsub_iq_create(client, "set");
1279         iks *pubsub, *subscribe;
1280
1281         if (!cfg || !cfg->global || !request) {
1282                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub subscription on client '%s'\n", client->name);
1283                 return;
1284         }
1285
1286         pubsub = iks_insert(request, "pubsub");
1287         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1288         subscribe = iks_insert(pubsub, "subscribe");
1289         iks_insert_attrib(subscribe, "jid", client->jid->partial);
1290         iks_insert_attrib(subscribe, "node", node);
1291         if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1292                 iks *options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
1293                 options = iks_insert(pubsub, "options");
1294                 x = iks_insert(options, "x");
1295                 iks_insert_attrib(x, "xmlns", "jabber:x:data");
1296                 iks_insert_attrib(x, "type", "submit");
1297                 sub_options = iks_insert(x, "field");
1298                 iks_insert_attrib(sub_options, "var", "FORM_TYPE");
1299                 iks_insert_attrib(sub_options, "type", "hidden");
1300                 iks_insert_cdata(iks_insert(sub_options, "value"),
1301                                  "http://jabber.org/protocol/pubsub#subscribe_options", 51);
1302                 sub_type = iks_insert(x, "field");
1303                 iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
1304                 iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
1305                 sub_depth = iks_insert(x, "field");
1306                 iks_insert_attrib(sub_depth, "var", "pubsub#subscription_depth");
1307                 iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
1308                 sub_expire = iks_insert(x, "field");
1309                 iks_insert_attrib(sub_expire, "var", "pubsub#expire");
1310                 iks_insert_cdata(iks_insert(sub_expire, "value"), "presence", 8);
1311         }
1312         ast_xmpp_client_send(client, request);
1313         iks_delete(request);
1314 }
1315
1316 /*!
1317  * \brief Callback for handling PubSub events
1318  * \param data void pointer to ast_xmpp_client structure
1319  * \param pak A pak
1320  * \return IKS_FILTER_EAT
1321  */
1322 static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
1323 {
1324         char *item_id, *device_state, *context, *cachable_str;
1325         int oldmsgs, newmsgs;
1326         iks *item, *item_content;
1327         struct ast_eid pubsub_eid;
1328         struct ast_event *event;
1329         unsigned int cachable = AST_DEVSTATE_CACHABLE;
1330         item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
1331         if (!item) {
1332                 ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
1333                 return IKS_FILTER_EAT;
1334         }
1335         item_id = iks_find_attrib(item, "id");
1336         item_content = iks_child(item);
1337         ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
1338         if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
1339                 ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
1340                 return IKS_FILTER_EAT;
1341         }
1342         if (!strcasecmp(iks_name(item_content), "state")) {
1343                 device_state = iks_find_cdata(item, "state");
1344                 if ((cachable_str = iks_find_cdata(item, "cachable"))) {
1345                         sscanf(cachable_str, "%30d", &cachable);
1346                 }
1347                 if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
1348                                             AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
1349                                             AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
1350                                             AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
1351                                             AST_EVENT_IE_END))) {
1352                         return IKS_FILTER_EAT;
1353                 }
1354         } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
1355                 context = strsep(&item_id, "@");
1356                 sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
1357                 sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
1358                 if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
1359                                             AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
1360                                             AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
1361                                             AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
1362                                             AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
1363                                             &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
1364                         return IKS_FILTER_EAT;
1365                 }
1366         } else {
1367                 ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
1368                           iks_name(item_content));
1369                 return IKS_FILTER_EAT;
1370         }
1371
1372         if (cachable == AST_DEVSTATE_CACHABLE) {
1373                 ast_event_queue_and_cache(event);
1374         } else {
1375                 ast_event_queue(event);
1376         }
1377
1378         return IKS_FILTER_EAT;
1379 }
1380
1381 static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
1382 {
1383         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1384         char *node_name, *error;
1385         int error_num;
1386         iks *orig_request, *orig_pubsub = iks_find(pak->x, "pubsub");
1387         struct ast_xmpp_client *client = data;
1388
1389         if (!cfg || !cfg->global) {
1390                 ast_log(LOG_ERROR, "No global configuration available\n");
1391                 return IKS_FILTER_EAT;
1392         }
1393
1394         if (!orig_pubsub) {
1395                 ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
1396                 return IKS_FILTER_EAT;
1397         }
1398
1399         orig_request = iks_child(orig_pubsub);
1400         error = iks_find_attrib(iks_find(pak->x, "error"), "code");
1401         node_name = iks_find_attrib(orig_request, "node");
1402
1403         if (!sscanf(error, "%30d", &error_num)) {
1404                 return IKS_FILTER_EAT;
1405         }
1406
1407         if (error_num > 399 && error_num < 500 && error_num != 404) {
1408                 ast_log(LOG_ERROR,
1409                         "Error performing operation on PubSub node %s, %s.\n", node_name, error);
1410                 return IKS_FILTER_EAT;
1411         } else if (error_num > 499 && error_num < 600) {
1412                 ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
1413                 return IKS_FILTER_EAT;
1414         }
1415
1416         if (!strcasecmp(iks_name(orig_request), "publish")) {
1417                 iks *request;
1418
1419                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1420                         if (iks_find(iks_find(orig_request, "item"), "state")) {
1421                                 xmpp_pubsub_create_leaf(client, "device_state", node_name);
1422                         } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
1423                                 xmpp_pubsub_create_leaf(client, "message_waiting", node_name);
1424                         }
1425                 } else {
1426                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1427                 }
1428
1429                 if ((request = xmpp_pubsub_iq_create(client, "set"))) {
1430                         iks_insert_node(request, orig_pubsub);
1431                         ast_xmpp_client_send(client, request);
1432                         iks_delete(request);
1433                 } else {
1434                         ast_log(LOG_ERROR, "PubSub publish could not create IQ\n");
1435                 }
1436
1437                 return IKS_FILTER_EAT;
1438         } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
1439                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1440                         xmpp_pubsub_create_collection(client, node_name);
1441                 } else {
1442                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1443                 }
1444         }
1445
1446         return IKS_FILTER_EAT;
1447 }
1448
1449 /*!
1450  * \brief Initialize collections for event distribution
1451  * \param client the configured XMPP client we use to connect to a XMPP server
1452  * \return void
1453  */
1454 static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
1455 {
1456         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1457         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1458
1459         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
1460                 return;
1461         }
1462
1463         xmpp_pubsub_unsubscribe(client, "device_state");
1464         xmpp_pubsub_unsubscribe(client, "message_waiting");
1465
1466         if (!(client->mwi_sub = ast_event_subscribe(AST_EVENT_MWI, xmpp_pubsub_mwi_cb, "xmpp_pubsub_mwi_subscription",
1467                                                     client, AST_EVENT_IE_END))) {
1468                 return;
1469         }
1470
1471         if (ast_enable_distributed_devstate()) {
1472                 return;
1473         }
1474         
1475
1476         if (!(client->device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
1477                                                              xmpp_pubsub_devstate_cb, "xmpp_pubsub_devstate_subscription", client, AST_EVENT_IE_END))) {
1478                 ast_event_unsubscribe(client->mwi_sub);
1479                 client->mwi_sub = NULL;
1480                 return;
1481         }
1482
1483         ast_event_dump_cache(client->device_state_sub);
1484
1485         xmpp_pubsub_subscribe(client, "device_state");
1486         xmpp_pubsub_subscribe(client, "message_waiting");
1487         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_event, client, IKS_RULE_TYPE,
1488                             IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
1489         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_error, client, IKS_RULE_TYPE,
1490                             IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1491
1492 }
1493
1494 /*! \brief Internal astobj2 callback function which returns the first resource, which is the highest priority one */
1495 static int xmpp_resource_immediate(void *obj, void *arg, int flags)
1496 {
1497         return CMP_MATCH | CMP_STOP;
1498 }
1499
1500 /*
1501  * \internal
1502  * \brief Dial plan function status(). puts the status of watched user
1503  * into a channel variable.
1504  * \param chan ast_channel
1505  * \param data
1506  * \retval 0 success
1507  * \retval -1 error
1508  */
1509 static int xmpp_status_exec(struct ast_channel *chan, const char *data)
1510 {
1511         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1512         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1513         struct ast_xmpp_buddy *buddy;
1514         struct ast_xmpp_resource *resource;
1515         char *s = NULL, status[2];
1516         int stat = 7;
1517         static int deprecation_warning = 0;
1518         AST_DECLARE_APP_ARGS(args,
1519                              AST_APP_ARG(sender);
1520                              AST_APP_ARG(jid);
1521                              AST_APP_ARG(variable);
1522                 );
1523         AST_DECLARE_APP_ARGS(jid,
1524                              AST_APP_ARG(screenname);
1525                              AST_APP_ARG(resource);
1526                 );
1527
1528         if (deprecation_warning++ % 10 == 0) {
1529                 ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
1530         }
1531
1532         if (ast_strlen_zero(data)) {
1533                 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
1534                 return 0;
1535         }
1536         s = ast_strdupa(data);
1537         AST_STANDARD_APP_ARGS(args, s);
1538
1539         if (args.argc != 3) {
1540                 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
1541                 return -1;
1542         }
1543
1544         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1545         if (jid.argc < 1 || jid.argc > 2) {
1546                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1547                 return -1;
1548         }
1549
1550         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1551                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1552                 return -1;
1553         }
1554
1555         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1556                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1557                 return -1;
1558         }
1559
1560         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1561                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1562         }
1563
1564         ao2_ref(buddy, -1);
1565
1566         if (resource) {
1567                 stat = resource->status;
1568                 ao2_ref(resource, -1);
1569         } else {
1570                 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
1571         }
1572
1573         snprintf(status, sizeof(status), "%d", stat);
1574         pbx_builtin_setvar_helper(chan, args.variable, status);
1575
1576         return 0;
1577 }
1578
1579 /*!
1580  * \internal
1581  * \brief Dial plan funtcion to retrieve the status of a buddy.
1582  * \param channel The associated ast_channel, if there is one
1583  * \param data The account, buddy JID, and optional timeout
1584  * timeout.
1585  * \retval 0 success
1586  * \retval -1 failure
1587  */
1588 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1589 {
1590         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1591         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1592         struct ast_xmpp_buddy *buddy;
1593         struct ast_xmpp_resource *resource;
1594         int stat = 7;
1595         AST_DECLARE_APP_ARGS(args,
1596                              AST_APP_ARG(sender);
1597                              AST_APP_ARG(jid);
1598                 );
1599         AST_DECLARE_APP_ARGS(jid,
1600                              AST_APP_ARG(screenname);
1601                              AST_APP_ARG(resource);
1602                 );
1603
1604         if (ast_strlen_zero(data)) {
1605                 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
1606                 return 0;
1607         }
1608         AST_STANDARD_APP_ARGS(args, data);
1609
1610         if (args.argc != 2) {
1611                 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
1612                 return -1;
1613         }
1614
1615         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1616         if (jid.argc < 1 || jid.argc > 2) {
1617                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1618                 return -1;
1619         }
1620
1621         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1622                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1623                 return -1;
1624         }
1625
1626         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1627                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1628                 return -1;
1629         }
1630
1631         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1632                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1633         }
1634
1635         ao2_ref(buddy, -1);
1636
1637         if (resource) {
1638                 stat = resource->status;
1639                 ao2_ref(resource, -1);
1640         } else {
1641                 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
1642         }
1643
1644         snprintf(buf, buflen, "%d", stat);
1645
1646         return 0;
1647 }
1648
1649 static struct ast_custom_function jabberstatus_function = {
1650         .name = "JABBER_STATUS",
1651         .read = acf_jabberstatus_read,
1652 };
1653
1654 /*!
1655  * \brief Application to join a chat room
1656  * \param chan ast_channel
1657  * \param data  Data is sender|jid|nickname.
1658  * \retval 0 success
1659  * \retval -1 error
1660  */
1661 static int xmpp_join_exec(struct ast_channel *chan, const char *data)
1662 {
1663         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1664         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1665         char *s, nick[XMPP_MAX_RESJIDLEN];
1666         AST_DECLARE_APP_ARGS(args,
1667                              AST_APP_ARG(sender);
1668                              AST_APP_ARG(jid);
1669                              AST_APP_ARG(nick);
1670                 );
1671
1672         if (ast_strlen_zero(data)) {
1673                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1674                 return -1;
1675         }
1676         s = ast_strdupa(data);
1677
1678         AST_STANDARD_APP_ARGS(args, s);
1679         if (args.argc < 2 || args.argc > 3) {
1680                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1681                 return -1;
1682         }
1683
1684         if (strchr(args.jid, '/')) {
1685                 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1686                 return -1;
1687         }
1688
1689         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1690                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1691                 return -1;
1692         }
1693
1694         if (ast_strlen_zero(args.nick)) {
1695                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1696                         snprintf(nick, sizeof(nick), "asterisk");
1697                 } else {
1698                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1699                 }
1700         } else {
1701                 snprintf(nick, sizeof(nick), "%s", args.nick);
1702         }
1703
1704         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1705                 ast_xmpp_chatroom_join(clientcfg->client, args.jid, nick);
1706         } else {
1707                 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1708         }
1709
1710         return 0;
1711 }
1712
1713 /*!
1714  * \brief Application to leave a chat room
1715  * \param chan ast_channel
1716  * \param data  Data is sender|jid|nickname.
1717  * \retval 0 success
1718  * \retval -1 error
1719  */
1720 static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
1721 {
1722         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1723         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1724         char *s, nick[XMPP_MAX_RESJIDLEN];
1725         AST_DECLARE_APP_ARGS(args,
1726                              AST_APP_ARG(sender);
1727                              AST_APP_ARG(jid);
1728                              AST_APP_ARG(nick);
1729                 );
1730
1731         if (ast_strlen_zero(data)) {
1732                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1733                 return -1;
1734         }
1735         s = ast_strdupa(data);
1736
1737         AST_STANDARD_APP_ARGS(args, s);
1738         if (args.argc < 2 || args.argc > 3) {
1739                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1740                 return -1;
1741         }
1742
1743         if (strchr(args.jid, '/')) {
1744                 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1745                 return -1;
1746         }
1747
1748         if (ast_strlen_zero(args.jid) || !strchr(args.jid, '@')) {
1749                 ast_log(LOG_ERROR, "No jabber ID specified\n");
1750                 return -1;
1751         }
1752
1753         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1754                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1755                 return -1;
1756         }
1757
1758         if (ast_strlen_zero(args.nick)) {
1759                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1760                         snprintf(nick, sizeof(nick), "asterisk");
1761                 } else {
1762                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1763                 }
1764         } else {
1765                 snprintf(nick, sizeof(nick), "%s", args.nick);
1766         }
1767
1768         ast_xmpp_chatroom_leave(clientcfg->client, args.jid, nick);
1769
1770         return 0;
1771 }
1772
1773 /*!
1774  * \internal
1775  * \brief Dial plan function to send a message.
1776  * \param chan ast_channel
1777  * \param data  Data is account,jid,message.
1778  * \retval 0 success
1779  * \retval -1 failure
1780  */
1781 static int xmpp_send_exec(struct ast_channel *chan, const char *data)
1782 {
1783         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1784         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1785         char *s;
1786         AST_DECLARE_APP_ARGS(args,
1787                              AST_APP_ARG(sender);
1788                              AST_APP_ARG(recipient);
1789                              AST_APP_ARG(message);
1790                 );
1791
1792         if (ast_strlen_zero(data)) {
1793                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1794                 return -1;
1795         }
1796         s = ast_strdupa(data);
1797
1798         AST_STANDARD_APP_ARGS(args, s);
1799
1800         if ((args.argc < 3) || ast_strlen_zero(args.message) || !strchr(args.recipient, '@')) {
1801                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1802                 return -1;
1803         }
1804
1805         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1806                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1807                 return -1;
1808         }
1809
1810         ast_xmpp_client_send_message(clientcfg->client, args.recipient, args.message);
1811
1812         return 0;
1813 }
1814
1815 /*!
1816  * \brief Application to send a message to a groupchat.
1817  * \param chan ast_channel
1818  * \param data  Data is sender|groupchat|message.
1819  * \retval 0 success
1820  * \retval -1 error
1821  */
1822 static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
1823 {
1824         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1825         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1826         char *s, nick[XMPP_MAX_RESJIDLEN];
1827         AST_DECLARE_APP_ARGS(args,
1828                              AST_APP_ARG(sender);
1829                              AST_APP_ARG(groupchat);
1830                              AST_APP_ARG(message);
1831                              AST_APP_ARG(nick);
1832                 );
1833
1834         if (ast_strlen_zero(data)) {
1835                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1836                 return -1;
1837         }
1838         s = ast_strdupa(data);
1839
1840         AST_STANDARD_APP_ARGS(args, s);
1841         if ((args.argc < 3) || (args.argc > 4) || ast_strlen_zero(args.message) || !strchr(args.groupchat, '@')) {
1842                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1843                 return -1;
1844         }
1845
1846         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1847                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1848                 return -1;
1849         }
1850
1851         if (ast_strlen_zero(args.nick) || args.argc == 3) {
1852                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1853                         snprintf(nick, sizeof(nick), "asterisk");
1854                 } else {
1855                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1856                 }
1857         } else {
1858                 snprintf(nick, sizeof(nick), "%s", args.nick);
1859         }
1860
1861         ast_xmpp_chatroom_send(clientcfg->client, nick, args.groupchat, args.message);
1862
1863         return 0;
1864 }
1865
1866 /*!
1867  * \internal
1868  * \brief Dial plan function to receive a message.
1869  * \param channel The associated ast_channel, if there is one
1870  * \param data The account, JID, and optional timeout
1871  * timeout.
1872  * \retval 0 success
1873  * \retval -1 failure
1874  */
1875 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1876 {
1877         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1878         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1879         char *parse = NULL;
1880         int timeout, jidlen, resourcelen, found = 0;
1881         struct timeval start;
1882         long diff = 0;
1883         struct ast_xmpp_message *message;
1884         AST_DECLARE_APP_ARGS(args,
1885                              AST_APP_ARG(account);
1886                              AST_APP_ARG(jid);
1887                              AST_APP_ARG(timeout);
1888                 );
1889         AST_DECLARE_APP_ARGS(jid,
1890                              AST_APP_ARG(screenname);
1891                              AST_APP_ARG(resource);
1892                 );
1893
1894         if (ast_strlen_zero(data)) {
1895                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1896                 return -1;
1897         }
1898
1899         parse = ast_strdupa(data);
1900         AST_STANDARD_APP_ARGS(args, parse);
1901
1902         if (args.argc < 2 || args.argc > 3) {
1903                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1904                 return -1;
1905         }
1906
1907         parse = ast_strdupa(args.jid);
1908         AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
1909         if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > XMPP_MAX_JIDLEN) {
1910                 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
1911                 return -1;
1912         }
1913
1914         if (ast_strlen_zero(args.timeout)) {
1915                 timeout = 20;
1916         } else {
1917                 sscanf(args.timeout, "%d", &timeout);
1918                 if (timeout <= 0) {
1919                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
1920                         return -1;
1921                 }
1922         }
1923
1924         jidlen = strlen(jid.screenname);
1925         resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
1926
1927         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.account))) {
1928                 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
1929                 return -1;
1930         }
1931
1932         ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
1933
1934         start = ast_tvnow();
1935
1936         if (ast_autoservice_start(chan) < 0) {
1937                 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
1938                 return -1;
1939         }
1940
1941         /* search the messages list, grab the first message that matches with
1942          * the from JID we're expecting, and remove it from the messages list */
1943         while (diff < timeout) {
1944                 struct timespec ts = { 0, };
1945                 struct timeval wait;
1946                 int res = 0;
1947
1948                 wait = ast_tvadd(start, ast_tv(timeout, 0));
1949                 ts.tv_sec = wait.tv_sec;
1950                 ts.tv_nsec = wait.tv_usec * 1000;
1951
1952                 /* wait up to timeout seconds for an incoming message */
1953                 ast_mutex_lock(&messagelock);
1954                 if (AST_LIST_EMPTY(&clientcfg->client->messages)) {
1955                         res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
1956                 }
1957                 ast_mutex_unlock(&messagelock);
1958                 if (res == ETIMEDOUT) {
1959                         ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
1960                         break;
1961                 }
1962
1963                 AST_LIST_LOCK(&clientcfg->client->messages);
1964                 AST_LIST_TRAVERSE_SAFE_BEGIN(&clientcfg->client->messages, message, list) {
1965                         if (jid.argc == 1) {
1966                                 /* no resource provided, compare bare JIDs */
1967                                 if (strncasecmp(jid.screenname, message->from, jidlen)) {
1968                                         continue;
1969                                 }
1970                         } else {
1971                                 /* resource appended, compare bare JIDs and resources */
1972                                 char *resource = strchr(message->from, '/');
1973                                 if (!resource || strlen(resource) == 0) {
1974                                         ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", message->from);
1975                                         if (strncasecmp(jid.screenname, message->from, jidlen)) {
1976                                                 continue;
1977                                         }
1978                                 } else {
1979                                         resource ++;
1980                                         if (strncasecmp(jid.screenname, message->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
1981                                                 continue;
1982                                         }
1983                                 }
1984                         }
1985                         /* check if the message is not too old */
1986                         if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
1987                                 ast_debug(3, "Found old message from %s, deleting it\n", message->from);
1988                                 AST_LIST_REMOVE_CURRENT(list);
1989                                 xmpp_message_destroy(message);
1990                                 continue;
1991                         }
1992                         found = 1;
1993                         ast_copy_string(buf, message->message, buflen);
1994                         AST_LIST_REMOVE_CURRENT(list);
1995                         xmpp_message_destroy(message);
1996                         break;
1997                 }
1998                 AST_LIST_TRAVERSE_SAFE_END;
1999                 AST_LIST_UNLOCK(&clientcfg->client->messages);
2000                 if (found) {
2001                         break;
2002                 }
2003
2004                 /* check timeout */
2005                 diff = ast_tvdiff_ms(ast_tvnow(), start);
2006         }
2007
2008         if (ast_autoservice_stop(chan) < 0) {
2009                 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
2010         }
2011
2012         /* return if we timed out */
2013         if (!found) {
2014                 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
2015                 return -1;
2016         }
2017
2018         return 0;
2019 }
2020
2021 static struct ast_custom_function jabberreceive_function = {
2022         .name = "JABBER_RECEIVE",
2023         .read = acf_jabberreceive_read,
2024 };
2025
2026 /*!
2027  * \internal
2028  * \brief Delete old messages from a given JID
2029  * Messages stored during more than client->message_timeout are deleted
2030  * \param client Asterisk's XMPP client
2031  * \param from the JID we received messages from
2032  * \retval the number of deleted messages
2033  */
2034 static int delete_old_messages(struct ast_xmpp_client *client, char *from)
2035 {
2036         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2037         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2038         int deleted = 0, isold = 0;
2039         struct ast_xmpp_message *message = NULL;
2040
2041         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2042                 return 0;
2043         }
2044
2045         AST_LIST_LOCK(&client->messages);
2046         AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, message, list) {
2047                 if (isold) {
2048                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2049                                 AST_LIST_REMOVE_CURRENT(list);
2050                                 xmpp_message_destroy(message);
2051                                 deleted++;
2052                         }
2053                 } else if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
2054                         isold = 1;
2055                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2056                                 AST_LIST_REMOVE_CURRENT(list);
2057                                 xmpp_message_destroy(message);
2058                                 deleted++;
2059                         }
2060                 }
2061         }
2062         AST_LIST_TRAVERSE_SAFE_END;
2063         AST_LIST_UNLOCK(&client->messages);
2064
2065         return deleted;
2066 }
2067
2068 static int xmpp_send_cb(const struct ast_msg *msg, const char *to, const char *from)
2069 {
2070         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2071         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2072         char *sender, *dest;
2073         int res;
2074
2075         sender = ast_strdupa(from);
2076         strsep(&sender, ":");
2077         dest = ast_strdupa(to);
2078         strsep(&dest, ":");
2079
2080         if (ast_strlen_zero(sender)) {
2081                 ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for XMPP\n", from);
2082                 return -1;
2083         }
2084
2085         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, sender))) {
2086                 ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
2087                 return -1;
2088         }
2089
2090         ast_debug(1, "Sending message to '%s' from '%s'\n", dest, clientcfg->name);
2091
2092         if ((res = ast_xmpp_client_send_message(clientcfg->client, dest, ast_msg_get_body(msg))) != IKS_OK) {
2093                 ast_log(LOG_WARNING, "Failed to send XMPP message (%d).\n", res);
2094         }
2095
2096         return res == IKS_OK ? 0 : -1;
2097 }
2098
2099 static const struct ast_msg_tech msg_tech = {
2100         .name = "xmpp",
2101         .msg_send = xmpp_send_cb,
2102 };
2103
2104 /*! \brief Internal function which changes the XMPP client state */
2105 static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
2106 {
2107         client->state = state;
2108 }
2109
2110 /*! \brief Internal function which creates a buddy on a client */
2111 static struct ast_xmpp_buddy *xmpp_client_create_buddy(struct ao2_container *container, const char *id)
2112 {
2113         struct ast_xmpp_buddy *buddy;
2114
2115         if (!(buddy = ao2_alloc(sizeof(*buddy), xmpp_buddy_destructor))) {
2116                 return NULL;
2117         }
2118
2119         if (!(buddy->resources = ao2_container_alloc(RESOURCE_BUCKETS, xmpp_resource_hash, xmpp_resource_cmp))) {
2120                 ao2_ref(buddy, -1);
2121                 return NULL;
2122         }
2123
2124         ast_copy_string(buddy->id, id, sizeof(buddy->id));
2125
2126         /* Assume we need to subscribe to get their presence until proven otherwise */
2127         buddy->subscribe = 1;
2128
2129         ao2_link(container, buddy);
2130
2131         return buddy;
2132 }
2133
2134 /*! \brief Helper function which unsubscribes a user and removes them from the roster */
2135 static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
2136 {
2137         iks *iq, *query = NULL, *item = NULL;
2138
2139         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, user,
2140                                                        "Goodbye. Your status is no longer required.\n"))) {
2141                 return -1;
2142         }
2143
2144         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item"))) {
2145                 ast_log(LOG_WARNING, "Could not allocate memory for roster removal of '%s' from client '%s'\n",
2146                         user, client->name);
2147                 goto done;
2148         }
2149
2150         iks_insert_attrib(iq, "from", client->jid->full);
2151         iks_insert_attrib(iq, "type", "set");
2152         iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
2153         iks_insert_node(iq, query);
2154         iks_insert_attrib(item, "jid", user);
2155         iks_insert_attrib(item, "subscription", "remove");
2156         iks_insert_node(query, item);
2157
2158         if (ast_xmpp_client_send(client, iq)) {
2159                 ast_log(LOG_WARNING, "Could not send roster removal request of '%s' from client '%s'\n",
2160                         user, client->name);
2161         }
2162
2163 done:
2164         iks_delete(item);
2165         iks_delete(query);
2166         iks_delete(iq);
2167
2168         return 0;
2169 }
2170
2171 /*! \brief Callback function which subscribes to a user if needed */
2172 static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
2173 {
2174         struct ast_xmpp_buddy *buddy = obj;
2175         struct ast_xmpp_client *client = arg;
2176
2177         if (!buddy->subscribe) {
2178                 return 0;
2179         }
2180
2181         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, buddy->id,
2182                                                        "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
2183                 ast_log(LOG_WARNING, "Could not send subscription for '%s' on client '%s'\n",
2184                         buddy->id, client->name);
2185         }
2186
2187         buddy->subscribe = 0;
2188
2189         return 0;
2190 }
2191
2192 /*! \brief Hook function called when roster is received from server */
2193 static int xmpp_roster_hook(void *data, ikspak *pak)
2194 {
2195         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2196         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2197         struct ast_xmpp_client *client = data;
2198         iks *item;
2199
2200         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2201                 return IKS_FILTER_EAT;
2202         }
2203
2204         for (item = iks_child(pak->query); item; item = iks_next(item)) {
2205                 struct ast_xmpp_buddy *buddy;
2206
2207                 if (iks_strcmp(iks_name(item), "item")) {
2208                         continue;
2209                 }
2210
2211                 if (!(buddy = ao2_find(client->buddies, iks_find_attrib(item, "jid"), OBJ_KEY))) {
2212                         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOPRUNE)) {
2213                                 /* The buddy has not been specified in the configuration file, we no longer
2214                                  * want them on our buddy list or to receive their presence. */
2215                                 if (xmpp_client_unsubscribe_user(client, iks_find_attrib(item, "jid"))) {
2216                                         ast_log(LOG_ERROR, "Could not unsubscribe user '%s' on client '%s'\n",
2217                                                 iks_find_attrib(item, "jid"), client->name);
2218                                 }
2219                                 continue;
2220                         }
2221
2222                         if (!(buddy = xmpp_client_create_buddy(client->buddies, iks_find_attrib(item, "jid")))) {
2223                                 ast_log(LOG_ERROR, "Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item, "jid"),
2224                                         client->name);
2225                                 continue;
2226                         }
2227                 }
2228
2229                 /* Determine if we need to subscribe to their presence or not */
2230                 if (!iks_strcmp(iks_find_attrib(item, "subscription"), "none") ||
2231                     !iks_strcmp(iks_find_attrib(item, "subscription"), "from")) {
2232                         buddy->subscribe = 1;
2233                 } else {
2234                         buddy->subscribe = 0;
2235                 }
2236
2237                 ao2_ref(buddy, -1);
2238         }
2239
2240         /* If autoregister is enabled we need to go through every buddy that we need to subscribe to and do so */
2241         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOREGISTER)) {
2242                 ao2_callback(client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, client);
2243         }
2244
2245         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
2246
2247         return IKS_FILTER_EAT;
2248 }
2249
2250 /*! \brief Internal function which changes the presence status of an XMPP client */
2251 static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
2252 {
2253         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2254         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2255         iks *presence = NULL, *cnode = NULL, *priority = NULL;
2256         char priorityS[10];
2257
2258         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2259             !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new("c")) || !(priority = iks_new("priority"))) {
2260                 ast_log(LOG_ERROR, "Unable to allocate stanzas for setting presence status for client '%s'\n", client->name);
2261                 goto done;
2262         }
2263
2264         if (!ast_strlen_zero(to)) {
2265                 iks_insert_attrib(presence, "to", to);
2266         }
2267
2268         if (!ast_strlen_zero(from)) {
2269                 iks_insert_attrib(presence, "from", from);
2270         }
2271
2272         snprintf(priorityS, sizeof(priorityS), "%d", clientcfg->priority);
2273         iks_insert_cdata(priority, priorityS, strlen(priorityS));
2274         iks_insert_node(presence, priority);
2275         iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
2276         iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
2277         iks_insert_attrib(cnode, "ext", "voice-v1 video-v1 camera-v1");
2278         iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
2279         iks_insert_node(presence, cnode);
2280         ast_xmpp_client_send(client, presence);
2281
2282 done:
2283         iks_delete(cnode);
2284         iks_delete(presence);
2285         iks_delete(priority);
2286 }
2287
2288 /*! \brief Hook function called when client receives a service discovery get message */
2289 static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
2290 {
2291         struct ast_xmpp_client *client = data;
2292         iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL;
2293
2294         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) ||
2295             !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) ||
2296             !(audio = iks_new("feature")) || !(video = iks_new("feature"))) {
2297                 ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
2298                         pak->from->full, client->name);
2299                 goto end;
2300         }
2301
2302         iks_insert_attrib(iq, "from", client->jid->full);
2303
2304         if (pak->from) {
2305                 iks_insert_attrib(iq, "to", pak->from->full);
2306         }
2307
2308         iks_insert_attrib(iq, "type", "result");
2309         iks_insert_attrib(iq, "id", pak->id);
2310         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2311         iks_insert_attrib(ident, "category", "client");
2312         iks_insert_attrib(ident, "type", "pc");
2313         iks_insert_attrib(ident, "name", "asterisk");
2314         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2315
2316         iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2317         iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1");
2318         iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1");
2319         iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1");
2320         iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio");
2321         iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video");
2322         iks_insert_node(iq, query);
2323         iks_insert_node(query, ident);
2324         iks_insert_node(query, google);
2325         iks_insert_node(query, disco);
2326         iks_insert_node(query, jingle);
2327         iks_insert_node(query, ice);
2328         iks_insert_node(query, rtp);
2329         iks_insert_node(query, audio);
2330         iks_insert_node(query, video);
2331         ast_xmpp_client_send(client, iq);
2332
2333 end:
2334         iks_delete(query);
2335         iks_delete(video);
2336         iks_delete(audio);
2337         iks_delete(rtp);
2338         iks_delete(ice);
2339         iks_delete(jingle);
2340         iks_delete(google);
2341         iks_delete(ident);
2342         iks_delete(disco);
2343         iks_delete(iq);
2344
2345         return IKS_FILTER_EAT;
2346 }
2347
2348 /*! \brief Hook function called when client receives a service discovery result message */
2349 static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
2350 {
2351         struct ast_xmpp_client *client = data;
2352         struct ast_xmpp_buddy *buddy;
2353         struct ast_xmpp_resource *resource;
2354
2355         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2356                 return IKS_FILTER_EAT;
2357         }
2358
2359         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY))) {
2360                 ao2_ref(buddy, -1);
2361                 return IKS_FILTER_EAT;
2362         }
2363
2364         ao2_lock(resource);
2365
2366         if (iks_find_with_attrib(pak->query, "feature", "var", "urn:xmpp:jingle:1")) {
2367                 resource->caps.jingle = 1;
2368         }
2369
2370         ao2_unlock(resource);
2371
2372         ao2_ref(resource, -1);
2373         ao2_ref(buddy, -1);
2374
2375         return IKS_FILTER_EAT;
2376 }
2377
2378 /*! \brief Hook function called when client finishes authenticating with the server */
2379 static int xmpp_connect_hook(void *data, ikspak *pak)
2380 {
2381         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2382         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2383         struct ast_xmpp_client *client = data;
2384         iks *roster;
2385
2386         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2387                 return -1;
2388         }
2389
2390         client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
2391
2392         if (ast_test_flag(&clientcfg->flags, XMPP_DISTRIBUTE_EVENTS)) {
2393                 xmpp_init_event_distribution(client);
2394         }
2395
2396         if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
2397                 ast_log(LOG_ERROR, "Unable to allocate memory for roster request for client '%s'\n", client->name);
2398                 return -1;
2399         }
2400
2401         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2402         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2403
2404         iks_insert_attrib(roster, "id", "roster");
2405         ast_xmpp_client_send(client, roster);
2406
2407         iks_filter_remove_hook(client->filter, xmpp_connect_hook);
2408         iks_filter_add_rule(client->filter, xmpp_roster_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
2409
2410         xmpp_client_set_presence(client, NULL, client->jid->full, clientcfg->status, clientcfg->statusmsg);
2411         xmpp_client_change_state(client, XMPP_STATE_ROSTER);
2412
2413         return IKS_FILTER_EAT;
2414 }
2415
2416 /*! \brief Logging hook function */
2417 static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
2418 {
2419         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2420         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2421         struct ast_xmpp_client *client = data;
2422
2423         if (!ast_strlen_zero(xmpp)) {
2424                 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
2425         }
2426
2427         if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
2428                 return;
2429         }
2430
2431         if (!incoming) {
2432                 if (strlen(xmpp) == 1) {
2433                         if (option_debug > 2  && xmpp[0] == ' ') {
2434                                 ast_verbose("\n<--- XMPP keep alive from '%s' --->\n", client->name);
2435                         }
2436                 } else {
2437                         ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2438                 }
2439         } else {
2440                 ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2441         }
2442 }
2443
2444 /*! \brief Internal function which sends a raw message */
2445 static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
2446 {
2447         int ret;
2448 #ifdef HAVE_OPENSSL
2449         int len = strlen(message);
2450
2451         if (xmpp_is_secure(client)) {
2452                 ret = SSL_write(client->ssl_session, message, len);
2453                 if (ret) {
2454                         /* Log the message here, because iksemel's logHook is
2455                            unaccessible */
2456                         xmpp_log_hook(client, message, len, 0);
2457                         return IKS_OK;
2458                 }
2459         }
2460 #endif
2461         /* If needed, data will be sent unencrypted, and logHook will
2462            be called inside iks_send_raw */
2463         ret = iks_send_raw(client->parser, message);
2464         if (ret != IKS_OK) {
2465                 return ret;
2466         }
2467
2468         return IKS_OK;
2469 }
2470
2471 /*! \brief Helper function which sends an XMPP stream header to the server */
2472 static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
2473 {
2474         char *namespace = ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client";
2475         char msg[91 + strlen(namespace) + 6 + strlen(to) + 16 + 1];
2476
2477         snprintf(msg, sizeof(msg), "<?xml version='1.0'?>"
2478                  "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
2479                  "%s' to='%s' version='1.0'>", namespace, to);
2480
2481         return xmpp_client_send_raw_message(client, msg);
2482 }
2483
2484 int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
2485 {
2486         return xmpp_client_send_raw_message(client, iks_string(iks_stack(stanza), stanza));
2487 }
2488
2489 /*! \brief Internal function called when we need to request TLS support */
2490 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2491 {
2492         /* If the client connection is already secure we can jump straight to authenticating */
2493         if (xmpp_is_secure(client)) {
2494                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2495                 return 0;
2496         }
2497
2498 #ifndef HAVE_OPENSSL
2499         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->name);
2500         return -1;
2501 #else
2502         if (iks_send_raw(client->parser, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
2503                 ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be started.\n", client->name);
2504                 return -1;
2505         }
2506
2507         client->stream_flags |= TRY_SECURE;
2508
2509         xmpp_client_change_state(client, XMPP_STATE_REQUESTED_TLS);
2510
2511         return 0;
2512 #endif
2513 }
2514
2515 /*! \brief Internal function called when we receive a response to our TLS initiation request */
2516 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2517 {
2518 #ifdef HAVE_OPENSSL
2519         int sock;
2520 #endif
2521
2522         if (!strcmp(iks_name(node), "success")) {
2523                 /* TLS is up and working, we can move on to authenticating now */
2524                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2525                 return 0;
2526         } else if (!strcmp(iks_name(node), "failure")) {
2527                 /* TLS negotiation was a failure, close it on down! */
2528                 return -1;
2529         } else if (strcmp(iks_name(node), "proceed")) {
2530                 /* Ignore any other responses */
2531                 return 0;
2532         }
2533
2534 #ifndef HAVE_OPENSSL
2535         ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->name);
2536         return -1;
2537 #else
2538         client->ssl_method = SSLv3_method();
2539         if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
2540                 goto failure;
2541         }
2542
2543         if (!(client->ssl_session = SSL_new(client->ssl_context))) {
2544                 goto failure;
2545         }
2546
2547         sock = iks_fd(client->parser);
2548         if (!SSL_set_fd(client->ssl_session, sock)) {
2549                 goto failure;
2550         }
2551
2552         if (!SSL_connect(client->ssl_session)) {
2553                 goto failure;
2554         }
2555
2556         client->stream_flags &= (~TRY_SECURE);
2557         client->stream_flags |= SECURE;
2558
2559         if (xmpp_send_stream_header(client, cfg, client->jid->server) != IKS_OK) {
2560                 ast_log(LOG_ERROR, "TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
2561                         client->name);
2562                 return -1;
2563         }
2564
2565         ast_debug(1, "TLS connection for client '%s' started with server\n", client->name);
2566
2567         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2568
2569         return 0;
2570
2571 failure:
2572         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
2573         return -1;
2574 #endif
2575 }
2576
2577 /*! \brief Internal function called when we need to authenticate using non-SASL */
2578 static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2579 {
2580         iks *iq = NULL, *query = NULL;
2581         char buf[41], sidpass[100];
2582
2583         if (!(iq = iks_new("iq")) || !(query = iks_insert(iq, "query"))) {
2584                 ast_log(LOG_ERROR, "Stanzas could not be allocated for authentication on client '%s'\n", client->name);
2585                 iks_delete(iq);
2586                 return -1;
2587         }
2588
2589         iks_insert_attrib(iq, "type", "set");
2590         iks_insert_cdata(iks_insert(query, "username"), client->jid->user, 0);
2591         iks_insert_cdata(iks_insert(query, "resource"), client->jid->resource, 0);
2592
2593         iks_insert_attrib(query, "xmlns", "jabber:iq:auth");
2594         snprintf(sidpass, sizeof(sidpass), "%s%s", iks_find_attrib(node, "id"), cfg->password);
2595         ast_sha1_hash(buf, sidpass);
2596         iks_insert_cdata(iks_insert(query, "digest"), buf, 0);
2597
2598         ast_xmpp_client_lock(client);
2599         iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
2600         iks_insert_attrib(iq, "id", client->mid);
2601         ast_xmpp_increment_mid(client->mid);
2602         ast_xmpp_client_unlock(client);
2603
2604         iks_insert_attrib(iq, "to", client->jid->server);
2605
2606         ast_xmpp_client_send(client, iq);
2607
2608         iks_delete(iq);
2609
2610         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2611
2612         return 0;
2613 }
2614
2615 /*! \brief Internal function called when we need to authenticate using SASL */
2616 static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2617 {
2618         int features, len = strlen(client->jid->user) + strlen(cfg->password) + 3;
2619         iks *auth;
2620         char combined[len];
2621         char base64[(len + 2) * 4 / 3];
2622
2623         if (strcmp(iks_name(node), "stream:features")) {
2624                 /* Ignore anything beside stream features */
2625                 return 0;
2626         }
2627
2628         features = iks_stream_features(node);
2629
2630         if ((features & IKS_STREAM_SASL_MD5) && !xmpp_is_secure(client)) {
2631                 if (iks_start_sasl(client->parser, IKS_SASL_DIGEST_MD5, (char*)client->jid->user, (char*)cfg->password) != IKS_OK) {
2632                         ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->name);
2633                         return -1;
2634                 }
2635
2636                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2637                 return 0;
2638         }
2639
2640         /* Our only other available option is plain so if they don't support it, bail out now */
2641         if (!(features & IKS_STREAM_SASL_PLAIN)) {
2642                 ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->name);
2643                 return -1;
2644         }
2645
2646         if (!(auth = iks_new("auth"))) {
2647                 ast_log(LOG_ERROR, "Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->name);
2648                 return -1;
2649         }
2650
2651         iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL);
2652         iks_insert_attrib(auth, "mechanism", "PLAIN");
2653
2654         if (strchr(client->jid->user, '/')) {
2655                 char *user = ast_strdupa(client->jid->user);
2656
2657                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, strsep(&user, "/"), 0, cfg->password);
2658         } else {
2659                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, client->jid->user, 0, cfg->password);
2660         }
2661
2662         ast_base64encode(base64, (const unsigned char *) combined, len - 1, (len + 2) * 4 / 3);
2663         iks_insert_cdata(auth, base64, 0);
2664
2665         ast_xmpp_client_send(client, auth);
2666
2667         iks_delete(auth);
2668
2669         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2670
2671         return 0;
2672 }
2673
2674 /*! \brief Internal function called when we need to authenticate */
2675 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2676 {
2677         return ast_test_flag(&cfg->flags, XMPP_USESASL) ? xmpp_client_authenticate_sasl(client, cfg, type, node) : xmpp_client_authenticate_digest(client, cfg, type, node);
2678 }
2679
2680 /*! \brief Internal function called when we are authenticating */
2681 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2682 {
2683         int features;
2684
2685         if (!strcmp(iks_name(node), "success")) {
2686                 /* Authentication was a success, yay! */
2687                 xmpp_send_stream_header(client, cfg, client->jid->server);
2688
2689                 return 0;
2690         } else if (!strcmp(iks_name(node), "failure")) {
2691                 /* Authentication was a bust, disconnect and reconnect later */
2692                 return -1;
2693         } else if (strcmp(iks_name(node), "stream:features")) {
2694                 /* Ignore any other responses */
2695                 return 0;
2696         }
2697
2698         features = iks_stream_features(node);
2699
2700         if (features & IKS_STREAM_BIND) {
2701                 iks *auth;
2702
2703                 if (!(auth = iks_make_resource_bind(client->jid))) {
2704                         ast_log(LOG_ERROR, "Failed to allocate memory for stream bind on client '%s'\n", client->name);
2705                         return -1;
2706                 }
2707
2708                 ast_xmpp_client_lock(client);
2709                 iks_insert_attrib(auth, "id", client->mid);
2710                 ast_xmpp_increment_mid(client->mid);
2711                 ast_xmpp_client_unlock(client);
2712                 ast_xmpp_client_send(client, auth);
2713
2714                 iks_delete(auth);
2715
2716                 iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
2717         }
2718
2719         if (features & IKS_STREAM_SESSION) {
2720                 iks *auth;
2721
2722                 if (!(auth = iks_make_session())) {
2723                         ast_log(LOG_ERROR, "Failed to allocate memory for stream session on client '%s'\n", client->name);
2724                         return -1;
2725                 }
2726
2727                 iks_insert_attrib(auth, "id", "auth");
2728                 ast_xmpp_client_lock(client);
2729                 ast_xmpp_increment_mid(client->mid);
2730                 ast_xmpp_client_unlock(client);
2731                 ast_xmpp_client_send(client, auth);
2732
2733                 iks_delete(auth);
2734
2735                 iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
2736         }
2737
2738         return 0;
2739 }
2740
2741 /*! \brief Internal function called when we should authenticate as a component */
2742 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2743 {
2744         char secret[160], shasum[320], message[344];
2745         ikspak *pak = iks_packet(node);
2746
2747         snprintf(secret, sizeof(secret), "%s%s", pak->id, cfg->password);
2748         ast_sha1_hash(shasum, secret);
2749         snprintf(message, sizeof(message), "<handshake>%s</handshake>", shasum);
2750
2751         if (xmpp_client_send_raw_message(client, message) != IKS_OK) {
2752                 ast_log(LOG_ERROR, "Unable to send handshake for component '%s'\n", client->name);
2753                 return -1;
2754         }
2755
2756         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2757
2758         return 0;
2759 }
2760
2761 /*! \brief Hook function called when component receives a service discovery get message */
2762 static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
2763 {
2764         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2765         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2766         struct ast_xmpp_client *client = data;
2767         iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL;
2768         iks *version = NULL, *vcard = NULL, *search = NULL, *item = NULL;
2769         char *node;
2770
2771         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2772             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(identity = iks_new("identity")) || !(disco = iks_new("feature")) ||
2773             !(reg = iks_new("feature")) || !(commands = iks_new("feature")) || !(gateway = iks_new("feature")) || !(version = iks_new("feature")) ||
2774             !(vcard = iks_new("feature")) || !(search = iks_new("search")) || !(item = iks_new("item"))) {
2775                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
2776                         pak->from->partial, client->name);
2777                 goto done;
2778         }
2779
2780         iks_insert_attrib(iq, "from", clientcfg->user);
2781         iks_insert_attrib(iq, "to", pak->from->full);
2782         iks_insert_attrib(iq, "id", pak->id);
2783         iks_insert_attrib(iq, "type", "result");
2784
2785         if (!(node = iks_find_attrib(pak->query, "node"))) {
2786                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2787                 iks_insert_attrib(identity, "category", "gateway");
2788                 iks_insert_attrib(identity, "type", "pstn");
2789                 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2790                 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2791                 iks_insert_attrib(reg, "var", "jabber:iq:register");
2792                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2793                 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2794                 iks_insert_attrib(version, "var", "jabber:iq:version");
2795                 iks_insert_attrib(vcard, "var", "vcard-temp");
2796                 iks_insert_attrib(search, "var", "jabber:iq:search");
2797
2798                 iks_insert_node(iq, query);
2799                 iks_insert_node(query, identity);
2800                 iks_insert_node(query, disco);
2801                 iks_insert_node(query, reg);
2802                 iks_insert_node(query, commands);
2803                 iks_insert_node(query, gateway);
2804                 iks_insert_node(query, version);
2805                 iks_insert_node(query, vcard);
2806                 iks_insert_node(query, search);
2807         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2808                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2809                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2810                 iks_insert_attrib(item, "node", "confirmaccount");
2811                 iks_insert_attrib(item, "name", "Confirm account");
2812                 iks_insert_attrib(item, "jid", clientcfg->user);
2813
2814                 iks_insert_node(iq, query);
2815                 iks_insert_node(query, item);
2816         } else if (!strcasecmp(node, "confirmaccount")) {
2817                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2818                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2819
2820                 iks_insert_node(iq, query);
2821                 iks_insert_node(query, commands);
2822         } else {
2823                 ast_debug(3, "Unsupported service discovery info request received with node '%s' on component '%s'\n",
2824                           node, client->name);
2825                 goto done;
2826         }
2827
2828         if (ast_xmpp_client_send(client, iq)) {
2829                 ast_log(LOG_WARNING, "Could not send response to service discovery request on component '%s'\n",
2830                         client->name);
2831         }
2832
2833 done:
2834         iks_delete(search);
2835         iks_delete(vcard);
2836         iks_delete(version);
2837         iks_delete(gateway);
2838         iks_delete(commands);
2839         iks_delete(reg);
2840         iks_delete(disco);
2841         iks_delete(identity);
2842         iks_delete(query);
2843         iks_delete(iq);
2844
2845         return IKS_FILTER_EAT;
2846 }
2847
2848 /*! \brief Hook function called when the component is queried about registration */
2849 static int xmpp_component_register_get_hook(void *data, ikspak *pak)
2850 {
2851         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2852         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2853         struct ast_xmpp_client *client = data;
2854         iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL, *instructions = NULL;
2855         struct ast_xmpp_buddy *buddy;
2856         char *node;
2857
2858         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2859             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(error = iks_new("error")) || !(notacceptable = iks_new("not-acceptable")) ||
2860             !(instructions = iks_new("instructions"))) {
2861                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
2862                         pak->from->partial, client->name);
2863                 goto done;
2864         }
2865
2866         iks_insert_attrib(iq, "from", clientcfg->user);
2867         iks_insert_attrib(iq, "to", pak->from->full);
2868         iks_insert_attrib(iq, "id", pak->id);
2869         iks_insert_attrib(iq, "type", "result");
2870         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
2871         iks_insert_node(iq, query);
2872
2873         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2874                 iks_insert_attrib(error, "code", "406");
2875                 iks_insert_attrib(error, "type", "modify");
2876                 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2877
2878                 iks_insert_node(iq, error);
2879                 iks_insert_node(error, notacceptable);
2880
2881                 ast_log(LOG_ERROR, "Received register attempt from '%s' but buddy is not configured on component '%s'\n",
2882                         pak->from->partial, client->name);
2883         } else if (!(node = iks_find_attrib(pak->query, "node"))) {
2884                 iks_insert_cdata(instructions, "Welcome to Asterisk - the Open Source PBX.\n", 0);
2885                 iks_insert_node(query, instructions);
2886                 ao2_ref(buddy, -1);
2887         } else {
2888                 ast_log(LOG_WARNING, "Received register get to component '%s' using unsupported node '%s' from '%s'\n",
2889                         client->name, node, pak->from->partial);
2890                 ao2_ref(buddy, -1);
2891                 goto done;
2892         }
2893
2894         if (ast_xmpp_client_send(client, iq)) {
2895                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register get on component '%s'\n",
2896                         pak->from->partial, client->name);
2897         }
2898
2899 done:
2900         iks_delete(instructions);
2901         iks_delete(notacceptable);
2902         iks_delete(error);
2903         iks_delete(query);
2904         iks_delete(iq);
2905
2906         return IKS_FILTER_EAT;
2907 }
2908
2909 /*! \brief Hook function called when someone registers to the component */
2910 static int xmpp_component_register_set_hook(void *data, ikspak *pak)
2911 {
2912         struct ast_xmpp_client *client = data;
2913         iks *iq, *presence = NULL, *x = NULL;
2914
2915         if (!(iq = iks_new("iq")) || !(presence = iks_new("presence")) || !(x = iks_new("x"))) {
2916                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
2917                         pak->from->partial, client->name);
2918                 goto done;
2919         }
2920
2921         iks_insert_attrib(iq, "from", client->jid->full);
2922         iks_insert_attrib(iq, "to", pak->from->full);
2923         iks_insert_attrib(iq, "id", pak->id);
2924         iks_insert_attrib(iq, "type", "result");
2925
2926         if (ast_xmpp_client_send(client, iq)) {
2927                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register set on component '%s'\n",
2928                         pak->from->partial, client->name);
2929                 goto done;
2930         }
2931
2932         iks_insert_attrib(presence, "from", client->jid->full);
2933         iks_insert_attrib(presence, "to", pak->from->partial);
2934         ast_xmpp_client_lock(client);
2935         iks_insert_attrib(presence, "id", client->mid);
2936         ast_xmpp_increment_mid(client->mid);
2937         ast_xmpp_client_unlock(client);
2938         iks_insert_attrib(presence, "type", "subscribe");
2939         iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
2940
2941         iks_insert_node(presence, x);
2942
2943         if (ast_xmpp_client_send(client, presence)) {
2944                 ast_log(LOG_WARNING, "Could not send subscription to '%s' on component '%s'\n",
2945                         pak->from->partial, client->name);
2946         }
2947
2948 done:
2949         iks_delete(x);
2950         iks_delete(presence);
2951         iks_delete(iq);
2952
2953         return IKS_FILTER_EAT;
2954 }
2955
2956 /*! \brief Hook function called when we receive a service discovery items request */
2957 static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
2958 {
2959         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2960         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2961         struct ast_xmpp_client *client = data;
2962         iks *iq = NULL, *query = NULL, *item = NULL, *feature = NULL;
2963         char *node;
2964
2965         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2966             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item")) || !(feature = iks_new("feature"))) {
2967                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
2968                         pak->from->partial, client->name);
2969                 goto done;
2970         }
2971
2972         iks_insert_attrib(iq, "from", clientcfg->user);
2973         iks_insert_attrib(iq, "to", pak->from->full);
2974         iks_insert_attrib(iq, "id", pak->id);
2975         iks_insert_attrib(iq, "type", "result");
2976         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2977         iks_insert_node(iq, query);
2978
2979         if (!(node = iks_find_attrib(pak->query, "node"))) {
2980                 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
2981                 iks_insert_attrib(item, "name", "Asterisk Commands");
2982                 iks_insert_attrib(item, "jid", clientcfg->user);
2983
2984                 iks_insert_node(query, item);
2985         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2986                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2987         } else {
2988                 ast_log(LOG_WARNING, "Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
2989                         client->name, node, pak->from->partial);
2990                 goto done;
2991         }
2992
2993         if (ast_xmpp_client_send(client, iq)) {
2994                 ast_log(LOG_WARNING, "Could not send response to service discovery items request from '%s' on component '%s'\n",
2995                         pak->from->partial, client->name);
2996         }
2997
2998 done:
2999         iks_delete(feature);
3000         iks_delete(item);
3001         iks_delete(query);
3002         iks_delete(iq);
3003
3004         return IKS_FILTER_EAT;
3005 }
3006
3007 /*! \brief Internal function called when we authenticated as a component */
3008 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
3009 {
3010         if (strcmp(iks_name(node), "handshake")) {
3011                 ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
3012                 return -1;
3013         }
3014
3015         iks_filter_add_rule(client->filter, xmpp_component_service_discovery_items_hook, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
3016
3017         iks_filter_add_rule(client->filter, xmpp_component_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
3018
3019         /* This uses the client service discovery result hook on purpose, as the code is common between both */
3020         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
3021
3022         iks_filter_add_rule(client->filter, xmpp_component_register_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
3023         iks_filter_add_rule(client->filter, xmpp_component_register_set_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
3024
3025         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
3026
3027         return 0;
3028 }
3029
3030 /*! \brief Internal function called when a message is received */
3031 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3032 {
3033         struct ast_xmpp_message *message;
3034         char *body;
3035         int deleted = 0;
3036
3037         ast_debug(3, "XMPP client '%s' received a message\n", client->name);
3038
3039         if (!(body = iks_find_cdata(pak->x, "body"))) {
3040                 /* Message contains no body, ignore it. */
3041                 return 0;
3042         }
3043
3044         if (!(message = ast_calloc(1, sizeof(*message)))) {
3045                 return -1;
3046         }
3047
3048         message->arrived = ast_tvnow();
3049
3050         message->message = ast_strdup(body);
3051
3052         ast_copy_string(message->id, S_OR(pak->id, ""), sizeof(message->id));
3053         message->from = !ast_strlen_zero(pak->from->full) ? ast_strdup(pak->from->full) : NULL;
3054
3055         if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
3056                 struct ast_msg *msg;
3057
3058                 if ((msg = ast_msg_alloc())) {
3059                         int res;
3060
3061                         ast_xmpp_client_lock(client);
3062
3063                         res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
3064                         res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
3065                         res |= ast_msg_set_body(msg, "%s", message->message);
3066                         res |= ast_msg_set_context(msg, "%s", cfg->context);
3067
3068                         ast_xmpp_client_unlock(client);
3069
3070                         if (res) {
3071                                 ast_msg_destroy(msg);
3072                         } else {
3073                                 ast_msg_queue(msg);
3074                         }
3075                 }
3076         }
3077
3078         /* remove old messages received from this JID
3079          * and insert received message */
3080         deleted = delete_old_messages(client, pak->from->partial);
3081         ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
3082         AST_LIST_LOCK(&client->messages);
3083         AST_LIST_INSERT_HEAD(&client->messages, message, list);
3084         AST_LIST_UNLOCK(&client->messages);
3085
3086         /* wake up threads waiting for messages */
3087         ast_mutex_lock(&messagelock);
3088         ast_cond_broadcast(&message_received_condition);
3089         ast_mutex_unlock(&messagelock);
3090
3091         return 0;
3092 }
3093
3094 /*! \brief Helper function which sends a discovery information request to a user */
3095 static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
3096 {
3097         iks *iq, *query;
3098         int res;
3099
3100         if (!(iq = iks_new("iq")) || !(query = iks_new("query"))) {
3101                 iks_delete(iq);
3102                 return -1;
3103         }
3104
3105         iks_insert_attrib(iq, "type", "get");
3106         iks_insert_attrib(iq, "to", to);
3107         iks_insert_attrib(iq, "from", from);
3108         ast_xmpp_client_lock(client);
3109         iks_insert_attrib(iq, "id", client->mid);
3110         ast_xmpp_increment_mid(client->mid);
3111         ast_xmpp_client_unlock(client);
3112         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
3113         iks_insert_node(iq, query);
3114
3115         res = ast_xmpp_client_send(client, iq);
3116
3117         iks_delete(query);
3118         iks_delete(iq);
3119
3120         return res;
3121 }
3122
3123 /*! \brief Internal function called when a presence message is received */
3124 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3125 {
3126         struct ast_xmpp_buddy *buddy;
3127         struct ast_xmpp_resource *resource;
3128         char *type = iks_find_attrib(pak->x, "type");
3129         int status = pak->show ? pak->show : STATUS_DISAPPEAR;
3130
3131         /* If no resource is available this is a general buddy presence update, which we will ignore */
3132         if (!pak->from->resource) {
3133                 return 0;
3134         }
3135
3136         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
3137                 /* Only output the message if it is not about us */
3138                 if (strcmp(client->jid->partial, pak->from->partial)) {
3139                         ast_log(LOG_WARNING, "Received presence information about '%s' despite not having them in roster on client '%s'\n",
3140                                 pak->from->partial, client->name);
3141                 }
3142                 return 0;
3143         }
3144
3145         /* If this is a component presence probe request answer immediately with our presence status */
3146         if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
3147                 xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3148         }
3149
3150         ao2_lock(buddy->resources);
3151
3152         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY | OBJ_NOLOCK))) {
3153                 /* Only create the new resource if it is not going away - in reality this should not happen */
3154                 if (status != STATUS_DISAPPEAR) {
3155                         if (!(resource = ao2_alloc(sizeof(*resource), xmpp_resource_destructor))) {
3156                                 ast_log(LOG_ERROR, "Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
3157                                         pak->from->resource, buddy->id, client->name);
3158                                 ao2_unlock(buddy->resources);
3159                                 ao2_ref(buddy, -1);
3160                                 return 0;
3161                         }
3162
3163                         ast_copy_string(resource->resource, pak->from->resource, sizeof(resource->resource));
3164                 }
3165         } else {
3166                 /* We unlink the resource in case the priority changes or in case they are going away */
3167                 ao2_unlink_flags(buddy->resources, resource, OBJ_NOLOCK);
3168         }
3169
3170         /* Only update the resource and add it back in if it is not going away */
3171         if (resource && (status != STATUS_DISAPPEAR)) {
3172                 char *node, *ver;
3173
3174                 /* Try to get the XMPP spec node, and fall back to Google if not found */
3175                 if (!(node = iks_find_attrib(iks_find(pak->x, "c"), "node"))) {
3176                         node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
3177                 }
3178
3179                 if (!(ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"))) {
3180                         ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
3181                 }
3182
3183                 if (resource->description) {
3184                         ast_free(resource->description);
3185                 }
3186
3187                 if ((node && strcmp(resource->caps.node, node)) || (ver && strcmp(resource->caps.version, ver))) {
3188                         /* For interoperability reasons, proceed even if the resource fails to provide node or version */
3189                         if (node) {
3190                                 ast_copy_string(resource->caps.node, node, sizeof(resource->caps.node));
3191                         }
3192                         if (ver) {
3193                                 ast_copy_string(resource->caps.version, ver, sizeof(resource->caps.version));
3194                         }
3195
3196                         /* Google Talk places the capabilities information directly in presence, so see if it is there */
3197                         if (iks_find_with_attrib(pak->x, "c", "node", "http://www.google.com/xmpp/client/caps") ||
3198                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.google.com/xmpp/client/caps") ||
3199                             iks_find_with_attrib(pak->x, "c", "node", "http://www.android.com/gtalk/client/caps") ||
3200                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.android.com/gtalk/client/caps") ||
3201                             iks_find_with_attrib(pak->x, "c", "node", "http://mail.google.com/xmpp/client/caps") ||
3202                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://mail.google.com/xmpp/client/caps")) {
3203                                 resource->caps.google = 1;
3204                         }
3205
3206                         /* To discover if the buddy supports Jingle we need to query, so do so */
3207                         if (xmpp_client_send_disco_info_request(client, pak->from->full, client->jid->full)) {
3208                                 ast_log(LOG_WARNING, "Could not send discovery information request to resource '%s' of buddy '%s' on client '%s', capabilities may be incomplete\n", resource->resource, buddy->id, client->name);
3209                         }
3210                 }
3211
3212                 resource->status = status;
3213                 resource->description = ast_strdup(iks_find_cdata(pak->x, "status"));
3214                 resource->priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
3215
3216                 ao2_link_flags(buddy->resources, resource, OBJ_NOLOCK);
3217
3218                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3219                               "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
3220                               "\r\nDescription: %s\r\n",
3221                               client->name, pak->from->partial, resource->resource, resource->status,
3222                               resource->priority, S_OR(resource->description, ""));
3223
3224                 ao2_ref(resource, -1);
3225         } else {
3226                 /* This will get hit by presence coming in for an unknown resource, and also when a resource goes away */
3227                 if (resource) {
3228                         ao2_ref(resource, -1);
3229                 }
3230
3231                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3232                               "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
3233                               client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
3234         }
3235
3236         ao2_unlock(buddy->resources);
3237
3238         ao2_ref(buddy, -1);
3239
3240         return 0;
3241 }
3242
3243 /*! \brief Internal function called when a subscription message is received */
3244 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg,iks *node, ikspak *pak)
3245 {
3246         struct ast_xmpp_buddy *buddy;
3247
3248         switch (pak->subtype) {
3249         case IKS_TYPE_SUBSCRIBE:
3250                 if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
3251                         iks *presence, *status = NULL;
3252
3253                         if ((presence = iks_new("presence")) && (status = iks_new("status"))) {
3254                                 iks_insert_attrib(presence, "type", "subscribed");
3255                                 iks_insert_attrib(presence, "to", pak->from->full);
3256                                 iks_insert_attrib(presence, "from", client->jid->full);
3257
3258                                 if (pak->id) {
3259                                         iks_insert_attrib(presence, "id", pak->id);
3260                                 }
3261
3262                                 iks_insert_cdata(status, "Asterisk has approved your subscription", 0);
3263                                 iks_insert_node(presence, status);
3264
3265                                 if (ast_xmpp_client_send(client, presence)) {
3266                                         ast_log(LOG_ERROR, "Could not send subscription acceptance to '%s' from client '%s'\n",
3267                                                 pak->from->partial, client->name);
3268                                 }
3269                         } else {
3270                                 ast_log(LOG_ERROR, "Could not allocate presence stanzas for accepting subscription from '%s' to client '%s'\n",
3271                                         pak->from->partial, client->name);
3272                         }
3273
3274                         iks_delete(status);
3275                         iks_delete(presence);
3276                 }
3277
3278                 if (ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
3279                         xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3280                 }
3281                 /* This purposely flows through so we have the subscriber amongst our buddies */
3282         case IKS_TYPE_SUBSCRIBED:
3283                 ao2_lock(client->buddies);
3284
3285                 if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK))) {
3286                         buddy = xmpp_client_create_buddy(client->buddies, pak->from->partial);
3287                 }
3288
3289                 if (!buddy) {
3290                         ast_log(LOG_WARNING, "Could not find or create buddy '%s' on client '%s'\n",
3291                                 pak->from->partial, client->name);
3292                 } else {
3293                         ao2_ref(buddy, -1);
3294                 }
3295
3296                 ao2_unlock(client->buddies);
3297
3298                 break;
3299         default:
3300                 break;
3301         }
3302
3303         return 0;
3304 }
3305
3306 /*! \brief Action hook for when things occur */
3307 static int xmpp_action_hook(void *data, int type, iks *node)
3308 {
3309         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3310         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3311         struct ast_xmpp_client *client = data;
3312         ikspak *pak;
3313         int i;
3314
3315         if (!node) {
3316                 ast_log(LOG_ERROR, "xmpp_action_hook was called without a packet\n");
3317                 return IKS_HOOK;
3318         }
3319
3320         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
3321                 return IKS_HOOK;
3322         }
3323
3324         /* If the client is disconnecting ignore everything */
3325         if (client->state == XMPP_STATE_DISCONNECTING) {
3326                 return IKS_HOOK;
3327         }
3328
3329         pak = iks_packet(node);
3330
3331         /* work around iksemel's impossibility to recognize node names
3332          * containing a colon. Set the namespace of the corresponding
3333          * node accordingly. */
3334         if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
3335                 char *node_ns = NULL;
3336                 char attr[XMPP_MAX_ATTRLEN];
3337                 char *node_name = iks_name(iks_child(node));
3338                 char *aux = strchr(node_name, ':') + 1;
3339                 snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
3340                 node_ns = iks_find_attrib(iks_child(node), attr);
3341                 if (node_ns) {
3342                         pak->ns = node_ns;
3343                         pak->query = iks_child(node);
3344                 }
3345         }
3346
3347         /* Process through any state handlers */
3348         for (i = 0; i < ARRAY_LEN(xmpp_state_handlers); i++) {
3349                 if ((xmpp_state_handlers[i].state == client->state) && (xmpp_state_handlers[i].component == (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? 1 : 0))) {
3350                         if (xmpp_state_handlers[i].handler(client, clientcfg, type, node)) {
3351                                 /* If the handler wants us to stop now, do so */
3352                                 return IKS_HOOK;
3353                         }
3354                         break;
3355                 }
3356         }
3357
3358         /* Process through any PAK handlers */
3359         for (i = 0; i < ARRAY_LEN(xmpp_pak_handlers); i++) {
3360                 if (xmpp_pak_handlers[i].type == pak->type) {
3361                         if (xmpp_pak_handlers[i].handler(client, clientcfg, node, pak)) {
3362                                 /* If the handler wants us to stop now, do so */
3363                                 return IKS_HOOK;
3364                         }
3365                         break;
3366                 }
3367         }
3368
3369         /* Send the packet through the filter in case any filters want to process it */
3370         iks_filter_packet(client->filter, pak);
3371
3372         iks_delete(node);
3373
3374         return IKS_OK;
3375 }
3376
3377 int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
3378 {
3379         if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
3380                 client->state = XMPP_STATE_DISCONNECTING;
3381                 pthread_join(client->thread, NULL);
3382                 client->thread = AST_PTHREADT_NULL;
3383         }
3384
3385         if (client->mwi_sub) {
3386                 ast_event_unsubscribe(client->mwi_sub);
3387                 client->mwi_sub = NULL;
3388                 xmpp_pubsub_unsubscribe(client, "message_waiting");
3389         }
3390
3391         if (client->device_state_sub) {
3392                 ast_event_unsubscribe(client->device_state_sub);
3393                 client->device_state_sub = NULL;
3394                 xmpp_pubsub_unsubscribe(client, "device_state");
3395         }
3396
3397 #ifdef HAVE_OPENSSL
3398         if (client->stream_flags & SECURE) {
3399                 SSL_shutdown(client->ssl_session);
3400                 SSL_CTX_free(client->ssl_context);
3401                 SSL_free(client->ssl_session);
3402         }
3403
3404         client->stream_flags = 0;
3405 #endif
3406
3407         if (client->parser) {
3408                 iks_disconnect(client->parser);
3409         }
3410
3411         /* Disconnecting the parser and going back to a disconnected state means any hooks should no longer be present */
3412         if (client->filter) {
3413                 iks_filter_delete(client->filter);
3414                 client->filter = NULL;
3415         }
3416
3417         client->state = XMPP_STATE_DISCONNECTED;
3418
3419         return 0;
3420 }
3421
3422 /*! \brief Internal function used to reconnect an XMPP client to its server */
3423 static int xmpp_client_reconnect(struct ast_xmpp_client *client)
3424 {
3425         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3426         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3427         int res = IKS_NET_NOCONN;
3428
3429         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
3430                 return -1;
3431         }
3432
3433         ast_xmpp_client_disconnect(client);
3434
3435         client->timeout = 50;
3436         iks_parser_reset(client->parser);
3437
3438         if (!client->filter && !(client->filter = iks_filter_new())) {
3439                 ast_log(LOG_ERROR, "Could not create IKS filter for client connection '%s'\n", client->name);
3440                 return -1;
3441         }
3442
3443         /* If it's a component connect to user otherwise connect to server */
3444         res = iks_connect_via(client->parser, S_OR(clientcfg->server, client->jid->server), clientcfg->port,
3445                               ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? clientcfg->user : client->jid->server);
3446
3447         if (res == IKS_NET_NOCONN) {
3448                 ast_log(LOG_ERROR, "No XMPP connection available when trying to connect client '%s'\n", client->name);
3449                 return -1;
3450         } else if (res == IKS_NET_NODNS) {
3451                 ast_log(LOG_ERROR, "No DNS available for XMPP connection when trying to connect client '%s'\n", client->name);
3452                 return -1;
3453         }
3454
3455         /* Depending on the configuration of the client we eiher jump to requesting TLS, or authenticating */
3456         xmpp_client_change_state(client, (ast_test_flag(&clientcfg->flags, XMPP_USETLS) ? XMPP_STATE_REQUEST_TLS : XMPP_STATE_AUTHENTICATE));
3457
3458         return 0;
3459 }
3460
3461 /*! \brief Internal function which polls on an XMPP client and receives data */
3462 static int xmpp_io_recv(struct ast_xmpp_client *client, char *buffer, size_t buf_len, int timeout)
3463 {
3464         struct pollfd pfd = { .events = POLLIN };
3465         int len, res;
3466
3467 #ifdef HAVE_OPENSSL
3468         if (xmpp_is_secure(client)) {
3469                 pfd.fd = SSL_get_fd(client->ssl_session);
3470                 if (pfd.fd < 0) {
3471                         return -1;
3472                 }
3473         } else
3474 #endif /* HAVE_OPENSSL */
3475                 pfd.fd = iks_fd(client->parser);
3476
3477         res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
3478         if (res > 0) {
3479 #ifdef HAVE_OPENSSL
3480                 if (xmpp_is_secure(client)) {
3481                         len = SSL_read(client->ssl_session, buffer, buf_len);
3482                 } else
3483 #endif /* HAVE_OPENSSL */
3484                         len = recv(pfd.fd, buffer, buf_len, 0);
3485
3486                 if (len > 0) {
3487                         return len;
3488                 } else if (len <= 0) {
3489                         return -1;
3490                 }
3491         }
3492         return res;
3493 }
3494
3495 /*! \brief Internal function which receives data from the XMPP client connection */
3496 static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int timeout)
3497 {
3498         int len, ret, pos = 0, newbufpos = 0;
3499         char buf[NET_IO_BUF_SIZE - 1] = "";
3500         char newbuf[NET_IO_BUF_SIZE - 1] = "";
3501         unsigned char c;
3502
3503         while (1) {
3504                 len = xmpp_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
3505                 if (len < 0) return IKS_NET_RWERR;
3506                 if (len == 0) return IKS_NET_EXPIRED;
3507                 buf[len] = '\0';
3508
3509                 /* our iksemel parser won't work as expected if we feed
3510                    it with XML packets that contain multiple whitespace
3511                    characters between tags */
3512                 while (pos < len) {
3513                         c = buf[pos];
3514                         /* if we stumble on the ending tag character,
3515                            we skip any whitespace that follows it*/
3516                         if (c == '>') {
3517                                 while (isspace(buf[pos+1])) {
3518                                         pos++;
3519                                 }
3520                         }
3521                         newbuf[newbufpos] = c;
3522                         newbufpos++;
3523                         pos++;
3524                 }
3525                 pos = 0;
3526                 newbufpos = 0;
3527
3528                 /* Log the message here, because iksemel's logHook is
3529                    unaccessible */
3530                 xmpp_log_hook(client, buf, len, 1);
3531
3532                 /* let iksemel deal with the string length,
3533                    and reset our buffer */
3534                 ret = iks_parse(client->parser, newbuf, 0, 0);
3535                 memset(newbuf, 0, sizeof(newbuf));
3536
3537                 switch (ret) {
3538                 case IKS_NOMEM:
3539                         ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
3540                         break;
3541                 case IKS_BADXML:
3542                         ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
3543                         break;
3544                 case IKS_HOOK:
3545                         ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
3546                         break;
3547                 }
3548                 if (ret != IKS_OK) {
3549                         return ret;
3550                 }
3551                 ast_debug(3, "XML parsing successful\n");
3552         }
3553         return IKS_OK;
3554 }
3555
3556 /*! \brief XMPP client connection thread */
3557 static void *xmpp_client_thread(void *data)
3558 {
3559         struct ast_xmpp_client *client = data;
3560         int res = IKS_NET_RWERR;
3561
3562         do {
3563                 if (client->state == XMPP_STATE_DISCONNECTING) {
3564                         break;
3565                 }
3566
3567                 if (res == IKS_NET_RWERR || client->timeout == 0) {
3568                         ast_debug(3, "Connecting client '%s'\n", client->name);
3569                         if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
3570                                 sleep(4);
3571                                 res = IKS_NET_RWERR;
3572                         }
3573                         continue;
3574                 }
3575
3576                 res = xmpp_client_receive(client, 1);
3577
3578                 /* Decrease timeout if no data received, and delete
3579                  * old messages globally */
3580                 if (res == IKS_NET_EXPIRED) {
3581                         client->timeout--;
3582                 }
3583
3584                 if (res == IKS_HOOK) {
3585                         ast_debug(2, "JABBER: Got hook event.\n");
3586                 } else if (res == IKS_NET_TLSFAIL) {
3587                         ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
3588                 } else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
3589                         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3590                         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3591
3592                         if (cfg && cfg->clients && (clientcfg = xmpp_config_find(cfg->clients, client->name))) {
3593                                 res = ast_test_flag(&clientcfg->flags, XMPP_KEEPALIVE) ? xmpp_client_send_raw_message(client, " ") : IKS_OK;
3594                         } else {
3595                                 res = IKS_OK;
3596                         }
3597
3598                         if (res == IKS_OK) {
3599                                 client->timeout = 50;
3600                         } else {
3601                                 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
3602                         }
3603                 } else if (res == IKS_NET_RWERR) {
3604                         ast_log(LOG_WARNING, "JABBER: socket read error\n");
3605                 }
3606
3607         } while (1);
3608
3609         return NULL;
3610 }
3611
3612 static int xmpp_client_config_merge_buddies(void *obj, void *arg, int flags)
3613 {
3614         struct ast_xmpp_buddy *buddy1 = obj, *buddy2;
3615         struct ao2_container *buddies = arg;
3616
3617         /* If the buddy does not already exist link it into the client buddies container */
3618         if (!(buddy2 = ao2_find(buddies, buddy1->id, OBJ_KEY))) {
3619                 ao2_link(buddies, buddy1);
3620         } else {
3621                 ao2_ref(buddy2, -1);
3622         }
3623
3624         /* All buddies are unlinked from the configuration buddies container, always */
3625         return 1;
3626 }
3627
3628 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags)
3629 {
3630         struct ast_xmpp_client_config *cfg = obj;
3631
3632         /* Merge buddies as need be */
3633         ao2_callback(cfg->buddies, OBJ_MULTIPLE | OBJ_UNLINK, xmpp_client_config_merge_buddies, cfg->client->buddies);
3634
3635         if (cfg->client->reconnect) {
3636                 /* Disconnect the existing session since our role is changing, or we are starting up */
3637                 ast_xmpp_client_disconnect(cfg->client);
3638
3639                 if (!(cfg->client->parser = iks_stream_new(ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client", cfg->client,
3640                                                            xmpp_action_hook))) {
3641                         ast_log(LOG_ERROR, "Iksemel stream could not be created for client '%s' - client not active\n", cfg->name);
3642                         return -1;
3643                 }
3644
3645                 iks_set_log_hook(cfg->client->parser, xmpp_log_hook);
3646
3647                 /* Create a JID based on the given user, if no resource is given use the default */
3648                 if (!strchr(cfg->user, '/') && !ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
3649                         char resource[strlen(cfg->user) + strlen("/asterisk-xmpp") + 1];
3650
3651                         snprintf(resource, sizeof(resource), "%s/asterisk-xmpp", cfg->user);
3652                         cfg->client->jid = iks_id_new(cfg->client->stack, resource);
3653                 } else {
3654                         cfg->client->jid = iks_id_new(cfg->client->stack, cfg->user);
3655                 }
3656
3657                 if (!cfg->client->jid) {
3658                         ast_log(LOG_ERROR, "Jabber identity could not be created for client '%s' - client not active\n", cfg->name);
3659                         return -1;
3660                 }
3661
3662                 ast_pthread_create_background(&cfg->client->thread, NULL, xmpp_client_thread, cfg->client);
3663
3664                 cfg->client->reconnect = 0;
3665         } else if (cfg->client->state == XMPP_STATE_CONNECTED) {
3666                 /* If this client is connected update their presence status since it may have changed */
3667                 xmpp_client_set_presence(cfg->client, NULL, cfg->client->jid->full, cfg->status, cfg->statusmsg);
3668
3669                 /* Subscribe to the status of any newly added buddies */
3670                 if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
3671                         ao2_callback(cfg->client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, cfg->client);
3672                 }
3673         }
3674
3675         return 0;
3676 }
3677
3678 /*!
3679  * \internal
3680  * \brief  Send a Jabber Message via call from the Manager
3681  * \param s mansession Manager session
3682  * \param m message Message to send
3683  * \return  0
3684  */
3685 static int manager_jabber_send(struct mansession *s, const struct message *m)
3686 {
3687         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3688         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3689         const char *id = astman_get_header(m, "ActionID");
3690         const char *jabber = astman_get_header(m, "Jabber");
3691         const char *screenname = astman_get_header(m, "ScreenName");
3692         const char *message = astman_get_header(m, "Message");
3693
3694         if (ast_strlen_zero(jabber)) {
3695                 astman_send_error(s, m, "No transport specified");
3696                 return 0;
3697         }
3698         if (ast_strlen_zero(screenname)) {
3699                 astman_send_error(s, m, "No ScreenName specified");
3700                 return 0;
3701         }
3702         if (ast_strlen_zero(message)) {
3703                 astman_send_error(s, m, "No Message specified");
3704                 return 0;
3705         }
3706
3707         astman_send_ack(s, m, "Attempting to send Jabber Message");
3708
3709         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, jabber))) {
3710                 astman_send_error(s, m, "Could not find Sender");
3711                 return 0;
3712         }
3713
3714         if (strchr(screenname, '@') && !ast_xmpp_client_send_message(clientcfg->client, screenname, message)) {
3715                 astman_append(s, "Response: Success\r\n");
3716         } else {
3717                 astman_append(s, "Response: Error\r\n");
3718         }
3719
3720         if (!ast_strlen_zero(id)) {
3721                 astman_append(s, "ActionID: %s\r\n", id);
3722         }
3723
3724         astman_append(s, "\r\n");
3725
3726         return 0;
3727 }
3728
3729 /*!
3730  * \brief Build the a node request
3731  * \param client the configured XMPP client we use to connect to a XMPP server
3732  * \param collection name of the collection for request
3733  * \return iks*
3734  */
3735 static iks* xmpp_pubsub_build_node_request(struct ast_xmpp_client *client, const char *collection)
3736 {
3737         iks *request = xmpp_pubsub_iq_create(client, "get"), *query;
3738
3739         if (!request) {
3740                 return NULL;
3741         }
3742
3743         query = iks_insert(request, "query");
3744         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
3745
3746         if (collection) {
3747                 iks_insert_attrib(query, "node", collection);
3748         }
3749
3750         return request;
3751 }
3752
3753 /*!
3754  * \brief Receive pubsub item lists
3755  * \param data pointer to ast_xmpp_client structure
3756  * \param pak response from pubsub diso#items query
3757  * \retur