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