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