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