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