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