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