Fix crash in res_xmpp when deleting pubsub node from CLI
[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" module="res_xmpp">
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" module="res_xmpp">JABBER_STATUS</ref>
94                         <ref type="function" module="res_xmpp">JABBER_RECEIVE</ref>
95                 </see-also>
96         </application>
97         <function name="JABBER_RECEIVE" language="en_US" module="res_xmpp">
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" module="res_xmpp">JABBER_STATUS</ref>
123                         <ref type="application" module="res_xmpp">JabberSend</ref>
124                 </see-also>
125         </function>
126         <function name="JABBER_STATUS" language="en_US" module="res_xmpp">
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" module="res_xmpp">JABBER_RECEIVE</ref>
153                         <ref type="application" module="res_xmpp">JabberSend</ref>
154                 </see-also>
155         </function>
156         <application name="JabberSendGroup" language="en_US" module="res_xmpp">
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" module="res_xmpp">
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" module="res_xmpp">
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" module="res_xmpp">
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" module="res_xmpp">
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->filter) {
444                 iks_filter_delete(client->filter);
445         }
446
447         if (client->stack) {
448                 iks_stack_delete(client->stack);
449         }
450
451         ao2_cleanup(client->buddies);
452
453         while ((message = AST_LIST_REMOVE_HEAD(&client->messages, list))) {
454                 xmpp_message_destroy(message);
455         }
456         AST_LIST_HEAD_DESTROY(&client->messages);
457 }
458
459 /*! \brief Hashing function for XMPP buddy */
460 static int xmpp_buddy_hash(const void *obj, const int flags)
461 {
462         const struct ast_xmpp_buddy *buddy = obj;
463         const char *id = obj;
464
465         return ast_str_hash(flags & OBJ_KEY ? id : buddy->id);
466 }
467
468 /*! \brief Comparator function for XMPP buddy */
469 static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
470 {
471         struct ast_xmpp_buddy *buddy1 = obj, *buddy2 = arg;
472         const char *id = arg;
473
474         return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
475 }
476
477 /*! \brief Allocator function for ast_xmpp_client */
478 static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
479 {
480         struct ast_xmpp_client *client;
481
482         if (!(client = ao2_alloc(sizeof(*client), xmpp_client_destructor))) {
483                 return NULL;
484         }
485
486         AST_LIST_HEAD_INIT(&client->messages);
487         client->thread = AST_PTHREADT_NULL;
488
489         if (!(client->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
490                 ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
491                 ao2_ref(client, -1);
492                 return NULL;
493         }
494
495         if (ast_string_field_init(client, 512)) {
496                 ast_log(LOG_ERROR, "Could not initialize stringfields for '%s'\n", name);
497                 ao2_ref(client, -1);
498                 return NULL;
499         }
500
501         if (!(client->stack = iks_stack_new(8192, 8192))) {
502                 ast_log(LOG_ERROR, "Could not create an Iksemel stack for '%s'\n", name);
503                 ao2_ref(client, -1);
504                 return NULL;
505         }
506
507         ast_string_field_set(client, name, name);
508
509         client->timeout = 50;
510         client->state = XMPP_STATE_DISCONNECTED;
511         ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
512
513         return client;
514 }
515
516 /*! \brief Find function for configuration */
517 static void *xmpp_config_find(struct ao2_container *tmp_container, const char *category)
518 {
519         return ao2_find(tmp_container, category, OBJ_KEY);
520 }
521
522 /*! \brief Look up existing client or create a new one */
523 static void *xmpp_client_find_or_create(const char *category)
524 {
525         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
526         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
527
528         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, category))) {
529                 return xmpp_client_alloc(category);
530         }
531
532         ao2_ref(clientcfg->client, +1);
533         return clientcfg->client;
534 }
535
536 /*! \brief Allocator function for configuration */
537 static void *ast_xmpp_client_config_alloc(const char *cat)
538 {
539         struct ast_xmpp_client_config *cfg;
540
541         if (!(cfg = ao2_alloc(sizeof(*cfg), ast_xmpp_client_config_destructor))) {
542                 return NULL;
543         }
544
545         if (ast_string_field_init(cfg, 512)) {
546                 ao2_ref(cfg, -1);
547                 return NULL;
548         }
549
550         if (!(cfg->client = xmpp_client_find_or_create(cat))) {
551                 ao2_ref(cfg, -1);
552                 return NULL;
553         }
554
555         if (!(cfg->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
556                 ao2_ref(cfg, -1);
557                 return NULL;
558         }
559
560         ast_string_field_set(cfg, name, cat);
561
562         return cfg;
563 }
564
565 /*! \brief Destructor for XMPP configuration */
566 static void xmpp_config_destructor(void *obj)
567 {
568         struct xmpp_config *cfg = obj;
569         ao2_cleanup(cfg->global);
570         ao2_cleanup(cfg->clients);
571 }
572
573 /*! \brief Hashing function for configuration */
574 static int xmpp_config_hash(const void *obj, const int flags)
575 {
576         const struct ast_xmpp_client_config *cfg = obj;
577         const char *name = (flags & OBJ_KEY) ? obj : cfg->name;
578         return ast_str_case_hash(name);
579 }
580
581 /*! \brief Comparator function for configuration */
582 static int xmpp_config_cmp(void *obj, void *arg, int flags)
583 {
584         struct ast_xmpp_client_config *one = obj, *two = arg;
585         const char *match = (flags & OBJ_KEY) ? arg : two->name;
586         return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
587 }
588
589 /*! \brief Allocator for XMPP configuration */
590 static void *xmpp_config_alloc(void)
591 {
592         struct xmpp_config *cfg;
593
594         if (!(cfg = ao2_alloc(sizeof(*cfg), xmpp_config_destructor))) {
595                 return NULL;
596         }
597
598         if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
599                 goto error;
600         }
601
602         ast_set_flag(&cfg->global->general, XMPP_AUTOREGISTER | XMPP_AUTOACCEPT | XMPP_USETLS | XMPP_USESASL | XMPP_KEEPALIVE);
603
604         if (!(cfg->clients = ao2_container_alloc(1, xmpp_config_hash, xmpp_config_cmp))) {
605                 goto error;
606         }
607
608         return cfg;
609 error:
610         ao2_ref(cfg, -1);
611         return NULL;
612 }
613
614 static int xmpp_config_prelink(void *newitem)
615 {
616         struct ast_xmpp_client_config *clientcfg = newitem;
617         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
618         RAII_VAR(struct ast_xmpp_client_config *, oldclientcfg, NULL, ao2_cleanup);
619
620         if (ast_strlen_zero(clientcfg->user)) {
621                 ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name);
622                 return -1;
623         } else if (ast_strlen_zero(clientcfg->password)) {
624                 ast_log(LOG_ERROR, "No password specified on client '%s'\n", clientcfg->name);
625                 return -1;
626         } else if (ast_strlen_zero(clientcfg->server)) {
627                 ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name);
628                 return -1;
629         }
630
631         /* If this is a new connection force a reconnect */
632         if (!cfg || !cfg->clients || !(oldclientcfg = xmpp_config_find(cfg->clients, clientcfg->name))) {
633                 clientcfg->client->reconnect = 1;
634                 return 0;
635         }
636
637         /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */
638         if (strcmp(clientcfg->user, oldclientcfg->user) ||
639             strcmp(clientcfg->password, oldclientcfg->password) ||
640             strcmp(clientcfg->server, oldclientcfg->server) ||
641             (clientcfg->port != oldclientcfg->port) ||
642             (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) ||
643             (clientcfg->priority != oldclientcfg->priority)) {
644                 clientcfg->client->reconnect = 1;
645         } else {
646                 clientcfg->client->reconnect = 0;
647         }
648
649         return 0;
650 }
651
652 static void xmpp_config_post_apply(void)
653 {
654         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
655
656         ao2_callback(cfg->clients, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_config_post_apply, NULL);
657 }
658
659 static struct aco_type global_option = {
660         .type = ACO_GLOBAL,
661         .item_offset = offsetof(struct xmpp_config, global),
662         .category_match = ACO_WHITELIST,
663         .category = "^general$",
664 };
665
666 struct aco_type *global_options[] = ACO_TYPES(&global_option);
667
668 static struct aco_type client_option = {
669         .type = ACO_ITEM,
670         .category_match = ACO_BLACKLIST,
671         .category = "^(general)$",
672         .item_alloc = ast_xmpp_client_config_alloc,
673         .item_find = xmpp_config_find,
674         .item_prelink = xmpp_config_prelink,
675         .item_offset = offsetof(struct xmpp_config, clients),
676 };
677
678 struct aco_type *client_options[] = ACO_TYPES(&client_option);
679
680 struct aco_file res_xmpp_conf = {
681         .filename = "xmpp.conf",
682         .alias = "jabber.conf",
683         .types = ACO_TYPES(&global_option, &client_option),
684 };
685
686 CONFIG_INFO_STANDARD(cfg_info, globals, xmpp_config_alloc,
687                      .files = ACO_FILES(&res_xmpp_conf),
688                      .post_apply_config = xmpp_config_post_apply,
689         );
690
691 /*! \brief Destructor callback function for XMPP resource */
692 static void xmpp_resource_destructor(void *obj)
693 {
694         struct ast_xmpp_resource *resource = obj;
695
696         if (resource->description) {
697                 ast_free(resource->description);
698         }
699 }
700
701 /*! \brief Hashing function for XMPP resource */
702 static int xmpp_resource_hash(const void *obj, const int flags)
703 {
704         const struct ast_xmpp_resource *resource = obj;
705
706         return flags & OBJ_KEY ? -1 : resource->priority;
707 }
708
709 /*! \brief Comparator function for XMPP resource */
710 static int xmpp_resource_cmp(void *obj, void *arg, int flags)
711 {
712         struct ast_xmpp_resource *resource1 = obj, *resource2 = arg;
713         const char *resource = arg;
714
715         return !strcmp(resource1->resource, flags & OBJ_KEY ? resource : resource2->resource) ? CMP_MATCH | CMP_STOP : 0;
716 }
717
718 /*! \brief Destructor callback function for XMPP buddy */
719 static void xmpp_buddy_destructor(void *obj)
720 {
721         struct ast_xmpp_buddy *buddy = obj;
722
723         if (buddy->resources) {
724                 ao2_ref(buddy->resources, -1);
725         }
726 }
727
728 /*! \brief Helper function which returns whether an XMPP client connection is secure or not */
729 static int xmpp_is_secure(struct ast_xmpp_client *client)
730 {
731 #ifdef HAVE_OPENSSL
732         return client->stream_flags & SECURE;
733 #else
734         return 0;
735 #endif
736 }
737
738 struct ast_xmpp_client *ast_xmpp_client_find(const char *name)
739 {
740         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
741         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
742
743         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
744                 return NULL;
745         }
746
747         ao2_ref(clientcfg->client, +1);
748         return clientcfg->client;
749 }
750
751 void ast_xmpp_client_unref(struct ast_xmpp_client *client)
752 {
753         ao2_ref(client, -1);
754 }
755
756 void ast_xmpp_client_lock(struct ast_xmpp_client *client)
757 {
758         ao2_lock(client);
759 }
760
761 void ast_xmpp_client_unlock(struct ast_xmpp_client *client)
762 {
763         ao2_unlock(client);
764 }
765
766 /*! \brief Internal function used to send a message to a user or chatroom */
767 static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
768 {
769         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
770         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
771         int res = 0;
772         char from[XMPP_MAX_JIDLEN];
773         iks *message_packet;
774
775         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
776             !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
777                 return -1;
778         }
779
780         if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
781                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
782         } else {
783                 snprintf(from, sizeof(from), "%s", client->jid->full);
784         }
785
786         iks_insert_attrib(message_packet, "from", from);
787
788         res = ast_xmpp_client_send(client, message_packet);
789
790         iks_delete(message_packet);
791
792         return res;
793 }
794
795 int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
796 {
797         return xmpp_client_send_message(client, 0, NULL, user, message);
798 }
799
800 int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
801 {
802         int res = 0;
803         iks *invite, *body = NULL, *namespace = NULL;
804
805         if (!(invite = iks_new("message")) || !(body = iks_new("body")) || !(namespace = iks_new("x"))) {
806                 res = -1;
807                 goto done;
808         }
809
810         iks_insert_attrib(invite, "to", user);
811         ast_xmpp_client_lock(client);
812         iks_insert_attrib(invite, "id", client->mid);
813         ast_xmpp_increment_mid(client->mid);
814         ast_xmpp_client_unlock(client);
815         iks_insert_cdata(body, message, 0);
816         iks_insert_node(invite, body);
817         iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
818         iks_insert_attrib(namespace, "jid", room);
819         iks_insert_node(invite, namespace);
820
821         res = ast_xmpp_client_send(client, invite);
822
823 done:
824         iks_delete(namespace);
825         iks_delete(body);
826         iks_delete(invite);
827
828         return res;
829 }
830
831 static int xmpp_client_set_group_presence(struct ast_xmpp_client *client, const char *room, int level, const char *nick)
832 {
833         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
834         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
835         int res = 0;
836         iks *presence = NULL, *x = NULL;
837         char from[XMPP_MAX_JIDLEN], roomid[XMPP_MAX_JIDLEN];
838
839         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
840             !(presence = iks_make_pres(level, NULL)) || !(x = iks_new("x"))) {
841                 res = -1;
842                 goto done;
843         }
844
845         if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
846                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
847                 snprintf(roomid, sizeof(roomid), "%s/%s", room, nick);
848         } else {
849                 snprintf(from, sizeof(from), "%s", client->jid->full);
850                 snprintf(roomid, sizeof(roomid), "%s/%s", room, S_OR(nick, client->jid->user));
851         }
852
853         iks_insert_attrib(presence, "to", roomid);
854         iks_insert_attrib(presence, "from", from);
855         iks_insert_attrib(x, "xmlns", "http://jabber.org/protocol/muc");
856         iks_insert_node(presence, x);
857
858         res = ast_xmpp_client_send(client, presence);
859
860 done:
861         iks_delete(x);
862         iks_delete(presence);
863
864         return res;
865 }
866
867 int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
868 {
869         return xmpp_client_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nickname);
870 }
871
872 int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
873 {
874         return xmpp_client_send_message(client, 1, nickname, address, message);
875 }
876
877 int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
878 {
879         return xmpp_client_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nickname);
880 }
881
882 void ast_xmpp_increment_mid(char *mid)
883 {
884         int i = 0;
885
886         for (i = strlen(mid) - 1; i >= 0; i--) {
887                 if (mid[i] != 'z') {
888                         mid[i] = mid[i] + 1;
889                         i = 0;
890                 } else {
891                         mid[i] = 'a';
892                 }
893         }
894 }
895
896 /*!
897  * \brief Create an IQ packet
898  * \param client the configured XMPP client we use to connect to a XMPP server
899  * \param type the type of IQ packet to create
900  * \return iks*
901  */
902 static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
903 {
904         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
905         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
906         iks *request;
907
908         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
909             !(request = iks_new("iq"))) {
910                 return NULL;
911         }
912
913         if (!ast_strlen_zero(clientcfg->pubsubnode)) {
914                 iks_insert_attrib(request, "to", clientcfg->pubsubnode);
915         }
916
917         iks_insert_attrib(request, "from", client->jid->full);
918         iks_insert_attrib(request, "type", type);
919         ast_xmpp_client_lock(client);
920         ast_xmpp_increment_mid(client->mid);
921         iks_insert_attrib(request, "id", client->mid);
922         ast_xmpp_client_unlock(client);
923
924         return request;
925 }
926
927 /*!
928  * \brief Build the skeleton of a publish
929  * \param client the configured XMPP client we use to connect to a XMPP server
930  * \param node Name of the node that will be published to
931  * \param event_type
932  * \return iks *
933  */
934 static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node,
935                                                const char *event_type, unsigned int cachable)
936 {
937         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
938         iks *request, *pubsub, *publish, *item;
939
940         if (!cfg || !cfg->global || !(request = xmpp_pubsub_iq_create(client, "set"))) {
941                 return NULL;
942         }
943
944         pubsub = iks_insert(request, "pubsub");
945         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
946         publish = iks_insert(pubsub, "publish");
947         iks_insert_attrib(publish, "node", ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248) ? node : event_type);
948         item = iks_insert(publish, "item");
949         iks_insert_attrib(item, "id", node);
950
951         if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
952                 iks *options, *x, *field_form_type, *field_persist;
953
954                 options = iks_insert(pubsub, "publish-options");
955                 x = iks_insert(options, "x");
956                 iks_insert_attrib(x, "xmlns", "jabber:x:data");
957                 iks_insert_attrib(x, "type", "submit");
958                 field_form_type = iks_insert(x, "field");
959                 iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
960                 iks_insert_attrib(field_form_type, "type", "hidden");
961                 iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
962                 field_persist = iks_insert(x, "field");
963                 iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
964                 iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
965         }
966
967         return item;
968
969 }
970
971 static iks* xmpp_pubsub_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
972 {
973         iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
974                 *field_deliver_payload, *field_persist_items, *field_access_model,
975                 *field_pubsub_collection;
976         configure = iks_insert(pubsub, "configure");
977         x = iks_insert(configure, "x");
978         iks_insert_attrib(x, "xmlns", "jabber:x:data");
979         iks_insert_attrib(x, "type", "submit");
980         field_owner = iks_insert(x, "field");
981         iks_insert_attrib(field_owner, "var", "FORM_TYPE");
982         iks_insert_attrib(field_owner, "type", "hidden");
983         iks_insert_cdata(iks_insert(field_owner, "value"),
984                          "http://jabber.org/protocol/pubsub#owner", 39);
985         if (node_type) {
986                 field_node_type = iks_insert(x, "field");
987                 iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
988                 iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
989         }
990         field_node_config = iks_insert(x, "field");
991         iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
992         iks_insert_attrib(field_node_config, "type", "hidden");
993         iks_insert_cdata(iks_insert(field_node_config, "value"),
994                          "http://jabber.org/protocol/pubsub#node_config", 45);
995         field_deliver_payload = iks_insert(x, "field");
996         iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
997         iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
998         field_persist_items = iks_insert(x, "field");
999         iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
1000         iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
1001         field_access_model = iks_insert(x, "field");
1002         iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
1003         iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
1004         if (node_type && !strcasecmp(node_type, "leaf")) {
1005                 field_pubsub_collection = iks_insert(x, "field");
1006                 iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
1007                 iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
1008                                  strlen(collection_name));
1009         }
1010         return configure;
1011 }
1012
1013 /*!
1014  * \brief Add Owner affiliations for pubsub node
1015  * \param client the configured XMPP client we use to connect to a XMPP server
1016  * \param node the name of the node to which to add affiliations
1017  * \return void
1018  */
1019 static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
1020 {
1021         iks *modify_affiliates = xmpp_pubsub_iq_create(client, "set");
1022         iks *pubsub, *affiliations, *affiliate;
1023         struct ao2_iterator i;
1024         struct ast_xmpp_buddy *buddy;
1025
1026         if (!modify_affiliates) {
1027                 ast_log(LOG_ERROR, "Could not create IQ for creating affiliations on client '%s'\n", client->name);
1028                 return;
1029         }
1030
1031         pubsub = iks_insert(modify_affiliates, "pubsub");
1032         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1033         affiliations = iks_insert(pubsub, "affiliations");
1034         iks_insert_attrib(affiliations, "node", node);
1035
1036         i = ao2_iterator_init(client->buddies, 0);
1037         while ((buddy = ao2_iterator_next(&i))) {
1038                 affiliate = iks_insert(affiliations, "affiliation");
1039                 iks_insert_attrib(affiliate, "jid", buddy->id);
1040                 iks_insert_attrib(affiliate, "affiliation", "owner");
1041                 ao2_ref(buddy, -1);
1042         }
1043         ao2_iterator_destroy(&i);
1044
1045         ast_xmpp_client_send(client, modify_affiliates);
1046         iks_delete(modify_affiliates);
1047 }
1048
1049 /*!
1050  * \brief Create a pubsub node
1051  * \param client the configured XMPP client we use to connect to a XMPP server
1052  * \param node_type the type of node to create
1053  * \param name the name of the node to create
1054  * \param collection_name
1055  * \return void
1056  */
1057 static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const
1058                                     char *name, const char *collection_name)
1059 {
1060         iks *node, *pubsub, *create;
1061
1062         if (!(node = xmpp_pubsub_iq_create(client, "set"))) {
1063                 return;
1064         }
1065
1066         pubsub = iks_insert(node, "pubsub");
1067         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1068         create = iks_insert(pubsub, "create");
1069         iks_insert_attrib(create, "node", name);
1070         xmpp_pubsub_build_node_config(pubsub, node_type, collection_name);
1071         ast_xmpp_client_send(client, node);
1072         xmpp_pubsub_create_affiliations(client, name);
1073         iks_delete(node);
1074 }
1075
1076 /*!
1077  * \brief Delete a PubSub node
1078  * \param client the configured XMPP client we use to connect to a XMPP server
1079  * \param node_name the name of the node to delete
1080  * return void
1081  */
1082 static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
1083 {
1084         iks *request, *pubsub, *delete;
1085
1086         if (!(request = xmpp_pubsub_iq_create(client, "set"))) {
1087                 return;
1088         }
1089
1090         pubsub = iks_insert(request, "pubsub");
1091         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1092         delete = iks_insert(pubsub, "delete");
1093         iks_insert_attrib(delete, "node", node_name);
1094         ast_xmpp_client_send(client, request);
1095
1096         iks_delete(request);
1097 }
1098
1099 /*!
1100  * \brief Create a PubSub collection node.
1101  * \param client the configured XMPP client we use to connect to a XMPP server
1102  * \param collection_name The name to use for this collection
1103  * \return void.
1104  */
1105 static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
1106 {
1107         xmpp_pubsub_create_node(client, "collection", collection_name, NULL);
1108 }
1109
1110
1111 /*!
1112  * \brief Create a PubSub leaf node.
1113  * \param client the configured XMPP client we use to connect to a XMPP server
1114  * \param collection_name
1115  * \param leaf_name The name to use for this collection
1116  * \return void.
1117  */
1118 static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name,
1119                                     const char *leaf_name)
1120 {
1121         xmpp_pubsub_create_node(client, "leaf", leaf_name, collection_name);
1122 }
1123
1124 /*!
1125  * \brief Publish MWI to a PubSub node
1126  * \param client the configured XMPP client we use to connect to a XMPP server
1127  * \param mailbox The Mailbox
1128  * \param context The Context
1129  * \param oldmsgs Old messages
1130  * \param newmsgs New Messages
1131  * \return void
1132  */
1133 static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox,
1134                                     const char *context, const char *oldmsgs, const char *newmsgs)
1135 {
1136         char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT], eid_str[20];
1137         iks *mailbox_node, *request;
1138
1139         snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
1140
1141         if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting", AST_DEVSTATE_CACHABLE))) {
1142                 return;
1143         }
1144
1145         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1146         mailbox_node = iks_insert(request, "mailbox");
1147         iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
1148         iks_insert_attrib(mailbox_node, "eid", eid_str);
1149         iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
1150         iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
1151
1152         ast_xmpp_client_send(client, iks_root(request));
1153
1154         iks_delete(request);
1155 }
1156
1157 /*!
1158  * \brief Publish device state to a PubSub node
1159  * \param client the configured XMPP client we use to connect to a XMPP server
1160  * \param device the name of the device whose state to publish
1161  * \param device_state the state to publish
1162  * \return void
1163  */
1164 static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device,
1165                                              const char *device_state, unsigned int cachable)
1166 {
1167         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1168         iks *request, *state;
1169         char eid_str[20], cachable_str[2];
1170
1171         if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) {
1172                 return;
1173         }
1174
1175         if (ast_test_flag(&cfg->global->pubsub, XMPP_PUBSUB_AUTOCREATE)) {
1176                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1177                         xmpp_pubsub_create_node(client, "leaf", device, "device_state");
1178                 } else {
1179                         xmpp_pubsub_create_node(client, NULL, device, NULL);
1180                 }
1181         }
1182
1183         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1184         state = iks_insert(request, "state");
1185         iks_insert_attrib(state, "xmlns", "http://asterisk.org");
1186         iks_insert_attrib(state, "eid", eid_str);
1187         snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
1188         iks_insert_attrib(state, "cachable", cachable_str);
1189         iks_insert_cdata(state, device_state, strlen(device_state));
1190         ast_xmpp_client_send(client, iks_root(request));
1191         iks_delete(request);
1192 }
1193
1194 /*!
1195  * \brief Callback function for MWI events
1196  * \param ast_event
1197  * \param data void pointer to ast_client structure
1198  * \return void
1199  */
1200 static void xmpp_pubsub_mwi_cb(const struct ast_event *ast_event, void *data)
1201 {
1202         struct ast_xmpp_client *client = data;
1203         const char *mailbox, *context;
1204         char oldmsgs[10], newmsgs[10];
1205
1206         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1207                 /* If the event didn't originate from this server, don't send it back out. */
1208                 ast_debug(1, "Returning here\n");
1209                 return;
1210         }
1211
1212         mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
1213         context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
1214         snprintf(oldmsgs, sizeof(oldmsgs), "%d",
1215                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
1216         snprintf(newmsgs, sizeof(newmsgs), "%d",
1217                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
1218         xmpp_pubsub_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
1219 }
1220
1221 /*!
1222  * \brief Callback function for device state events
1223  * \param ast_event
1224  * \param data void pointer to ast_client structure
1225  * \return void
1226  */
1227 static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *data)
1228 {
1229         struct ast_xmpp_client *client = data;
1230         const char *device, *device_state;
1231         unsigned int cachable;
1232
1233         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1234                 /* If the event didn't originate from this server, don't send it back out. */
1235                 ast_debug(1, "Returning here\n");
1236                 return;
1237         }
1238
1239         device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
1240         device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
1241         cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
1242         xmpp_pubsub_publish_device_state(client, device, device_state, cachable);
1243 }
1244
1245 /*!
1246  * \brief Unsubscribe from a PubSub node
1247  * \param client the configured XMPP client we use to connect to a XMPP server
1248  * \param node the name of the node to which to unsubscribe from
1249  * \return void
1250  */
1251 static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
1252 {
1253         iks *request = xmpp_pubsub_iq_create(client, "set");
1254         iks *pubsub, *unsubscribe;
1255
1256         if (!request) {
1257                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->name);
1258                 return;
1259         }
1260
1261         pubsub = iks_insert(request, "pubsub");
1262         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1263         unsubscribe = iks_insert(pubsub, "unsubscribe");
1264         iks_insert_attrib(unsubscribe, "jid", client->jid->partial);
1265         iks_insert_attrib(unsubscribe, "node", node);
1266
1267         ast_xmpp_client_send(client, request);
1268         iks_delete(request);
1269 }
1270
1271 /*!
1272  * \brief Subscribe to a PubSub node
1273  * \param client the configured XMPP client we use to connect to a XMPP server
1274  * \param node the name of the node to which to subscribe
1275  * \return void
1276  */
1277 static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
1278 {
1279         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1280         iks *request = xmpp_pubsub_iq_create(client, "set");
1281         iks *pubsub, *subscribe;
1282
1283         if (!cfg || !cfg->global || !request) {
1284                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub subscription on client '%s'\n", client->name);
1285                 return;
1286         }
1287
1288         pubsub = iks_insert(request, "pubsub");
1289         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1290         subscribe = iks_insert(pubsub, "subscribe");
1291         iks_insert_attrib(subscribe, "jid", client->jid->partial);
1292         iks_insert_attrib(subscribe, "node", node);
1293         if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1294                 iks *options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
1295                 options = iks_insert(pubsub, "options");
1296                 x = iks_insert(options, "x");
1297                 iks_insert_attrib(x, "xmlns", "jabber:x:data");
1298                 iks_insert_attrib(x, "type", "submit");
1299                 sub_options = iks_insert(x, "field");
1300                 iks_insert_attrib(sub_options, "var", "FORM_TYPE");
1301                 iks_insert_attrib(sub_options, "type", "hidden");
1302                 iks_insert_cdata(iks_insert(sub_options, "value"),
1303                                  "http://jabber.org/protocol/pubsub#subscribe_options", 51);
1304                 sub_type = iks_insert(x, "field");
1305                 iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
1306                 iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
1307                 sub_depth = iks_insert(x, "field");
1308                 iks_insert_attrib(sub_depth, "var", "pubsub#subscription_depth");
1309                 iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
1310                 sub_expire = iks_insert(x, "field");
1311                 iks_insert_attrib(sub_expire, "var", "pubsub#expire");
1312                 iks_insert_cdata(iks_insert(sub_expire, "value"), "presence", 8);
1313         }
1314         ast_xmpp_client_send(client, request);
1315         iks_delete(request);
1316 }
1317
1318 /*!
1319  * \brief Callback for handling PubSub events
1320  * \param data void pointer to ast_xmpp_client structure
1321  * \param pak A pak
1322  * \return IKS_FILTER_EAT
1323  */
1324 static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
1325 {
1326         char *item_id, *device_state, *context, *cachable_str;
1327         int oldmsgs, newmsgs;
1328         iks *item, *item_content;
1329         struct ast_eid pubsub_eid;
1330         struct ast_event *event;
1331         unsigned int cachable = AST_DEVSTATE_CACHABLE;
1332         item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
1333         if (!item) {
1334                 ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
1335                 return IKS_FILTER_EAT;
1336         }
1337         item_id = iks_find_attrib(item, "id");
1338         item_content = iks_child(item);
1339         ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
1340         if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
1341                 ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
1342                 return IKS_FILTER_EAT;
1343         }
1344         if (!strcasecmp(iks_name(item_content), "state")) {
1345                 device_state = iks_find_cdata(item, "state");
1346                 if ((cachable_str = iks_find_cdata(item, "cachable"))) {
1347                         sscanf(cachable_str, "%30d", &cachable);
1348                 }
1349                 if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
1350                                             AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
1351                                             AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
1352                                             AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
1353                                             AST_EVENT_IE_END))) {
1354                         return IKS_FILTER_EAT;
1355                 }
1356         } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
1357                 context = strsep(&item_id, "@");
1358                 sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
1359                 sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
1360                 if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
1361                                             AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
1362                                             AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
1363                                             AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
1364                                             AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
1365                                             &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
1366                         return IKS_FILTER_EAT;
1367                 }
1368         } else {
1369                 ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
1370                           iks_name(item_content));
1371                 return IKS_FILTER_EAT;
1372         }
1373
1374         if (cachable == AST_DEVSTATE_CACHABLE) {
1375                 ast_event_queue_and_cache(event);
1376         } else {
1377                 ast_event_queue(event);
1378         }
1379
1380         return IKS_FILTER_EAT;
1381 }
1382
1383 static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
1384 {
1385         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1386         char *node_name, *error;
1387         int error_num;
1388         iks *orig_request, *orig_pubsub = iks_find(pak->x, "pubsub");
1389         struct ast_xmpp_client *client = data;
1390
1391         if (!cfg || !cfg->global) {
1392                 ast_log(LOG_ERROR, "No global configuration available\n");
1393                 return IKS_FILTER_EAT;
1394         }
1395
1396         if (!orig_pubsub) {
1397                 ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
1398                 return IKS_FILTER_EAT;
1399         }
1400
1401         orig_request = iks_child(orig_pubsub);
1402         error = iks_find_attrib(iks_find(pak->x, "error"), "code");
1403         node_name = iks_find_attrib(orig_request, "node");
1404
1405         if (!sscanf(error, "%30d", &error_num)) {
1406                 return IKS_FILTER_EAT;
1407         }
1408
1409         if (error_num > 399 && error_num < 500 && error_num != 404) {
1410                 ast_log(LOG_ERROR,
1411                         "Error performing operation on PubSub node %s, %s.\n", node_name, error);
1412                 return IKS_FILTER_EAT;
1413         } else if (error_num > 499 && error_num < 600) {
1414                 ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
1415                 return IKS_FILTER_EAT;
1416         }
1417
1418         if (!strcasecmp(iks_name(orig_request), "publish")) {
1419                 iks *request;
1420
1421                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1422                         if (iks_find(iks_find(orig_request, "item"), "state")) {
1423                                 xmpp_pubsub_create_leaf(client, "device_state", node_name);
1424                         } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
1425                                 xmpp_pubsub_create_leaf(client, "message_waiting", node_name);
1426                         }
1427                 } else {
1428                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1429                 }
1430
1431                 if ((request = xmpp_pubsub_iq_create(client, "set"))) {
1432                         iks_insert_node(request, orig_pubsub);
1433                         ast_xmpp_client_send(client, request);
1434                         iks_delete(request);
1435                 } else {
1436                         ast_log(LOG_ERROR, "PubSub publish could not create IQ\n");
1437                 }
1438
1439                 return IKS_FILTER_EAT;
1440         } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
1441                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1442                         xmpp_pubsub_create_collection(client, node_name);
1443                 } else {
1444                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1445                 }
1446         }
1447
1448         return IKS_FILTER_EAT;
1449 }
1450
1451 /*!
1452  * \brief Initialize collections for event distribution
1453  * \param client the configured XMPP client we use to connect to a XMPP server
1454  * \return void
1455  */
1456 static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
1457 {
1458         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1459         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1460
1461         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
1462                 return;
1463         }
1464
1465         xmpp_pubsub_unsubscribe(client, "device_state");
1466         xmpp_pubsub_unsubscribe(client, "message_waiting");
1467
1468         if (!(client->mwi_sub = ast_event_subscribe(AST_EVENT_MWI, xmpp_pubsub_mwi_cb, "xmpp_pubsub_mwi_subscription",
1469                                                     client, AST_EVENT_IE_END))) {
1470                 return;
1471         }
1472
1473         if (ast_enable_distributed_devstate()) {
1474                 return;
1475         }
1476         
1477
1478         if (!(client->device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
1479                                                              xmpp_pubsub_devstate_cb, "xmpp_pubsub_devstate_subscription", client, AST_EVENT_IE_END))) {
1480                 ast_event_unsubscribe(client->mwi_sub);
1481                 client->mwi_sub = NULL;
1482                 return;
1483         }
1484
1485         ast_event_dump_cache(client->device_state_sub);
1486
1487         xmpp_pubsub_subscribe(client, "device_state");
1488         xmpp_pubsub_subscribe(client, "message_waiting");
1489         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_event, client, IKS_RULE_TYPE,
1490                             IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
1491         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_error, client, IKS_RULE_TYPE,
1492                             IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1493
1494 }
1495
1496 /*! \brief Internal astobj2 callback function which returns the first resource, which is the highest priority one */
1497 static int xmpp_resource_immediate(void *obj, void *arg, int flags)
1498 {
1499         return CMP_MATCH | CMP_STOP;
1500 }
1501
1502 /*
1503  * \internal
1504  * \brief Dial plan function status(). puts the status of watched user
1505  * into a channel variable.
1506  * \param chan ast_channel
1507  * \param data
1508  * \retval 0 success
1509  * \retval -1 error
1510  */
1511 static int xmpp_status_exec(struct ast_channel *chan, const char *data)
1512 {
1513         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1514         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1515         struct ast_xmpp_buddy *buddy;
1516         struct ast_xmpp_resource *resource;
1517         char *s = NULL, status[2];
1518         int stat = 7;
1519         static int deprecation_warning = 0;
1520         AST_DECLARE_APP_ARGS(args,
1521                              AST_APP_ARG(sender);
1522                              AST_APP_ARG(jid);
1523                              AST_APP_ARG(variable);
1524                 );
1525         AST_DECLARE_APP_ARGS(jid,
1526                              AST_APP_ARG(screenname);
1527                              AST_APP_ARG(resource);
1528                 );
1529
1530         if (deprecation_warning++ % 10 == 0) {
1531                 ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
1532         }
1533
1534         if (ast_strlen_zero(data)) {
1535                 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
1536                 return 0;
1537         }
1538         s = ast_strdupa(data);
1539         AST_STANDARD_APP_ARGS(args, s);
1540
1541         if (args.argc != 3) {
1542                 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
1543                 return -1;
1544         }
1545
1546         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1547         if (jid.argc < 1 || jid.argc > 2) {
1548                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1549                 return -1;
1550         }
1551
1552         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1553                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1554                 return -1;
1555         }
1556
1557         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1558                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1559                 return -1;
1560         }
1561
1562         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1563                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1564         }
1565
1566         ao2_ref(buddy, -1);
1567
1568         if (resource) {
1569                 stat = resource->status;
1570                 ao2_ref(resource, -1);
1571         } else {
1572                 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
1573         }
1574
1575         snprintf(status, sizeof(status), "%d", stat);
1576         pbx_builtin_setvar_helper(chan, args.variable, status);
1577
1578         return 0;
1579 }
1580
1581 /*!
1582  * \internal
1583  * \brief Dial plan funtcion to retrieve the status of a buddy.
1584  * \param channel The associated ast_channel, if there is one
1585  * \param data The account, buddy JID, and optional timeout
1586  * timeout.
1587  * \retval 0 success
1588  * \retval -1 failure
1589  */
1590 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1591 {
1592         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1593         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1594         struct ast_xmpp_buddy *buddy;
1595         struct ast_xmpp_resource *resource;
1596         int stat = 7;
1597         AST_DECLARE_APP_ARGS(args,
1598                              AST_APP_ARG(sender);
1599                              AST_APP_ARG(jid);
1600                 );
1601         AST_DECLARE_APP_ARGS(jid,
1602                              AST_APP_ARG(screenname);
1603                              AST_APP_ARG(resource);
1604                 );
1605
1606         if (ast_strlen_zero(data)) {
1607                 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
1608                 return 0;
1609         }
1610         AST_STANDARD_APP_ARGS(args, data);
1611
1612         if (args.argc != 2) {
1613                 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
1614                 return -1;
1615         }
1616
1617         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1618         if (jid.argc < 1 || jid.argc > 2) {
1619                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1620                 return -1;
1621         }
1622
1623         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1624                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1625                 return -1;
1626         }
1627
1628         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1629                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1630                 return -1;
1631         }
1632
1633         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1634                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1635         }
1636
1637         ao2_ref(buddy, -1);
1638
1639         if (resource) {
1640                 stat = resource->status;
1641                 ao2_ref(resource, -1);
1642         } else {
1643                 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
1644         }
1645
1646         snprintf(buf, buflen, "%d", stat);
1647
1648         return 0;
1649 }
1650
1651 static struct ast_custom_function jabberstatus_function = {
1652         .name = "JABBER_STATUS",
1653         .read = acf_jabberstatus_read,
1654 };
1655
1656 /*!
1657  * \brief Application to join a chat room
1658  * \param chan ast_channel
1659  * \param data  Data is sender|jid|nickname.
1660  * \retval 0 success
1661  * \retval -1 error
1662  */
1663 static int xmpp_join_exec(struct ast_channel *chan, const char *data)
1664 {
1665         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1666         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1667         char *s, nick[XMPP_MAX_RESJIDLEN];
1668         AST_DECLARE_APP_ARGS(args,
1669                              AST_APP_ARG(sender);
1670                              AST_APP_ARG(jid);
1671                              AST_APP_ARG(nick);
1672                 );
1673
1674         if (ast_strlen_zero(data)) {
1675                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1676                 return -1;
1677         }
1678         s = ast_strdupa(data);
1679
1680         AST_STANDARD_APP_ARGS(args, s);
1681         if (args.argc < 2 || args.argc > 3) {
1682                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1683                 return -1;
1684         }
1685
1686         if (strchr(args.jid, '/')) {
1687                 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1688                 return -1;
1689         }
1690
1691         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1692                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1693                 return -1;
1694         }
1695
1696         if (ast_strlen_zero(args.nick)) {
1697                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1698                         snprintf(nick, sizeof(nick), "asterisk");
1699                 } else {
1700                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1701                 }
1702         } else {
1703                 snprintf(nick, sizeof(nick), "%s", args.nick);
1704         }
1705
1706         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1707                 ast_xmpp_chatroom_join(clientcfg->client, args.jid, nick);
1708         } else {
1709                 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1710         }
1711
1712         return 0;
1713 }
1714
1715 /*!
1716  * \brief Application to leave a chat room
1717  * \param chan ast_channel
1718  * \param data  Data is sender|jid|nickname.
1719  * \retval 0 success
1720  * \retval -1 error
1721  */
1722 static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
1723 {
1724         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1725         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1726         char *s, nick[XMPP_MAX_RESJIDLEN];
1727         AST_DECLARE_APP_ARGS(args,
1728                              AST_APP_ARG(sender);
1729                              AST_APP_ARG(jid);
1730                              AST_APP_ARG(nick);
1731                 );
1732
1733         if (ast_strlen_zero(data)) {
1734                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1735                 return -1;
1736         }
1737         s = ast_strdupa(data);
1738
1739         AST_STANDARD_APP_ARGS(args, s);
1740         if (args.argc < 2 || args.argc > 3) {
1741                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1742                 return -1;
1743         }
1744
1745         if (strchr(args.jid, '/')) {
1746                 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1747                 return -1;
1748         }
1749
1750         if (ast_strlen_zero(args.jid) || !strchr(args.jid, '@')) {
1751                 ast_log(LOG_ERROR, "No jabber ID specified\n");
1752                 return -1;
1753         }
1754
1755         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1756                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1757                 return -1;
1758         }
1759
1760         if (ast_strlen_zero(args.nick)) {
1761                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1762                         snprintf(nick, sizeof(nick), "asterisk");
1763                 } else {
1764                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1765                 }
1766         } else {
1767                 snprintf(nick, sizeof(nick), "%s", args.nick);
1768         }
1769
1770         ast_xmpp_chatroom_leave(clientcfg->client, args.jid, nick);
1771
1772         return 0;
1773 }
1774
1775 /*!
1776  * \internal
1777  * \brief Dial plan function to send a message.
1778  * \param chan ast_channel
1779  * \param data  Data is account,jid,message.
1780  * \retval 0 success
1781  * \retval -1 failure
1782  */
1783 static int xmpp_send_exec(struct ast_channel *chan, const char *data)
1784 {
1785         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1786         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1787         char *s;
1788         AST_DECLARE_APP_ARGS(args,
1789                              AST_APP_ARG(sender);
1790                              AST_APP_ARG(recipient);
1791                              AST_APP_ARG(message);
1792                 );
1793
1794         if (ast_strlen_zero(data)) {
1795                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1796                 return -1;
1797         }
1798         s = ast_strdupa(data);
1799
1800         AST_STANDARD_APP_ARGS(args, s);
1801
1802         if ((args.argc < 3) || ast_strlen_zero(args.message) || !strchr(args.recipient, '@')) {
1803                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1804                 return -1;
1805         }
1806
1807         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1808                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1809                 return -1;
1810         }
1811
1812         ast_xmpp_client_send_message(clientcfg->client, args.recipient, args.message);
1813
1814         return 0;
1815 }
1816
1817 /*!
1818  * \brief Application to send a message to a groupchat.
1819  * \param chan ast_channel
1820  * \param data  Data is sender|groupchat|message.
1821  * \retval 0 success
1822  * \retval -1 error
1823  */
1824 static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
1825 {
1826         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1827         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1828         char *s, nick[XMPP_MAX_RESJIDLEN];
1829         AST_DECLARE_APP_ARGS(args,
1830                              AST_APP_ARG(sender);
1831                              AST_APP_ARG(groupchat);
1832                              AST_APP_ARG(message);
1833                              AST_APP_ARG(nick);
1834                 );
1835
1836         if (ast_strlen_zero(data)) {
1837                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1838                 return -1;
1839         }
1840         s = ast_strdupa(data);
1841
1842         AST_STANDARD_APP_ARGS(args, s);
1843         if ((args.argc < 3) || (args.argc > 4) || ast_strlen_zero(args.message) || !strchr(args.groupchat, '@')) {
1844                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1845                 return -1;
1846         }
1847
1848         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1849                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1850                 return -1;
1851         }
1852
1853         if (ast_strlen_zero(args.nick) || args.argc == 3) {
1854                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1855                         snprintf(nick, sizeof(nick), "asterisk");
1856                 } else {
1857                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1858                 }
1859         } else {
1860                 snprintf(nick, sizeof(nick), "%s", args.nick);
1861         }
1862
1863         ast_xmpp_chatroom_send(clientcfg->client, nick, args.groupchat, args.message);
1864
1865         return 0;
1866 }
1867
1868 /*!
1869  * \internal
1870  * \brief Dial plan function to receive a message.
1871  * \param channel The associated ast_channel, if there is one
1872  * \param data The account, JID, and optional timeout
1873  * timeout.
1874  * \retval 0 success
1875  * \retval -1 failure
1876  */
1877 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1878 {
1879         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1880         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1881         char *parse = NULL;
1882         int timeout, jidlen, resourcelen, found = 0;
1883         struct timeval start;
1884         long diff = 0;
1885         struct ast_xmpp_message *message;
1886         AST_DECLARE_APP_ARGS(args,
1887                              AST_APP_ARG(account);
1888                              AST_APP_ARG(jid);
1889                              AST_APP_ARG(timeout);
1890                 );
1891         AST_DECLARE_APP_ARGS(jid,
1892                              AST_APP_ARG(screenname);
1893                              AST_APP_ARG(resource);
1894                 );
1895
1896         if (ast_strlen_zero(data)) {
1897                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1898                 return -1;
1899         }
1900
1901         parse = ast_strdupa(data);
1902         AST_STANDARD_APP_ARGS(args, parse);
1903
1904         if (args.argc < 2 || args.argc > 3) {
1905                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1906                 return -1;
1907         }
1908
1909         parse = ast_strdupa(args.jid);
1910         AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
1911         if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > XMPP_MAX_JIDLEN) {
1912                 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
1913                 return -1;
1914         }
1915
1916         if (ast_strlen_zero(args.timeout)) {
1917                 timeout = 20;
1918         } else {
1919                 sscanf(args.timeout, "%d", &timeout);
1920                 if (timeout <= 0) {
1921                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
1922                         return -1;
1923                 }
1924         }
1925
1926         jidlen = strlen(jid.screenname);
1927         resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
1928
1929         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.account))) {
1930                 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
1931                 return -1;
1932         }
1933
1934         ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
1935
1936         start = ast_tvnow();
1937
1938         if (ast_autoservice_start(chan) < 0) {
1939                 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
1940                 return -1;
1941         }
1942
1943         /* search the messages list, grab the first message that matches with
1944          * the from JID we're expecting, and remove it from the messages list */
1945         while (diff < timeout) {
1946                 struct timespec ts = { 0, };
1947                 struct timeval wait;
1948                 int res = 0;
1949
1950                 wait = ast_tvadd(start, ast_tv(timeout, 0));
1951                 ts.tv_sec = wait.tv_sec;
1952                 ts.tv_nsec = wait.tv_usec * 1000;
1953
1954                 /* wait up to timeout seconds for an incoming message */
1955                 ast_mutex_lock(&messagelock);
1956                 if (AST_LIST_EMPTY(&clientcfg->client->messages)) {
1957                         res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
1958                 }
1959                 ast_mutex_unlock(&messagelock);
1960                 if (res == ETIMEDOUT) {
1961                         ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
1962                         break;
1963                 }
1964
1965                 AST_LIST_LOCK(&clientcfg->client->messages);
1966                 AST_LIST_TRAVERSE_SAFE_BEGIN(&clientcfg->client->messages, message, list) {
1967                         if (jid.argc == 1) {
1968                                 /* no resource provided, compare bare JIDs */
1969                                 if (strncasecmp(jid.screenname, message->from, jidlen)) {
1970                                         continue;
1971                                 }
1972                         } else {
1973                                 /* resource appended, compare bare JIDs and resources */
1974                                 char *resource = strchr(message->from, '/');
1975                                 if (!resource || strlen(resource) == 0) {
1976                                         ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", message->from);
1977                                         if (strncasecmp(jid.screenname, message->from, jidlen)) {
1978                                                 continue;
1979                                         }
1980                                 } else {
1981                                         resource ++;
1982                                         if (strncasecmp(jid.screenname, message->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
1983                                                 continue;
1984                                         }
1985                                 }
1986                         }
1987                         /* check if the message is not too old */
1988                         if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
1989                                 ast_debug(3, "Found old message from %s, deleting it\n", message->from);
1990                                 AST_LIST_REMOVE_CURRENT(list);
1991                                 xmpp_message_destroy(message);
1992                                 continue;
1993                         }
1994                         found = 1;
1995                         ast_copy_string(buf, message->message, buflen);
1996                         AST_LIST_REMOVE_CURRENT(list);
1997                         xmpp_message_destroy(message);
1998                         break;
1999                 }
2000                 AST_LIST_TRAVERSE_SAFE_END;
2001                 AST_LIST_UNLOCK(&clientcfg->client->messages);
2002                 if (found) {
2003                         break;
2004                 }
2005
2006                 /* check timeout */
2007                 diff = ast_tvdiff_ms(ast_tvnow(), start);
2008         }
2009
2010         if (ast_autoservice_stop(chan) < 0) {
2011                 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
2012         }
2013
2014         /* return if we timed out */
2015         if (!found) {
2016                 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
2017                 return -1;
2018         }
2019
2020         return 0;
2021 }
2022
2023 static struct ast_custom_function jabberreceive_function = {
2024         .name = "JABBER_RECEIVE",
2025         .read = acf_jabberreceive_read,
2026 };
2027
2028 /*!
2029  * \internal
2030  * \brief Delete old messages from a given JID
2031  * Messages stored during more than client->message_timeout are deleted
2032  * \param client Asterisk's XMPP client
2033  * \param from the JID we received messages from
2034  * \retval the number of deleted messages
2035  */
2036 static int delete_old_messages(struct ast_xmpp_client *client, char *from)
2037 {
2038         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2039         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2040         int deleted = 0, isold = 0;
2041         struct ast_xmpp_message *message = NULL;
2042
2043         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2044                 return 0;
2045         }
2046
2047         AST_LIST_LOCK(&client->messages);
2048         AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, message, list) {
2049                 if (isold) {
2050                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2051                                 AST_LIST_REMOVE_CURRENT(list);
2052                                 xmpp_message_destroy(message);
2053                                 deleted++;
2054                         }
2055                 } else if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
2056                         isold = 1;
2057                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2058                                 AST_LIST_REMOVE_CURRENT(list);
2059                                 xmpp_message_destroy(message);
2060                                 deleted++;
2061                         }
2062                 }
2063         }
2064         AST_LIST_TRAVERSE_SAFE_END;
2065         AST_LIST_UNLOCK(&client->messages);
2066
2067         return deleted;
2068 }
2069
2070 static int xmpp_send_cb(const struct ast_msg *msg, const char *to, const char *from)
2071 {
2072         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2073         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2074         char *sender, *dest;
2075         int res;
2076
2077         sender = ast_strdupa(from);
2078         strsep(&sender, ":");
2079         dest = ast_strdupa(to);
2080         strsep(&dest, ":");
2081
2082         if (ast_strlen_zero(sender)) {
2083                 ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for XMPP\n", from);
2084                 return -1;
2085         }
2086
2087         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, sender))) {
2088                 ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
2089                 return -1;
2090         }
2091
2092         ast_debug(1, "Sending message to '%s' from '%s'\n", dest, clientcfg->name);
2093
2094         if ((res = ast_xmpp_client_send_message(clientcfg->client, dest, ast_msg_get_body(msg))) != IKS_OK) {
2095                 ast_log(LOG_WARNING, "Failed to send XMPP message (%d).\n", res);
2096         }
2097
2098         return res == IKS_OK ? 0 : -1;
2099 }
2100
2101 static const struct ast_msg_tech msg_tech = {
2102         .name = "xmpp",
2103         .msg_send = xmpp_send_cb,
2104 };
2105
2106 /*! \brief Internal function which changes the XMPP client state */
2107 static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
2108 {
2109         client->state = state;
2110 }
2111
2112 /*! \brief Internal function which creates a buddy on a client */
2113 static struct ast_xmpp_buddy *xmpp_client_create_buddy(struct ao2_container *container, const char *id)
2114 {
2115         struct ast_xmpp_buddy *buddy;
2116
2117         if (!(buddy = ao2_alloc(sizeof(*buddy), xmpp_buddy_destructor))) {
2118                 return NULL;
2119         }
2120
2121         if (!(buddy->resources = ao2_container_alloc(RESOURCE_BUCKETS, xmpp_resource_hash, xmpp_resource_cmp))) {
2122                 ao2_ref(buddy, -1);
2123                 return NULL;
2124         }
2125
2126         ast_copy_string(buddy->id, id, sizeof(buddy->id));
2127
2128         /* Assume we need to subscribe to get their presence until proven otherwise */
2129         buddy->subscribe = 1;
2130
2131         ao2_link(container, buddy);
2132
2133         return buddy;
2134 }
2135
2136 /*! \brief Helper function which unsubscribes a user and removes them from the roster */
2137 static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
2138 {
2139         iks *iq, *query = NULL, *item = NULL;
2140
2141         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, user,
2142                                                        "Goodbye. Your status is no longer required.\n"))) {
2143                 return -1;
2144         }
2145
2146         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item"))) {
2147                 ast_log(LOG_WARNING, "Could not allocate memory for roster removal of '%s' from client '%s'\n",
2148                         user, client->name);
2149                 goto done;
2150         }
2151
2152         iks_insert_attrib(iq, "from", client->jid->full);
2153         iks_insert_attrib(iq, "type", "set");
2154         iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
2155         iks_insert_node(iq, query);
2156         iks_insert_attrib(item, "jid", user);
2157         iks_insert_attrib(item, "subscription", "remove");
2158         iks_insert_node(query, item);
2159
2160         if (ast_xmpp_client_send(client, iq)) {
2161                 ast_log(LOG_WARNING, "Could not send roster removal request of '%s' from client '%s'\n",
2162                         user, client->name);
2163         }
2164
2165 done:
2166         iks_delete(item);
2167         iks_delete(query);
2168         iks_delete(iq);
2169
2170         return 0;
2171 }
2172
2173 /*! \brief Callback function which subscribes to a user if needed */
2174 static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
2175 {
2176         struct ast_xmpp_buddy *buddy = obj;
2177         struct ast_xmpp_client *client = arg;
2178
2179         if (!buddy->subscribe) {
2180                 return 0;
2181         }
2182
2183         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, buddy->id,
2184                                                        "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
2185                 ast_log(LOG_WARNING, "Could not send subscription for '%s' on client '%s'\n",
2186                         buddy->id, client->name);
2187         }
2188
2189         buddy->subscribe = 0;
2190
2191         return 0;
2192 }
2193
2194 /*! \brief Hook function called when roster is received from server */
2195 static int xmpp_roster_hook(void *data, ikspak *pak)
2196 {
2197         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2198         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2199         struct ast_xmpp_client *client = data;
2200         iks *item;
2201
2202         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2203                 return IKS_FILTER_EAT;
2204         }
2205
2206         for (item = iks_child(pak->query); item; item = iks_next(item)) {
2207                 struct ast_xmpp_buddy *buddy;
2208
2209                 if (iks_strcmp(iks_name(item), "item")) {
2210                         continue;
2211                 }
2212
2213                 if (!(buddy = ao2_find(client->buddies, iks_find_attrib(item, "jid"), OBJ_KEY))) {
2214                         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOPRUNE)) {
2215                                 /* The buddy has not been specified in the configuration file, we no longer
2216                                  * want them on our buddy list or to receive their presence. */
2217                                 if (xmpp_client_unsubscribe_user(client, iks_find_attrib(item, "jid"))) {
2218                                         ast_log(LOG_ERROR, "Could not unsubscribe user '%s' on client '%s'\n",
2219                                                 iks_find_attrib(item, "jid"), client->name);
2220                                 }
2221                                 continue;
2222                         }
2223
2224                         if (!(buddy = xmpp_client_create_buddy(client->buddies, iks_find_attrib(item, "jid")))) {
2225                                 ast_log(LOG_ERROR, "Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item, "jid"),
2226                                         client->name);
2227                                 continue;
2228                         }
2229                 }
2230
2231                 /* Determine if we need to subscribe to their presence or not */
2232                 if (!iks_strcmp(iks_find_attrib(item, "subscription"), "none") ||
2233                     !iks_strcmp(iks_find_attrib(item, "subscription"), "from")) {
2234                         buddy->subscribe = 1;
2235                 } else {
2236                         buddy->subscribe = 0;
2237                 }
2238
2239                 ao2_ref(buddy, -1);
2240         }
2241
2242         /* If autoregister is enabled we need to go through every buddy that we need to subscribe to and do so */
2243         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOREGISTER)) {
2244                 ao2_callback(client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, client);
2245         }
2246
2247         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
2248
2249         return IKS_FILTER_EAT;
2250 }
2251
2252 /*! \brief Internal function which changes the presence status of an XMPP client */
2253 static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
2254 {
2255         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2256         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2257         iks *presence = NULL, *cnode = NULL, *priority = NULL;
2258         char priorityS[10];
2259
2260         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2261             !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new("c")) || !(priority = iks_new("priority"))) {
2262                 ast_log(LOG_ERROR, "Unable to allocate stanzas for setting presence status for client '%s'\n", client->name);
2263                 goto done;
2264         }
2265
2266         if (!ast_strlen_zero(to)) {
2267                 iks_insert_attrib(presence, "to", to);
2268         }
2269
2270         if (!ast_strlen_zero(from)) {
2271                 iks_insert_attrib(presence, "from", from);
2272         }
2273
2274         snprintf(priorityS, sizeof(priorityS), "%d", clientcfg->priority);
2275         iks_insert_cdata(priority, priorityS, strlen(priorityS));
2276         iks_insert_node(presence, priority);
2277         iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
2278         iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
2279         iks_insert_attrib(cnode, "ext", "voice-v1 video-v1 camera-v1");
2280         iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
2281         iks_insert_node(presence, cnode);
2282         ast_xmpp_client_send(client, presence);
2283
2284 done:
2285         iks_delete(cnode);
2286         iks_delete(presence);
2287         iks_delete(priority);
2288 }
2289
2290 /*! \brief Hook function called when client receives a service discovery get message */
2291 static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
2292 {
2293         struct ast_xmpp_client *client = data;
2294         iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL;
2295
2296         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) ||
2297             !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) ||
2298             !(audio = iks_new("feature")) || !(video = iks_new("feature"))) {
2299                 ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
2300                         pak->from->full, client->name);
2301                 goto end;
2302         }
2303
2304         iks_insert_attrib(iq, "from", client->jid->full);
2305
2306         if (pak->from) {
2307                 iks_insert_attrib(iq, "to", pak->from->full);
2308         }
2309
2310         iks_insert_attrib(iq, "type", "result");
2311         iks_insert_attrib(iq, "id", pak->id);
2312         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2313         iks_insert_attrib(ident, "category", "client");
2314         iks_insert_attrib(ident, "type", "pc");
2315         iks_insert_attrib(ident, "name", "asterisk");
2316         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2317
2318         iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2319         iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1");
2320         iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1");
2321         iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1");
2322         iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio");
2323         iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video");
2324         iks_insert_node(iq, query);
2325         iks_insert_node(query, ident);
2326         iks_insert_node(query, google);
2327         iks_insert_node(query, disco);
2328         iks_insert_node(query, jingle);
2329         iks_insert_node(query, ice);
2330         iks_insert_node(query, rtp);
2331         iks_insert_node(query, audio);
2332         iks_insert_node(query, video);
2333         ast_xmpp_client_send(client, iq);
2334
2335 end:
2336         iks_delete(query);
2337         iks_delete(video);
2338         iks_delete(audio);
2339         iks_delete(rtp);
2340         iks_delete(ice);
2341         iks_delete(jingle);
2342         iks_delete(google);
2343         iks_delete(ident);
2344         iks_delete(disco);
2345         iks_delete(iq);
2346
2347         return IKS_FILTER_EAT;
2348 }
2349
2350 /*! \brief Hook function called when client receives a service discovery result message */
2351 static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
2352 {
2353         struct ast_xmpp_client *client = data;
2354         struct ast_xmpp_buddy *buddy;
2355         struct ast_xmpp_resource *resource;
2356
2357         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2358                 return IKS_FILTER_EAT;
2359         }
2360
2361         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY))) {
2362                 ao2_ref(buddy, -1);
2363                 return IKS_FILTER_EAT;
2364         }
2365
2366         ao2_lock(resource);
2367
2368         if (iks_find_with_attrib(pak->query, "feature", "var", "urn:xmpp:jingle:1")) {
2369                 resource->caps.jingle = 1;
2370         }
2371
2372         ao2_unlock(resource);
2373
2374         ao2_ref(resource, -1);
2375         ao2_ref(buddy, -1);
2376
2377         return IKS_FILTER_EAT;
2378 }
2379
2380 /*! \brief Hook function called when client finishes authenticating with the server */
2381 static int xmpp_connect_hook(void *data, ikspak *pak)
2382 {
2383         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2384         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2385         struct ast_xmpp_client *client = data;
2386         iks *roster;
2387
2388         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2389                 return -1;
2390         }
2391
2392         client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
2393
2394         if (ast_test_flag(&clientcfg->flags, XMPP_DISTRIBUTE_EVENTS)) {
2395                 xmpp_init_event_distribution(client);
2396         }
2397
2398         if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
2399                 ast_log(LOG_ERROR, "Unable to allocate memory for roster request for client '%s'\n", client->name);
2400                 return -1;
2401         }
2402
2403         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);
2404         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);
2405
2406         iks_insert_attrib(roster, "id", "roster");
2407         ast_xmpp_client_send(client, roster);
2408
2409         iks_filter_remove_hook(client->filter, xmpp_connect_hook);
2410         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);
2411
2412         xmpp_client_set_presence(client, NULL, client->jid->full, clientcfg->status, clientcfg->statusmsg);
2413         xmpp_client_change_state(client, XMPP_STATE_ROSTER);
2414
2415         return IKS_FILTER_EAT;
2416 }
2417
2418 /*! \brief Logging hook function */
2419 static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
2420 {
2421         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2422         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2423         struct ast_xmpp_client *client = data;
2424
2425         if (!ast_strlen_zero(xmpp)) {
2426                 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
2427         }
2428
2429         if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
2430                 return;
2431         }
2432
2433         if (!incoming) {
2434                 if (strlen(xmpp) == 1) {
2435                         if (option_debug > 2  && xmpp[0] == ' ') {
2436                                 ast_verbose("\n<--- XMPP keep alive from '%s' --->\n", client->name);
2437                         }
2438                 } else {
2439                         ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2440                 }
2441         } else {
2442                 ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2443         }
2444 }
2445
2446 /*! \brief Internal function which sends a raw message */
2447 static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
2448 {
2449         int ret;
2450 #ifdef HAVE_OPENSSL
2451         int len = strlen(message);
2452
2453         if (xmpp_is_secure(client)) {
2454                 ret = SSL_write(client->ssl_session, message, len);
2455                 if (ret) {
2456                         /* Log the message here, because iksemel's logHook is
2457                            unaccessible */
2458                         xmpp_log_hook(client, message, len, 0);
2459                         return IKS_OK;
2460                 }
2461         }
2462 #endif
2463         /* If needed, data will be sent unencrypted, and logHook will
2464            be called inside iks_send_raw */
2465         ret = iks_send_raw(client->parser, message);
2466         if (ret != IKS_OK) {
2467                 return ret;
2468         }
2469
2470         return IKS_OK;
2471 }
2472
2473 /*! \brief Helper function which sends an XMPP stream header to the server */
2474 static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
2475 {
2476         char *namespace = ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client";
2477         char msg[91 + strlen(namespace) + 6 + strlen(to) + 16 + 1];
2478
2479         snprintf(msg, sizeof(msg), "<?xml version='1.0'?>"
2480                  "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
2481                  "%s' to='%s' version='1.0'>", namespace, to);
2482
2483         return xmpp_client_send_raw_message(client, msg);
2484 }
2485
2486 int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
2487 {
2488         return xmpp_client_send_raw_message(client, iks_string(iks_stack(stanza), stanza));
2489 }
2490
2491 /*! \brief Internal function called when we need to request TLS support */
2492 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2493 {
2494         /* If the client connection is already secure we can jump straight to authenticating */
2495         if (xmpp_is_secure(client)) {
2496                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2497                 return 0;
2498         }
2499
2500 #ifndef HAVE_OPENSSL
2501         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->name);
2502         return -1;
2503 #else
2504         if (iks_send_raw(client->parser, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
2505                 ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be started.\n", client->name);
2506                 return -1;
2507         }
2508
2509         client->stream_flags |= TRY_SECURE;
2510
2511         xmpp_client_change_state(client, XMPP_STATE_REQUESTED_TLS);
2512
2513         return 0;
2514 #endif
2515 }
2516
2517 /*! \brief Internal function called when we receive a response to our TLS initiation request */
2518 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2519 {
2520 #ifdef HAVE_OPENSSL
2521         int sock;
2522 #endif
2523
2524         if (!strcmp(iks_name(node), "success")) {
2525                 /* TLS is up and working, we can move on to authenticating now */
2526                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2527                 return 0;
2528         } else if (!strcmp(iks_name(node), "failure")) {
2529                 /* TLS negotiation was a failure, close it on down! */
2530                 return -1;
2531         } else if (strcmp(iks_name(node), "proceed")) {
2532                 /* Ignore any other responses */
2533                 return 0;
2534         }
2535
2536 #ifndef HAVE_OPENSSL
2537         ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->name);
2538         return -1;
2539 #else
2540         client->ssl_method = SSLv3_method();
2541         if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
2542                 goto failure;
2543         }
2544
2545         if (!(client->ssl_session = SSL_new(client->ssl_context))) {
2546                 goto failure;
2547         }
2548
2549         sock = iks_fd(client->parser);
2550         if (!SSL_set_fd(client->ssl_session, sock)) {
2551                 goto failure;
2552         }
2553
2554         if (!SSL_connect(client->ssl_session)) {
2555                 goto failure;
2556         }
2557
2558         client->stream_flags &= (~TRY_SECURE);
2559         client->stream_flags |= SECURE;
2560
2561         if (xmpp_send_stream_header(client, cfg, client->jid->server) != IKS_OK) {
2562                 ast_log(LOG_ERROR, "TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
2563                         client->name);
2564                 return -1;
2565         }
2566
2567         ast_debug(1, "TLS connection for client '%s' started with server\n", client->name);
2568
2569         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2570
2571         return 0;
2572
2573 failure:
2574         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
2575         return -1;
2576 #endif
2577 }
2578
2579 /*! \brief Internal function called when we need to authenticate using non-SASL */
2580 static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2581 {
2582         iks *iq = NULL, *query = NULL;
2583         char buf[41], sidpass[100];
2584
2585         if (!(iq = iks_new("iq")) || !(query = iks_insert(iq, "query"))) {
2586                 ast_log(LOG_ERROR, "Stanzas could not be allocated for authentication on client '%s'\n", client->name);
2587                 iks_delete(iq);
2588                 return -1;
2589         }
2590
2591         iks_insert_attrib(iq, "type", "set");
2592         iks_insert_cdata(iks_insert(query, "username"), client->jid->user, 0);
2593         iks_insert_cdata(iks_insert(query, "resource"), client->jid->resource, 0);
2594
2595         iks_insert_attrib(query, "xmlns", "jabber:iq:auth");
2596         snprintf(sidpass, sizeof(sidpass), "%s%s", iks_find_attrib(node, "id"), cfg->password);
2597         ast_sha1_hash(buf, sidpass);
2598         iks_insert_cdata(iks_insert(query, "digest"), buf, 0);
2599
2600         ast_xmpp_client_lock(client);
2601         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);
2602         iks_insert_attrib(iq, "id", client->mid);
2603         ast_xmpp_increment_mid(client->mid);
2604         ast_xmpp_client_unlock(client);
2605
2606         iks_insert_attrib(iq, "to", client->jid->server);
2607
2608         ast_xmpp_client_send(client, iq);
2609
2610         iks_delete(iq);
2611
2612         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2613
2614         return 0;
2615 }
2616
2617 /*! \brief Internal function called when we need to authenticate using SASL */
2618 static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2619 {
2620         int features, len = strlen(client->jid->user) + strlen(cfg->password) + 3;
2621         iks *auth;
2622         char combined[len];
2623         char base64[(len + 2) * 4 / 3];
2624
2625         if (strcmp(iks_name(node), "stream:features")) {
2626                 /* Ignore anything beside stream features */
2627                 return 0;
2628         }
2629
2630         features = iks_stream_features(node);
2631
2632         if ((features & IKS_STREAM_SASL_MD5) && !xmpp_is_secure(client)) {
2633                 if (iks_start_sasl(client->parser, IKS_SASL_DIGEST_MD5, (char*)client->jid->user, (char*)cfg->password) != IKS_OK) {
2634                         ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->name);
2635                         return -1;
2636                 }
2637
2638                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2639                 return 0;
2640         }
2641
2642         /* Our only other available option is plain so if they don't support it, bail out now */
2643         if (!(features & IKS_STREAM_SASL_PLAIN)) {
2644                 ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->name);
2645                 return -1;
2646         }
2647
2648         if (!(auth = iks_new("auth"))) {
2649                 ast_log(LOG_ERROR, "Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->name);
2650                 return -1;
2651         }
2652
2653         iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL);
2654         iks_insert_attrib(auth, "mechanism", "PLAIN");
2655
2656         if (strchr(client->jid->user, '/')) {
2657                 char *user = ast_strdupa(client->jid->user);
2658
2659                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, strsep(&user, "/"), 0, cfg->password);
2660         } else {
2661                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, client->jid->user, 0, cfg->password);
2662         }
2663
2664         ast_base64encode(base64, (const unsigned char *) combined, len - 1, (len + 2) * 4 / 3);
2665         iks_insert_cdata(auth, base64, 0);
2666
2667         ast_xmpp_client_send(client, auth);
2668
2669         iks_delete(auth);
2670
2671         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2672
2673         return 0;
2674 }
2675
2676 /*! \brief Internal function called when we need to authenticate */
2677 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2678 {
2679         return ast_test_flag(&cfg->flags, XMPP_USESASL) ? xmpp_client_authenticate_sasl(client, cfg, type, node) : xmpp_client_authenticate_digest(client, cfg, type, node);
2680 }
2681
2682 /*! \brief Internal function called when we are authenticating */
2683 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2684 {
2685         int features;
2686
2687         if (!strcmp(iks_name(node), "success")) {
2688                 /* Authentication was a success, yay! */
2689                 xmpp_send_stream_header(client, cfg, client->jid->server);
2690
2691                 return 0;
2692         } else if (!strcmp(iks_name(node), "failure")) {
2693                 /* Authentication was a bust, disconnect and reconnect later */
2694                 return -1;
2695         } else if (strcmp(iks_name(node), "stream:features")) {
2696                 /* Ignore any other responses */
2697                 return 0;
2698         }
2699
2700         features = iks_stream_features(node);
2701
2702         if (features & IKS_STREAM_BIND) {
2703                 iks *auth;
2704
2705                 if (!(auth = iks_make_resource_bind(client->jid))) {
2706                         ast_log(LOG_ERROR, "Failed to allocate memory for stream bind on client '%s'\n", client->name);
2707                         return -1;
2708                 }
2709
2710                 ast_xmpp_client_lock(client);
2711                 iks_insert_attrib(auth, "id", client->mid);
2712                 ast_xmpp_increment_mid(client->mid);
2713                 ast_xmpp_client_unlock(client);
2714                 ast_xmpp_client_send(client, auth);
2715
2716                 iks_delete(auth);
2717
2718                 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);
2719         }
2720
2721         if (features & IKS_STREAM_SESSION) {
2722                 iks *auth;
2723
2724                 if (!(auth = iks_make_session())) {
2725                         ast_log(LOG_ERROR, "Failed to allocate memory for stream session on client '%s'\n", client->name);
2726                         return -1;
2727                 }
2728
2729                 iks_insert_attrib(auth, "id", "auth");
2730                 ast_xmpp_client_lock(client);
2731                 ast_xmpp_increment_mid(client->mid);
2732                 ast_xmpp_client_unlock(client);
2733                 ast_xmpp_client_send(client, auth);
2734
2735                 iks_delete(auth);
2736
2737                 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);
2738         }
2739
2740         return 0;
2741 }
2742
2743 /*! \brief Internal function called when we should authenticate as a component */
2744 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2745 {
2746         char secret[160], shasum[320], message[344];
2747         ikspak *pak = iks_packet(node);
2748
2749         snprintf(secret, sizeof(secret), "%s%s", pak->id, cfg->password);
2750         ast_sha1_hash(shasum, secret);
2751         snprintf(message, sizeof(message), "<handshake>%s</handshake>", shasum);
2752
2753         if (xmpp_client_send_raw_message(client, message) != IKS_OK) {
2754                 ast_log(LOG_ERROR, "Unable to send handshake for component '%s'\n", client->name);
2755                 return -1;
2756         }
2757
2758         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2759
2760         return 0;
2761 }
2762
2763 /*! \brief Hook function called when component receives a service discovery get message */
2764 static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
2765 {
2766         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2767         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2768         struct ast_xmpp_client *client = data;
2769         iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL;
2770         iks *version = NULL, *vcard = NULL, *search = NULL, *item = NULL;
2771         char *node;
2772
2773         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2774             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(identity = iks_new("identity")) || !(disco = iks_new("feature")) ||
2775             !(reg = iks_new("feature")) || !(commands = iks_new("feature")) || !(gateway = iks_new("feature")) || !(version = iks_new("feature")) ||
2776             !(vcard = iks_new("feature")) || !(search = iks_new("search")) || !(item = iks_new("item"))) {
2777                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
2778                         pak->from->partial, client->name);
2779                 goto done;
2780         }
2781
2782         iks_insert_attrib(iq, "from", clientcfg->user);
2783         iks_insert_attrib(iq, "to", pak->from->full);
2784         iks_insert_attrib(iq, "id", pak->id);
2785         iks_insert_attrib(iq, "type", "result");
2786
2787         if (!(node = iks_find_attrib(pak->query, "node"))) {
2788                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2789                 iks_insert_attrib(identity, "category", "gateway");
2790                 iks_insert_attrib(identity, "type", "pstn");
2791                 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2792                 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2793                 iks_insert_attrib(reg, "var", "jabber:iq:register");
2794                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2795                 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2796                 iks_insert_attrib(version, "var", "jabber:iq:version");
2797                 iks_insert_attrib(vcard, "var", "vcard-temp");
2798                 iks_insert_attrib(search, "var", "jabber:iq:search");
2799
2800                 iks_insert_node(iq, query);
2801                 iks_insert_node(query, identity);
2802                 iks_insert_node(query, disco);
2803                 iks_insert_node(query, reg);
2804                 iks_insert_node(query, commands);
2805                 iks_insert_node(query, gateway);
2806                 iks_insert_node(query, version);
2807                 iks_insert_node(query, vcard);
2808                 iks_insert_node(query, search);
2809         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2810                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2811                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2812                 iks_insert_attrib(item, "node", "confirmaccount");
2813                 iks_insert_attrib(item, "name", "Confirm account");
2814                 iks_insert_attrib(item, "jid", clientcfg->user);
2815
2816                 iks_insert_node(iq, query);
2817                 iks_insert_node(query, item);
2818         } else if (!strcasecmp(node, "confirmaccount")) {
2819                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2820                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2821
2822                 iks_insert_node(iq, query);
2823                 iks_insert_node(query, commands);
2824         } else {
2825                 ast_debug(3, "Unsupported service discovery info request received with node '%s' on component '%s'\n",
2826                           node, client->name);
2827                 goto done;
2828         }
2829
2830         if (ast_xmpp_client_send(client, iq)) {
2831                 ast_log(LOG_WARNING, "Could not send response to service discovery request on component '%s'\n",
2832                         client->name);
2833         }
2834
2835 done:
2836         iks_delete(search);
2837         iks_delete(vcard);
2838         iks_delete(version);
2839         iks_delete(gateway);
2840         iks_delete(commands);
2841         iks_delete(reg);
2842         iks_delete(disco);
2843         iks_delete(identity);
2844         iks_delete(query);
2845         iks_delete(iq);
2846
2847         return IKS_FILTER_EAT;
2848 }
2849
2850 /*! \brief Hook function called when the component is queried about registration */
2851 static int xmpp_component_register_get_hook(void *data, ikspak *pak)
2852 {
2853         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2854         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2855         struct ast_xmpp_client *client = data;
2856         iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL, *instructions = NULL;
2857         struct ast_xmpp_buddy *buddy;
2858         char *node;
2859
2860         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2861             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(error = iks_new("error")) || !(notacceptable = iks_new("not-acceptable")) ||
2862             !(instructions = iks_new("instructions"))) {
2863                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
2864                         pak->from->partial, client->name);
2865                 goto done;
2866         }
2867
2868         iks_insert_attrib(iq, "from", clientcfg->user);
2869         iks_insert_attrib(iq, "to", pak->from->full);
2870         iks_insert_attrib(iq, "id", pak->id);
2871         iks_insert_attrib(iq, "type", "result");
2872         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
2873         iks_insert_node(iq, query);
2874
2875         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2876                 iks_insert_attrib(error, "code", "406");
2877                 iks_insert_attrib(error, "type", "modify");
2878                 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2879
2880                 iks_insert_node(iq, error);
2881                 iks_insert_node(error, notacceptable);
2882
2883                 ast_log(LOG_ERROR, "Received register attempt from '%s' but buddy is not configured on component '%s'\n",
2884                         pak->from->partial, client->name);
2885         } else if (!(node = iks_find_attrib(pak->query, "node"))) {
2886                 iks_insert_cdata(instructions, "Welcome to Asterisk - the Open Source PBX.\n", 0);
2887                 iks_insert_node(query, instructions);
2888                 ao2_ref(buddy, -1);
2889         } else {
2890                 ast_log(LOG_WARNING, "Received register get to component '%s' using unsupported node '%s' from '%s'\n",
2891                         client->name, node, pak->from->partial);
2892                 ao2_ref(buddy, -1);
2893                 goto done;
2894         }
2895
2896         if (ast_xmpp_client_send(client, iq)) {
2897                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register get on component '%s'\n",
2898                         pak->from->partial, client->name);
2899         }
2900
2901 done:
2902         iks_delete(instructions);
2903         iks_delete(notacceptable);
2904         iks_delete(error);
2905         iks_delete(query);
2906         iks_delete(iq);
2907
2908         return IKS_FILTER_EAT;
2909 }
2910
2911 /*! \brief Hook function called when someone registers to the component */
2912 static int xmpp_component_register_set_hook(void *data, ikspak *pak)
2913 {
2914         struct ast_xmpp_client *client = data;
2915         iks *iq, *presence = NULL, *x = NULL;
2916
2917         if (!(iq = iks_new("iq")) || !(presence = iks_new("presence")) || !(x = iks_new("x"))) {
2918                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
2919                         pak->from->partial, client->name);
2920                 goto done;
2921         }
2922
2923         iks_insert_attrib(iq, "from", client->jid->full);
2924         iks_insert_attrib(iq, "to", pak->from->full);
2925         iks_insert_attrib(iq, "id", pak->id);
2926         iks_insert_attrib(iq, "type", "result");
2927
2928         if (ast_xmpp_client_send(client, iq)) {
2929                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register set on component '%s'\n",
2930                         pak->from->partial, client->name);
2931                 goto done;
2932         }
2933
2934         iks_insert_attrib(presence, "from", client->jid->full);
2935         iks_insert_attrib(presence, "to", pak->from->partial);
2936         ast_xmpp_client_lock(client);
2937         iks_insert_attrib(presence, "id", client->mid);
2938         ast_xmpp_increment_mid(client->mid);
2939         ast_xmpp_client_unlock(client);
2940         iks_insert_attrib(presence, "type", "subscribe");
2941         iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
2942
2943         iks_insert_node(presence, x);
2944
2945         if (ast_xmpp_client_send(client, presence)) {
2946                 ast_log(LOG_WARNING, "Could not send subscription to '%s' on component '%s'\n",
2947                         pak->from->partial, client->name);
2948         }
2949
2950 done:
2951         iks_delete(x);
2952         iks_delete(presence);
2953         iks_delete(iq);
2954
2955         return IKS_FILTER_EAT;
2956 }
2957
2958 /*! \brief Hook function called when we receive a service discovery items request */
2959 static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
2960 {
2961         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2962         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2963         struct ast_xmpp_client *client = data;
2964         iks *iq = NULL, *query = NULL, *item = NULL, *feature = NULL;
2965         char *node;
2966
2967         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2968             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item")) || !(feature = iks_new("feature"))) {
2969                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
2970                         pak->from->partial, client->name);
2971                 goto done;
2972         }
2973
2974         iks_insert_attrib(iq, "from", clientcfg->user);
2975         iks_insert_attrib(iq, "to", pak->from->full);
2976         iks_insert_attrib(iq, "id", pak->id);
2977         iks_insert_attrib(iq, "type", "result");
2978         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2979         iks_insert_node(iq, query);
2980
2981         if (!(node = iks_find_attrib(pak->query, "node"))) {
2982                 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
2983                 iks_insert_attrib(item, "name", "Asterisk Commands");
2984                 iks_insert_attrib(item, "jid", clientcfg->user);
2985
2986                 iks_insert_node(query, item);
2987         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2988                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2989         } else {
2990                 ast_log(LOG_WARNING, "Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
2991                         client->name, node, pak->from->partial);
2992                 goto done;
2993         }
2994
2995         if (ast_xmpp_client_send(client, iq)) {
2996                 ast_log(LOG_WARNING, "Could not send response to service discovery items request from '%s' on component '%s'\n",
2997                         pak->from->partial, client->name);
2998         }
2999
3000 done:
3001         iks_delete(feature);
3002         iks_delete(item);
3003         iks_delete(query);
3004         iks_delete(iq);
3005
3006         return IKS_FILTER_EAT;
3007 }
3008
3009 /*! \brief Internal function called when we authenticated as a component */
3010 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
3011 {
3012         if (strcmp(iks_name(node), "handshake")) {
3013                 ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
3014                 return -1;
3015         }
3016
3017         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);
3018
3019         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);
3020
3021         /* This uses the client service discovery result hook on purpose, as the code is common between both */
3022         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);
3023
3024         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);
3025         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);
3026
3027         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
3028
3029         return 0;
3030 }
3031
3032 /*! \brief Internal function called when a message is received */
3033 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3034 {
3035         struct ast_xmpp_message *message;
3036         char *body;
3037         int deleted = 0;
3038
3039         ast_debug(3, "XMPP client '%s' received a message\n", client->name);
3040
3041         if (!(body = iks_find_cdata(pak->x, "body"))) {
3042                 /* Message contains no body, ignore it. */
3043                 return 0;
3044         }
3045
3046         if (!(message = ast_calloc(1, sizeof(*message)))) {
3047                 return -1;
3048         }
3049
3050         message->arrived = ast_tvnow();
3051
3052         message->message = ast_strdup(body);
3053
3054         ast_copy_string(message->id, S_OR(pak->id, ""), sizeof(message->id));
3055         message->from = !ast_strlen_zero(pak->from->full) ? ast_strdup(pak->from->full) : NULL;
3056
3057         if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
3058                 struct ast_msg *msg;
3059
3060                 if ((msg = ast_msg_alloc())) {
3061                         int res;
3062
3063                         ast_xmpp_client_lock(client);
3064
3065                         res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
3066                         res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
3067                         res |= ast_msg_set_body(msg, "%s", message->message);
3068                         res |= ast_msg_set_context(msg, "%s", cfg->context);
3069
3070                         ast_xmpp_client_unlock(client);
3071
3072                         if (res) {
3073                                 ast_msg_destroy(msg);
3074                         } else {
3075                                 ast_msg_queue(msg);
3076                         }
3077                 }
3078         }
3079
3080         /* remove old messages received from this JID
3081          * and insert received message */
3082         deleted = delete_old_messages(client, pak->from->partial);
3083         ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
3084         AST_LIST_LOCK(&client->messages);
3085         AST_LIST_INSERT_HEAD(&client->messages, message, list);
3086         AST_LIST_UNLOCK(&client->messages);
3087
3088         /* wake up threads waiting for messages */
3089         ast_mutex_lock(&messagelock);
3090         ast_cond_broadcast(&message_received_condition);
3091         ast_mutex_unlock(&messagelock);
3092
3093         return 0;
3094 }
3095
3096 /*! \brief Helper function which sends a discovery information request to a user */
3097 static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
3098 {
3099         iks *iq, *query;
3100         int res;
3101
3102         if (!(iq = iks_new("iq")) || !(query = iks_new("query"))) {
3103                 iks_delete(iq);
3104                 return -1;
3105         }
3106
3107         iks_insert_attrib(iq, "type", "get");
3108         iks_insert_attrib(iq, "to", to);
3109         iks_insert_attrib(iq, "from", from);
3110         ast_xmpp_client_lock(client);
3111         iks_insert_attrib(iq, "id", client->mid);
3112         ast_xmpp_increment_mid(client->mid);
3113         ast_xmpp_client_unlock(client);
3114         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
3115         iks_insert_node(iq, query);
3116
3117         res = ast_xmpp_client_send(client, iq);
3118
3119         iks_delete(query);
3120         iks_delete(iq);
3121
3122         return res;
3123 }
3124
3125 /*! \brief Internal function called when a presence message is received */
3126 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3127 {
3128         struct ast_xmpp_buddy *buddy;
3129         struct ast_xmpp_resource *resource;
3130         char *type = iks_find_attrib(pak->x, "type");
3131         int status = pak->show ? pak->show : STATUS_DISAPPEAR;
3132
3133         /* If no resource is available this is a general buddy presence update, which we will ignore */
3134         if (!pak->from->resource) {
3135                 return 0;
3136         }
3137
3138         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
3139                 /* Only output the message if it is not about us */
3140                 if (strcmp(client->jid->partial, pak->from->partial)) {
3141                         ast_log(LOG_WARNING, "Received presence information about '%s' despite not having them in roster on client '%s'\n",
3142                                 pak->from->partial, client->name);
3143                 }
3144                 return 0;
3145         }
3146
3147         /* If this is a component presence probe request answer immediately with our presence status */
3148         if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
3149                 xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3150         }
3151
3152         ao2_lock(buddy->resources);
3153
3154         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY | OBJ_NOLOCK))) {
3155                 /* Only create the new resource if it is not going away - in reality this should not happen */
3156                 if (status != STATUS_DISAPPEAR) {
3157                         if (!(resource = ao2_alloc(sizeof(*resource), xmpp_resource_destructor))) {
3158                                 ast_log(LOG_ERROR, "Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
3159                                         pak->from->resource, buddy->id, client->name);
3160                                 ao2_unlock(buddy->resources);
3161                                 ao2_ref(buddy, -1);
3162                                 return 0;
3163                         }
3164
3165                         ast_copy_string(resource->resource, pak->from->resource, sizeof(resource->resource));
3166                 }
3167         } else {
3168                 /* We unlink the resource in case the priority changes or in case they are going away */
3169                 ao2_unlink_flags(buddy->resources, resource, OBJ_NOLOCK);
3170         }
3171
3172         /* Only update the resource and add it back in if it is not going away */
3173         if (resource && (status != STATUS_DISAPPEAR)) {
3174                 char *node, *ver;
3175
3176                 /* Try to get the XMPP spec node, and fall back to Google if not found */
3177                 if (!(node = iks_find_attrib(iks_find(pak->x, "c"), "node"))) {
3178                         node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
3179                 }
3180
3181                 if (!(ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"))) {
3182                         ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
3183                 }
3184
3185                 if (resource->description) {
3186                         ast_free(resource->description);
3187                 }
3188
3189                 if ((node && strcmp(resource->caps.node, node)) || (ver && strcmp(resource->caps.version, ver))) {
3190                         /* For interoperability reasons, proceed even if the resource fails to provide node or version */
3191                         if (node) {
3192                                 ast_copy_string(resource->caps.node, node, sizeof(resource->caps.node));
3193                         }
3194                         if (ver) {
3195                                 ast_copy_string(resource->caps.version, ver, sizeof(resource->caps.version));
3196                         }
3197
3198                         /* Google Talk places the capabilities information directly in presence, so see if it is there */
3199                         if (iks_find_with_attrib(pak->x, "c", "node", "http://www.google.com/xmpp/client/caps") ||
3200                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.google.com/xmpp/client/caps") ||
3201                             iks_find_with_attrib(pak->x, "c", "node", "http://www.android.com/gtalk/client/caps") ||
3202                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.android.com/gtalk/client/caps") ||
3203                             iks_find_with_attrib(pak->x, "c", "node", "http://mail.google.com/xmpp/client/caps") ||
3204                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://mail.google.com/xmpp/client/caps")) {
3205                                 resource->caps.google = 1;
3206                         }
3207
3208                         /* To discover if the buddy supports Jingle we need to query, so do so */
3209                         if (xmpp_client_send_disco_info_request(client, pak->from->full, client->jid->full)) {
3210                                 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);
3211                         }
3212                 }
3213
3214                 resource->status = status;
3215                 resource->description = ast_strdup(iks_find_cdata(pak->x, "status"));
3216                 resource->priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
3217
3218                 ao2_link_flags(buddy->resources, resource, OBJ_NOLOCK);
3219
3220                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3221                               "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
3222                               "\r\nDescription: %s\r\n",
3223                               client->name, pak->from->partial, resource->resource, resource->status,
3224                               resource->priority, S_OR(resource->description, ""));
3225
3226                 ao2_ref(resource, -1);
3227         } else {
3228                 /* This will get hit by presence coming in for an unknown resource, and also when a resource goes away */
3229                 if (resource) {
3230                         ao2_ref(resource, -1);
3231                 }
3232
3233                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3234                               "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
3235                               client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
3236         }
3237
3238         ao2_unlock(buddy->resources);
3239
3240         ao2_ref(buddy, -1);
3241
3242         return 0;
3243 }
3244
3245 /*! \brief Internal function called when a subscription message is received */
3246 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg,iks *node, ikspak *pak)
3247 {
3248         struct ast_xmpp_buddy *buddy;
3249
3250         switch (pak->subtype) {
3251         case IKS_TYPE_SUBSCRIBE:
3252                 if (ast_test_flag(