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