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