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