security_events: Fix error caused by DTD validation error
[asterisk/asterisk.git] / res / res_jabber.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Matt O'Gorman <mogorman@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  * \brief A resource for interfacing Asterisk directly as a client
21  * or a component to a XMPP/Jabber compliant server.
22  *
23  * References:
24  * - http://www.xmpp.org - The XMPP standards foundation
25  *
26  * Iksemel http://code.google.com/p/iksemel/
27  *
28  * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
29  * \todo Dialplan applications need RETURN variable, like JABBERSENDSTATUS
30  *
31  */
32
33 /*! \li \ref res_jabber.c uses the configuration file \ref jabber.conf
34  * \addtogroup configuration_file Configuration Files
35  */
36
37 /*! 
38  * \page jabber.conf jabber.conf
39  * \verbinclude jabber.conf.sample
40  */
41
42 /*** MODULEINFO
43         <defaultenabled>no</defaultenabled>
44         <depend>iksemel</depend>
45         <use type="external">openssl</use>
46         <support_level>deprecated</support_level>
47         <replacement>res_xmpp</replacement>
48  ***/
49
50 #include "asterisk.h"
51
52 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53
54 #include <ctype.h>
55 #include <iksemel.h>
56
57 #include "asterisk/channel.h"
58 #include "asterisk/jabber.h"
59 #include "asterisk/file.h"
60 #include "asterisk/config.h"
61 #include "asterisk/callerid.h"
62 #include "asterisk/lock.h"
63 #include "asterisk/cli.h"
64 #include "asterisk/app.h"
65 #include "asterisk/pbx.h"
66 #include "asterisk/md5.h"
67 #include "asterisk/acl.h"
68 #include "asterisk/utils.h"
69 #include "asterisk/module.h"
70 #include "asterisk/astobj.h"
71 #include "asterisk/astdb.h"
72 #include "asterisk/manager.h"
73 #include "asterisk/devicestate.h"
74 #include "asterisk/message.h"
75
76 /*** DOCUMENTATION
77         <application name="JabberSend" language="en_US" module="res_jabber">
78                 <synopsis>
79                         Sends an XMPP message to a buddy.
80                 </synopsis>
81                 <syntax>
82                         <parameter name="account" required="true">
83                                 <para>The local named account to listen on (specified in
84                                 jabber.conf)</para>
85                         </parameter>
86                         <parameter name="jid" required="true">
87                                 <para>Jabber ID of the buddy to send the message to. It can be a
88                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
89                         </parameter>
90                         <parameter name="message" required="true">
91                                 <para>The message to send.</para>
92                         </parameter>
93                 </syntax>
94                 <description>
95                         <para>Sends the content of <replaceable>message</replaceable> as text message
96                         from the given <replaceable>account</replaceable> to the buddy identified by
97                         <replaceable>jid</replaceable></para>
98                         <para>Example: JabberSend(asterisk,bob@domain.com,Hello world) sends "Hello world"
99                         to <replaceable>bob@domain.com</replaceable> as an XMPP message from the account
100                         <replaceable>asterisk</replaceable>, configured in jabber.conf.</para>
101                 </description>
102                 <see-also>
103                         <ref type="function" module="res_jabber">JABBER_STATUS</ref>
104                         <ref type="function" module="res_jabber">JABBER_RECEIVE</ref>
105                 </see-also>
106         </application>
107         <function name="JABBER_RECEIVE" language="en_US" module="res_jabber">
108                 <synopsis>
109                         Reads XMPP messages.
110                 </synopsis>
111                 <syntax>
112                         <parameter name="account" required="true">
113                                 <para>The local named account to listen on (specified in
114                                 jabber.conf)</para>
115                         </parameter>
116                         <parameter name="jid" required="true">
117                                 <para>Jabber ID of the buddy to receive message from. It can be a
118                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
119                         </parameter>
120                         <parameter name="timeout">
121                                 <para>In seconds, defaults to <literal>20</literal>.</para>
122                         </parameter>
123                 </syntax>
124                 <description>
125                         <para>Receives a text message on the given <replaceable>account</replaceable>
126                         from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
127                         <para>Example: ${JABBER_RECEIVE(asterisk,bob@domain.com)} returns an XMPP message
128                         sent from <replaceable>bob@domain.com</replaceable> (or nothing in case of a time out), to
129                         the <replaceable>asterisk</replaceable> XMPP account configured in jabber.conf.</para>
130                 </description>
131                 <see-also>
132                         <ref type="function" module="res_jabber">JABBER_STATUS</ref>
133                         <ref type="application" module="res_jabber">JabberSend</ref>
134                 </see-also>
135         </function>
136         <function name="JABBER_STATUS" language="en_US" module="res_jabber">
137                 <synopsis>
138                         Retrieves a buddy's status.
139                 </synopsis>
140                 <syntax>
141                         <parameter name="account" required="true">
142                                 <para>The local named account to listen on (specified in
143                                 jabber.conf)</para>
144                         </parameter>
145                         <parameter name="jid" required="true">
146                                 <para>Jabber ID of the buddy to receive message from. It can be a
147                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
148                         </parameter>
149                 </syntax>
150                 <description>
151                         <para>Retrieves the numeric status associated with the buddy identified
152                         by <replaceable>jid</replaceable>.
153                         If the buddy does not exist in the buddylist, returns 7.</para>
154                         <para>Status will be 1-7.</para>
155                         <para>1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline</para>
156                         <para>If not in roster variable will be set to 7.</para>
157                         <para>Example: ${JABBER_STATUS(asterisk,bob@domain.com)} returns 1 if
158                         <replaceable>bob@domain.com</replaceable> is online. <replaceable>asterisk</replaceable> is
159                         the associated XMPP account configured in jabber.conf.</para>
160                 </description>
161                 <see-also>
162                         <ref type="function" module="res_jabber">JABBER_RECEIVE</ref>
163                         <ref type="application" module="res_jabber">JabberSend</ref>
164                 </see-also>
165         </function>
166         <application name="JabberSendGroup" language="en_US" module="res_jabber">
167                 <synopsis>
168                         Send a Jabber Message to a specified chat room
169                 </synopsis>
170                 <syntax>
171                         <parameter name="Jabber" required="true">
172                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
173                         </parameter>
174                         <parameter name="RoomJID" required="true">
175                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
176                         </parameter>
177                         <parameter name="Message" required="true">
178                                 <para>Message to be sent to the chat room.</para>
179                         </parameter>
180                         <parameter name="Nickname" required="false">
181                                 <para>The nickname Asterisk uses in the chat room.</para>
182                         </parameter>
183                 </syntax>
184                 <description>
185                         <para>Allows user to send a message to a chat room via XMPP.</para>
186                         <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>
187                 </description>
188         </application>
189         <application name="JabberJoin" language="en_US" module="res_jabber">
190                 <synopsis>
191                         Join a chat room
192                 </synopsis>
193                 <syntax>
194                         <parameter name="Jabber" required="true">
195                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
196                         </parameter>
197                         <parameter name="RoomJID" required="true">
198                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
199                         </parameter>
200                         <parameter name="Nickname" required="false">
201                                 <para>The nickname Asterisk will use in the chat room.</para>
202                                 <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>
203                         </parameter>
204                 </syntax>
205                 <description>
206                         <para>Allows Asterisk to join a chat room.</para>
207                 </description>
208         </application>
209         <application name="JabberLeave" language="en_US" module="res_jabber">
210                 <synopsis>
211                         Leave a chat room
212                 </synopsis>
213                 <syntax>
214                         <parameter name="Jabber" required="true">
215                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
216                         </parameter>
217                         <parameter name="RoomJID" required="true">
218                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
219                         </parameter>
220                         <parameter name="Nickname" required="false">
221                                 <para>The nickname Asterisk uses in the chat room.</para>
222                         </parameter>
223                 </syntax>
224                 <description>
225                         <para>Allows Asterisk to leave a chat room.</para>
226                 </description>
227         </application>
228         <application name="JabberStatus" language="en_US" module="res_jabber">
229                 <synopsis>
230                         Retrieve the status of a jabber list member
231                 </synopsis>
232                 <syntax>
233                         <parameter name="Jabber" required="true">
234                                 <para>Client or transport Asterisk users to connect to Jabber.</para>
235                         </parameter>
236                         <parameter name="JID" required="true">
237                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
238                         </parameter>
239                         <parameter name="Variable" required="true">
240                                 <para>Variable to store the status of requested user.</para>
241                         </parameter>
242                 </syntax>
243                 <description>
244                         <para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
245                         <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
246                         The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
247                         <enumlist>
248                                 <enum name="1">
249                                         <para>Online.</para>
250                                 </enum>
251                                 <enum name="2">
252                                         <para>Chatty.</para>
253                                 </enum>
254                                 <enum name="3">
255                                         <para>Away.</para>
256                                 </enum>
257                                 <enum name="4">
258                                         <para>Extended Away.</para>
259                                 </enum>
260                                 <enum name="5">
261                                         <para>Do Not Disturb.</para>
262                                 </enum>
263                                 <enum name="6">
264                                         <para>Offline.</para>
265                                 </enum>
266                                 <enum name="7">
267                                         <para>Not In Roster.</para>
268                                 </enum>
269                         </enumlist>
270                 </description>
271         </application>
272         <manager name="JabberSend" language="en_US" module="res_jabber">
273                 <synopsis>
274                         Sends a message to a Jabber Client.
275                 </synopsis>
276                 <syntax>
277                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
278                         <parameter name="Jabber" required="true">
279                                 <para>Client or transport Asterisk uses to connect to JABBER.</para>
280                         </parameter>
281                         <parameter name="JID" required="true">
282                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
283                         </parameter>
284                         <parameter name="Message" required="true">
285                                 <para>Message to be sent to the buddy.</para>
286                         </parameter>
287                 </syntax>
288                 <description>
289                         <para>Sends a message to a Jabber Client.</para>
290                 </description>
291         </manager>
292  ***/
293
294 /*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we
295  * need to read both files */
296 #define JABBER_CONFIG "jabber.conf"
297
298 /*-- Forward declarations */
299 static void aji_message_destroy(struct aji_message *obj);
300 static int aji_is_secure(struct aji_client *client);
301 #ifdef HAVE_OPENSSL
302 static int aji_start_tls(struct aji_client *client);
303 static int aji_tls_handshake(struct aji_client *client);
304 #endif
305 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
306 static int aji_recv(struct aji_client *client, int timeout);
307 static int aji_send_header(struct aji_client *client, const char *to);
308 static int aji_send_raw(struct aji_client *client, const char *xmlstr);
309 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
310 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
311 static int aji_act_hook(void *data, int type, iks *node);
312 static void aji_handle_iq(struct aji_client *client, iks *node);
313 static void aji_handle_message(struct aji_client *client, ikspak *pak);
314 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
315 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
316 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message);
317 static void *aji_recv_loop(void *data);
318 static int aji_initialize(struct aji_client *client);
319 static int aji_client_connect(void *data, ikspak *pak);
320 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
321 static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc);
322 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
323 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
324 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
325 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
326 static int aji_create_client(char *label, struct ast_variable *var, int debug);
327 static int aji_create_buddy(char *label, struct aji_client *client);
328 static int aji_reload(int reload);
329 static int aji_load_config(int reload);
330 static void aji_pruneregister(struct aji_client *client);
331 static int aji_filter_roster(void *data, ikspak *pak);
332 static int aji_get_roster(struct aji_client *client);
333 static int aji_client_info_handler(void *data, ikspak *pak);
334 static int aji_dinfo_handler(void *data, ikspak *pak);
335 static int aji_ditems_handler(void *data, ikspak *pak);
336 static int aji_register_query_handler(void *data, ikspak *pak);
337 static int aji_register_approve_handler(void *data, ikspak *pak);
338 static int aji_reconnect(struct aji_client *client);
339 static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd,
340         struct ast_cli_args *a);
341 static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd,
342         struct ast_cli_args *a);
343 static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
344         ast_cli_args *a);
345 static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
346                 ast_cli_args *a);
347 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
348 static int aji_receive_node_list(void *data, ikspak* pak);
349 static void aji_init_event_distribution(struct aji_client *client);
350 static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type,
351         const char *name, const char *collection_name);
352 static iks* aji_build_node_config(iks *pubsub, const char *node_type,
353         const char *collection_name);
354 static void aji_create_pubsub_collection(struct aji_client *client,
355         const char *collection_name);
356 static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
357    const char *leaf_name);
358 static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
359         struct ast_cli_args *a);
360 static void aji_create_affiliations(struct aji_client *client, const char *node);
361 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
362 static void aji_publish_device_state(struct aji_client *client, const char * device,
363                                      const char *device_state, unsigned int cachable);
364 static int aji_handle_pubsub_error(void *data, ikspak *pak);
365 static int aji_handle_pubsub_event(void *data, ikspak *pak);
366 static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
367 static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name);
368 static iks* aji_build_node_request(struct aji_client *client, const char *collection);
369 static int aji_delete_node_list(void *data, ikspak* pak);
370 static void aji_pubsub_purge_nodes(struct aji_client *client,
371         const char* collection_name);
372 static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
373         const char *oldmsgs, const char *newmsgs);
374 static void aji_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg);
375 static void aji_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg);
376 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
377                                        const char *event_type, unsigned int cachable);
378 /* No transports in this version */
379 /*
380 static int aji_create_transport(char *label, struct aji_client *client);
381 static int aji_register_transport(void *data, ikspak *pak);
382 static int aji_register_transport2(void *data, ikspak *pak);
383 */
384
385 static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from);
386
387 static const struct ast_msg_tech msg_tech = {
388         .name = "xmpp",
389         .msg_send = msg_send_cb,
390 };
391
392 static struct ast_cli_entry aji_cli[] = {
393         AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
394         AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
395         AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
396         AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
397         AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."),
398         AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"),
399         AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"),
400         AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"),
401         AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
402 };
403
404 static char *app_ajisend = "JabberSend";
405 static char *app_ajisendgroup = "JabberSendGroup";
406 static char *app_ajistatus = "JabberStatus";
407 static char *app_ajijoin = "JabberJoin";
408 static char *app_ajileave = "JabberLeave";
409
410 static struct aji_client_container clients;
411 static struct aji_capabilities *capabilities = NULL;
412 static struct stasis_subscription *mwi_sub = NULL;
413 static struct stasis_subscription *device_state_sub = NULL;
414 static ast_cond_t message_received_condition;
415 static ast_mutex_t messagelock;
416
417 /*! \brief Global flags, initialized to default values */
418 static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT };
419
420 /*! \brief PubSub flags, initialized to default values */
421 static struct ast_flags pubsubflags = { 0 };
422 /*!
423  * \internal
424  * \brief Deletes the aji_client data structure.
425  * \param obj aji_client The structure we will delete.
426  * \return void.
427  */
428 void ast_aji_client_destroy(struct aji_client *obj)
429 {
430         struct aji_message *tmp;
431         ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
432         ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
433         iks_filter_delete(obj->f);
434         iks_parser_delete(obj->p);
435         iks_stack_delete(obj->stack);
436         AST_LIST_LOCK(&obj->messages);
437         while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
438                 aji_message_destroy(tmp);
439         }
440         AST_LIST_HEAD_DESTROY(&obj->messages);
441         ast_free(obj);
442 }
443
444 /*!
445  * \internal
446  * \brief Deletes the aji_buddy data structure.
447  * \param obj aji_buddy The structure we will delete.
448  * \return void.
449  */
450 void ast_aji_buddy_destroy(struct aji_buddy *obj)
451 {
452         struct aji_resource *tmp;
453
454         while ((tmp = obj->resources)) {
455                 obj->resources = obj->resources->next;
456                 ast_free(tmp->description);
457                 ast_free(tmp);
458         }
459
460         ast_free(obj);
461 }
462
463 /*!
464  * \internal
465  * \brief Deletes the aji_message data structure.
466  * \param obj aji_message The structure we will delete.
467  * \return void.
468  */
469 static void aji_message_destroy(struct aji_message *obj)
470 {
471         if (obj->from) {
472                 ast_free(obj->from);
473         }
474         if (obj->message) {
475                 ast_free(obj->message);
476         }
477         ast_free(obj);
478 }
479
480 /*!
481  * \internal
482  * \brief Find version in XML stream and populate our capabilities list
483  * \param node the node attribute in the caps element we'll look for or add to
484  * our list
485  * \param version the version attribute in the caps element we'll look for or
486  * add to our list
487  * \param pak struct The XML stanza we're processing
488  * \return a pointer to the added or found aji_version structure
489  */
490 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
491 {
492         struct aji_capabilities *list = NULL;
493         struct aji_version *res = NULL;
494
495         list = capabilities;
496
497         if (!node) {
498                 node = pak->from->full;
499         }
500         if (!version) {
501                 version = "none supplied.";
502         }
503         while (list) {
504                 if (!strcasecmp(list->node, node)) {
505                         res = list->versions;
506                         while(res) {
507                                 if (!strcasecmp(res->version, version)) {
508                                         return res;
509                                 }
510                                 res = res->next;
511                         }
512                         /* Specified version not found. Let's add it to
513                            this node in our capabilities list */
514                         if (!res) {
515                                 res = ast_malloc(sizeof(*res));
516                                 if (!res) {
517                                         ast_log(LOG_ERROR, "Out of memory!\n");
518                                         return NULL;
519                                 }
520                                 res->jingle = 0;
521                                 res->parent = list;
522                                 ast_copy_string(res->version, version, sizeof(res->version));
523                                 res->next = list->versions;
524                                 list->versions = res;
525                                 return res;
526                         }
527                 }
528                 list = list->next;
529         }
530         /* Specified node not found. Let's add it our capabilities list */
531         if (!list) {
532                 list = ast_malloc(sizeof(*list));
533                 if (!list) {
534                         ast_log(LOG_ERROR, "Out of memory!\n");
535                         return NULL;
536                 }
537                 res = ast_malloc(sizeof(*res));
538                 if (!res) {
539                         ast_log(LOG_ERROR, "Out of memory!\n");
540                         ast_free(list);
541                         return NULL;
542                 }
543                 ast_copy_string(list->node, node, sizeof(list->node));
544                 ast_copy_string(res->version, version, sizeof(res->version));
545                 res->jingle = 0;
546                 res->parent = list;
547                 res->next = NULL;
548                 list->versions = res;
549                 list->next = capabilities;
550                 capabilities = list;
551         }
552         return res;
553 }
554
555 /*!
556  * \internal
557  * \brief Find the aji_resource we want
558  * \param buddy aji_buddy A buddy
559  * \param name
560  * \return aji_resource object
561 */
562 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
563 {
564         struct aji_resource *res = NULL;
565         if (!buddy || !name) {
566                 return res;
567         }
568         res = buddy->resources;
569         while (res) {
570                 if (!strcasecmp(res->resource, name)) {
571                         break;
572                 }
573                 res = res->next;
574         }
575         return res;
576 }
577
578 /*!
579  * \internal
580  * \brief Jabber GTalk function
581  * \param node iks
582  * \return 1 on success, 0 on failure.
583 */
584 static int gtalk_yuck(iks *node)
585 {
586         if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
587                 ast_debug(1, "Found resource with Googletalk voice capabilities\n");
588                 return 1;
589         } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
590                 ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
591                 return 1;
592         } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
593                 ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
594                 return 1;
595         }
596
597         return 0;
598 }
599
600 /*!
601  * \internal
602  * \brief Setup the authentication struct
603  * \param id iksid 
604  * \param pass password
605  * \param sid
606  * \return x iks
607 */
608 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
609 {
610         iks *x, *y;
611         x = iks_new("iq");
612         iks_insert_attrib(x, "type", "set");
613         y = iks_insert(x, "query");
614         iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
615         iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
616         iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
617         if (sid) {
618                 char buf[41];
619                 char sidpass[100];
620                 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
621                 ast_sha1_hash(buf, sidpass);
622                 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
623         } else {
624                 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
625         }
626         return x;
627 }
628
629 /*!
630  * \internal
631  * \brief Dial plan function status(). puts the status of watched user 
632  * into a channel variable.
633  * \param chan ast_channel
634  * \param data
635  * \retval 0 success
636  * \retval -1 error
637  */
638 static int aji_status_exec(struct ast_channel *chan, const char *data)
639 {
640         struct aji_client *client = NULL;
641         struct aji_buddy *buddy = NULL;
642         struct aji_resource *r = NULL;
643         char *s = NULL;
644         int stat = 7;
645         char status[2];
646         static int deprecation_warning = 0;
647         AST_DECLARE_APP_ARGS(args,
648                 AST_APP_ARG(sender);
649                 AST_APP_ARG(jid);
650                 AST_APP_ARG(variable);
651         );
652         AST_DECLARE_APP_ARGS(jid,
653                 AST_APP_ARG(screenname);
654                 AST_APP_ARG(resource);
655         );
656
657         if (deprecation_warning++ % 10 == 0) {
658                 ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
659         }
660
661         if (!data) {
662                 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
663                 return 0;
664         }
665         s = ast_strdupa(data);
666         AST_STANDARD_APP_ARGS(args, s);
667
668         if (args.argc != 3) {
669                 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
670                 return -1;
671         }
672
673         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
674         if (jid.argc < 1 || jid.argc > 2) {
675                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
676                 return -1;
677         }
678
679         if (!(client = ast_aji_get_client(args.sender))) {
680                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
681                 return -1;
682         }
683         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
684         if (!buddy) {
685                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
686                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
687                 return -1;
688         }
689         r = aji_find_resource(buddy, jid.resource);
690         if (!r && buddy->resources) {
691                 r = buddy->resources;
692         }
693         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
694         ASTOBJ_UNREF(client, ast_aji_client_destroy);
695         if (!r) {
696                 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
697         } else {
698                 stat = r->status;
699         }
700         snprintf(status, sizeof(status), "%d", stat);
701         pbx_builtin_setvar_helper(chan, args.variable, status);
702         return 0;
703 }
704
705 /*!
706  * \internal
707  * \brief Dial plan funtcion to retrieve the status of a buddy.
708  * \param channel The associated ast_channel, if there is one
709  * \param data The account, buddy JID, and optional timeout
710  * timeout.
711  * \retval 0 success
712  * \retval -1 failure
713  */
714 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
715 {
716         struct aji_client *client = NULL;
717         struct aji_buddy *buddy = NULL;
718         struct aji_resource *r = NULL;
719         int stat = 7;
720         AST_DECLARE_APP_ARGS(args,
721                 AST_APP_ARG(sender);
722                 AST_APP_ARG(jid);
723         );
724         AST_DECLARE_APP_ARGS(jid,
725                 AST_APP_ARG(screenname);
726                 AST_APP_ARG(resource);
727         );
728
729         if (!data) {
730                 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
731                 return 0;
732         }
733         AST_STANDARD_APP_ARGS(args, data);
734
735         if (args.argc != 2) {
736                 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
737                 return -1;
738         }
739
740         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
741         if (jid.argc < 1 || jid.argc > 2) {
742                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
743                 return -1;
744         }
745
746         if (!(client = ast_aji_get_client(args.sender))) {
747                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
748                 return -1;
749         }
750         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
751         if (!buddy) {
752                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
753                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
754                 return -1;
755         }
756         r = aji_find_resource(buddy, jid.resource);
757         if (!r && buddy->resources) {
758                 r = buddy->resources;
759         }
760         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
761         ASTOBJ_UNREF(client, ast_aji_client_destroy);
762         if (!r) {
763                 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
764         } else {
765                 stat = r->status;
766         }
767         snprintf(buf, buflen, "%d", stat);
768         return 0;
769 }
770
771 static struct ast_custom_function jabberstatus_function = {
772         .name = "JABBER_STATUS",
773         .read = acf_jabberstatus_read,
774 };
775
776 /*!
777  * \internal
778  * \brief Dial plan function to receive a message.
779  * \param channel The associated ast_channel, if there is one
780  * \param data The account, JID, and optional timeout
781  * timeout.
782  * \retval 0 success
783  * \retval -1 failure
784  */
785 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
786 {
787         char *parse = NULL;
788         int timeout;
789         int jidlen, resourcelen;
790         struct timeval start;
791         long diff = 0;
792         struct aji_client *client = NULL;
793         int found = 0;
794         struct aji_message *tmp = NULL;
795         AST_DECLARE_APP_ARGS(args,
796                         AST_APP_ARG(account);
797                         AST_APP_ARG(jid);
798                         AST_APP_ARG(timeout);
799                         );
800         AST_DECLARE_APP_ARGS(jid,
801                         AST_APP_ARG(screenname);
802                         AST_APP_ARG(resource);
803         );
804
805         if (ast_strlen_zero(data)) {
806                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
807                 return -1;
808         }
809
810         parse = ast_strdupa(data);
811         AST_STANDARD_APP_ARGS(args, parse);
812
813         if (args.argc < 2 || args.argc > 3) {
814                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
815                 return -1;
816         }
817
818         parse = ast_strdupa(args.jid);
819         AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
820         if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
821                 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
822                 return -1;
823         }
824
825         if (ast_strlen_zero(args.timeout)) {
826                 timeout = 20;
827         } else {
828                 sscanf(args.timeout, "%d", &timeout);
829                 if (timeout <= 0) {
830                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
831                         return -1;
832                 }
833         }
834
835         jidlen = strlen(jid.screenname);
836         resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
837
838         client = ast_aji_get_client(args.account);
839         if (!client) {
840                 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
841                 return -1;
842         }
843
844         ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
845
846         start = ast_tvnow();
847
848         if (ast_autoservice_start(chan) < 0) {
849                 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
850                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
851                 return -1;
852         }
853
854         /* search the messages list, grab the first message that matches with
855          * the from JID we're expecting, and remove it from the messages list */
856         while (diff < timeout) {
857                 struct timespec ts = { 0, };
858                 struct timeval wait;
859                 int res;
860
861                 wait = ast_tvadd(start, ast_tv(timeout, 0));
862                 ts.tv_sec = wait.tv_sec;
863                 ts.tv_nsec = wait.tv_usec * 1000;
864
865                 /* wait up to timeout seconds for an incoming message */
866                 ast_mutex_lock(&messagelock);
867                 res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
868                 ast_mutex_unlock(&messagelock);
869                 if (res == ETIMEDOUT) {
870                         ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
871                         break;
872                 }
873
874                 AST_LIST_LOCK(&client->messages);
875                 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
876                         if (jid.argc == 1) {
877                                 /* no resource provided, compare bare JIDs */
878                                 if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
879                                         continue;
880                                 }
881                         } else {
882                                 /* resource appended, compare bare JIDs and resources */
883                                 char *resource = strchr(tmp->from, '/');
884                                 if (!resource || strlen(resource) == 0) {
885                                         ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
886                                         if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
887                                                 continue;
888                                         }
889                                 } else {
890                                         resource ++;
891                                         if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
892                                                 continue;
893                                         }
894                                 }
895                         }
896                         /* check if the message is not too old */
897                         if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
898                                 ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
899                                 AST_LIST_REMOVE_CURRENT(list);
900                                 aji_message_destroy(tmp);
901                                 continue;
902                         }
903                         found = 1;
904                         ast_copy_string(buf, tmp->message, buflen);
905                         AST_LIST_REMOVE_CURRENT(list);
906                         aji_message_destroy(tmp);
907                         break;
908                 }
909                 AST_LIST_TRAVERSE_SAFE_END;
910                 AST_LIST_UNLOCK(&client->messages);
911                 if (found) {
912                         break;
913                 }
914
915                 /* check timeout */
916                 diff = ast_tvdiff_ms(ast_tvnow(), start);
917         }
918
919         ASTOBJ_UNREF(client, ast_aji_client_destroy);
920         if (ast_autoservice_stop(chan) < 0) {
921                 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
922         }
923
924         /* return if we timed out */
925         if (!found) {
926                 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
927                 return -1;
928         }
929
930         return 0;
931 }
932
933 static struct ast_custom_function jabberreceive_function = {
934         .name = "JABBER_RECEIVE",
935         .read = acf_jabberreceive_read,
936 };
937
938 /*!
939  * \internal
940  * \brief Delete old messages from a given JID
941  * Messages stored during more than client->message_timeout are deleted
942  * \param client Asterisk's XMPP client
943  * \param from the JID we received messages from
944  * \retval the number of deleted messages
945  * \retval -1 failure
946  */
947 static int delete_old_messages(struct aji_client *client, char *from)
948 {
949         int deleted = 0;
950         int isold = 0;
951         struct aji_message *tmp = NULL;
952         if (!client) {
953                 ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
954                 return -1;
955         }
956
957         /* remove old messages */
958         AST_LIST_LOCK(&client->messages);
959         if (AST_LIST_EMPTY(&client->messages)) {
960                 AST_LIST_UNLOCK(&client->messages);
961                 return 0;
962         }
963
964         AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
965                 if (isold) {
966                         if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
967                                 AST_LIST_REMOVE_CURRENT(list);
968                                 aji_message_destroy(tmp);
969                                 deleted ++;
970                         }
971                 } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
972                         isold = 1;
973                         if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
974                                 AST_LIST_REMOVE_CURRENT(list);
975                                 aji_message_destroy(tmp);
976                                 deleted ++;
977                         }
978                 }
979         }
980         AST_LIST_TRAVERSE_SAFE_END;
981         AST_LIST_UNLOCK(&client->messages);
982
983         return deleted;
984 }
985
986 /*!
987  * \internal
988  * \brief Delete old messages
989  * Messages stored during more than client->message_timeout are deleted
990  * \param client Asterisk's XMPP client
991  * \retval the number of deleted messages
992  * \retval -1 failure
993  */
994 static int delete_old_messages_all(struct aji_client *client)
995 {
996         return delete_old_messages(client, NULL);
997 }
998
999 /*!
1000 * \brief Application to join a chat room
1001 * \param chan ast_channel
1002 * \param data  Data is sender|jid|nickname.
1003 * \retval 0 success
1004 * \retval -1 error
1005 */
1006 static int aji_join_exec(struct ast_channel *chan, const char *data)
1007 {
1008         struct aji_client *client = NULL;
1009         char *s;
1010         char nick[AJI_MAX_RESJIDLEN];
1011
1012         AST_DECLARE_APP_ARGS(args,
1013                 AST_APP_ARG(sender);
1014                 AST_APP_ARG(jid);
1015                 AST_APP_ARG(nick);
1016         );
1017
1018         if (!data) {
1019                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1020                 return -1;
1021         }
1022         s = ast_strdupa(data);
1023
1024         AST_STANDARD_APP_ARGS(args, s);
1025         if (args.argc < 2 || args.argc > 3) {
1026                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1027                 return -1;
1028         }
1029
1030         if (strchr(args.jid, '/')) {
1031                 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1032                 return -1;
1033         }
1034
1035         if (!(client = ast_aji_get_client(args.sender))) {
1036                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1037                 return -1;
1038         }
1039
1040         if (!ast_strlen_zero(args.nick)) {
1041                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1042         } else {
1043                 if (client->component) {
1044                         sprintf(nick, "asterisk");
1045                 } else {
1046                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1047                 }
1048         }
1049
1050         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1051                 ast_aji_join_chat(client, args.jid, nick);
1052         } else {
1053                 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1054         }
1055
1056         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1057         return 0;
1058 }
1059
1060 /*!
1061 * \brief Application to leave a chat room
1062 * \param chan ast_channel
1063 * \param data  Data is sender|jid|nickname.
1064 * \retval 0 success
1065 * \retval -1 error
1066 */
1067 static int aji_leave_exec(struct ast_channel *chan, const char *data)
1068 {
1069         struct aji_client *client = NULL;
1070         char *s;
1071         char nick[AJI_MAX_RESJIDLEN];
1072         AST_DECLARE_APP_ARGS(args,
1073                 AST_APP_ARG(sender);
1074                 AST_APP_ARG(jid);
1075                 AST_APP_ARG(nick);
1076         );
1077
1078         if (!data) {
1079                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1080                 return -1;
1081         }
1082         s = ast_strdupa(data);
1083
1084         AST_STANDARD_APP_ARGS(args, s);
1085         if (args.argc < 2 || args.argc > 3) {
1086                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1087                 return -1;
1088         }
1089
1090         if (strchr(args.jid, '/')) {
1091                 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1092                 return -1;
1093         }
1094
1095         if (!(client = ast_aji_get_client(args.sender))) {
1096                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1097                 return -1;
1098         }
1099
1100         if (!ast_strlen_zero(args.nick)) {
1101                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1102         } else {
1103                 if (client->component) {
1104                         sprintf(nick, "asterisk");
1105                 } else {
1106                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1107                 }
1108         }
1109
1110         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1111                 ast_aji_leave_chat(client, args.jid, nick);
1112         }
1113         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1114         return 0;
1115 }
1116
1117 /*!
1118  * \internal
1119  * \brief Dial plan function to send a message.
1120  * \param chan ast_channel
1121  * \param data  Data is account,jid,message.
1122  * \retval 0 success
1123  * \retval -1 failure
1124  */
1125 static int aji_send_exec(struct ast_channel *chan, const char *data)
1126 {
1127         struct aji_client *client = NULL;
1128         char *s;
1129         AST_DECLARE_APP_ARGS(args,
1130                 AST_APP_ARG(sender);
1131                 AST_APP_ARG(recipient);
1132                 AST_APP_ARG(message);
1133         );
1134
1135         if (!data) {
1136                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1137                 return -1;
1138         }
1139         s = ast_strdupa(data);
1140
1141         AST_STANDARD_APP_ARGS(args, s);
1142         if (args.argc < 3) {
1143                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1144                 return -1;
1145         }
1146
1147         if (!(client = ast_aji_get_client(args.sender))) {
1148                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1149                 return -1;
1150         }
1151         if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
1152                 ast_aji_send_chat(client, args.recipient, args.message);
1153         }
1154         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1155         return 0;
1156 }
1157
1158 static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from)
1159 {
1160         struct aji_client *client;
1161         char *sender;
1162         char *dest;
1163         int res;
1164
1165         sender = ast_strdupa(from);
1166         strsep(&sender, ":");
1167         dest = ast_strdupa(to);
1168         strsep(&dest, ":");
1169
1170         if (ast_strlen_zero(sender)) {
1171                 ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for xmpp\n", from);
1172                 return -1;
1173         }
1174
1175         if (!(client = ast_aji_get_client(sender))) {
1176                 ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
1177                 return -1;
1178         }
1179
1180         ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name);
1181
1182         res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg));
1183         if (res != IKS_OK) {
1184                 ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res);
1185         }
1186
1187         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1188         return res == IKS_OK ? 0 : -1;
1189 }
1190
1191 /*!
1192 * \brief Application to send a message to a groupchat.
1193 * \param chan ast_channel
1194 * \param data  Data is sender|groupchat|message.
1195 * \retval 0 success
1196 * \retval -1 error
1197 */
1198 static int aji_sendgroup_exec(struct ast_channel *chan, const char *data)
1199 {
1200         struct aji_client *client = NULL;
1201         char *s;
1202         char nick[AJI_MAX_RESJIDLEN];
1203         int res = 0;
1204         AST_DECLARE_APP_ARGS(args,
1205                 AST_APP_ARG(sender);
1206                 AST_APP_ARG(groupchat);
1207                 AST_APP_ARG(message);
1208                 AST_APP_ARG(nick);
1209         );
1210
1211         if (!data) {
1212                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1213                 return -1;
1214         }
1215         s = ast_strdupa(data);
1216
1217         AST_STANDARD_APP_ARGS(args, s);
1218         if (args.argc < 3 || args.argc > 4) {
1219                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1220                 return -1;
1221         }
1222
1223         if (!(client = ast_aji_get_client(args.sender))) {
1224                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1225                 return -1;
1226         }
1227
1228         if (ast_strlen_zero(args.nick) || args.argc == 3) {
1229                 if (client->component) {
1230                         sprintf(nick, "asterisk");
1231                 } else {
1232                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1233                 }
1234         } else {
1235                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1236         }
1237
1238         if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
1239                 res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
1240         }
1241
1242         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1243         if (res != IKS_OK) {
1244                 return -1;
1245         }
1246         return 0;
1247 }
1248
1249 /*!
1250  * \internal
1251  * \brief Tests whether the connection is secured or not
1252  * \return 0 if the connection is not secured
1253  */
1254 static int aji_is_secure(struct aji_client *client)
1255 {
1256 #ifdef HAVE_OPENSSL
1257         return client->stream_flags & SECURE;
1258 #else
1259         return 0;
1260 #endif
1261 }
1262
1263 #ifdef HAVE_OPENSSL
1264 /*!
1265  * \internal
1266  * \brief Starts the TLS procedure
1267  * \param client the configured XMPP client we use to connect to a XMPP server
1268  * \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL
1269  * if OpenSSL is not installed
1270  */
1271 static int aji_start_tls(struct aji_client *client)
1272 {
1273         int ret;
1274
1275         /* This is sent not encrypted */
1276         if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
1277                 return ret;
1278         }
1279
1280         client->stream_flags |= TRY_SECURE;
1281         return IKS_OK;
1282 }
1283
1284 /*!
1285  * \internal
1286  * \brief TLS handshake, OpenSSL initialization
1287  * \param client the configured XMPP client we use to connect to a XMPP server
1288  * \return IKS_OK on success, IKS_NET_TLSFAIL on failure
1289  */
1290 static int aji_tls_handshake(struct aji_client *client)
1291 {
1292         int sock;
1293
1294         ast_debug(1, "Starting TLS handshake\n");
1295
1296         /* Choose an SSL/TLS protocol version, create SSL_CTX */
1297         client->ssl_method = SSLv3_method();
1298         if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
1299                 return IKS_NET_TLSFAIL;
1300         }
1301
1302         /* Create new SSL session */
1303         if (!(client->ssl_session = SSL_new(client->ssl_context))) {
1304                 return IKS_NET_TLSFAIL;
1305         }
1306
1307         /* Enforce TLS on our XMPP connection */
1308         sock = iks_fd(client->p);
1309         if (!SSL_set_fd(client->ssl_session, sock)) {
1310                 return IKS_NET_TLSFAIL;
1311         }
1312
1313         /* Perform SSL handshake */
1314         if (!SSL_connect(client->ssl_session)) {
1315                 return IKS_NET_TLSFAIL;
1316         }
1317
1318         client->stream_flags &= (~TRY_SECURE);
1319         client->stream_flags |= SECURE;
1320
1321         /* Sent over the established TLS connection */
1322         if (aji_send_header(client, client->jid->server) != IKS_OK) {
1323                 return IKS_NET_TLSFAIL;
1324         }
1325
1326         ast_debug(1, "TLS started with server\n");
1327
1328         return IKS_OK;
1329 }
1330 #endif /* HAVE_OPENSSL */
1331
1332 /*!
1333  * \internal
1334  * \brief Secured or unsecured IO socket receiving function
1335  * \param client the configured XMPP client we use to connect to a XMPP server
1336  * \param buffer the reception buffer
1337  * \param buf_len the size of the buffer
1338  * \param timeout the select timer
1339  * \retval the number of read bytes
1340  * \retval 0 timeout expiration
1341  * \retval -1 error
1342  */
1343 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
1344 {
1345         struct pollfd pfd = { .events = POLLIN };
1346         int len, res;
1347
1348 #ifdef HAVE_OPENSSL
1349         if (aji_is_secure(client)) {
1350                 pfd.fd = SSL_get_fd(client->ssl_session);
1351                 if (pfd.fd < 0) {
1352                         return -1;
1353                 }
1354         } else
1355 #endif /* HAVE_OPENSSL */
1356                 pfd.fd = iks_fd(client->p);
1357
1358         res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
1359         if (res > 0) {
1360 #ifdef HAVE_OPENSSL
1361                 if (aji_is_secure(client)) {
1362                         len = SSL_read(client->ssl_session, buffer, buf_len);
1363                 } else
1364 #endif /* HAVE_OPENSSL */
1365                         len = recv(pfd.fd, buffer, buf_len, 0);
1366
1367                 if (len > 0) {
1368                         return len;
1369                 } else if (len <= 0) {
1370                         return -1;
1371                 }
1372         }
1373         return res;
1374 }
1375
1376 /*!
1377  * \internal
1378  * \brief Tries to receive data from the Jabber server
1379  * \param client the configured XMPP client we use to connect to a XMPP server
1380  * \param timeout the timeout value
1381  * This function receives (encrypted or unencrypted) data from the XMPP server,
1382  * and passes it to the parser.
1383  * \retval IKS_OK success
1384  * \retval IKS_NET_RWERR IO error
1385  * \retval IKS_NET_NOCONN no connection available
1386  * \retval IKS_NET_EXPIRED timeout expiration
1387  */
1388 static int aji_recv (struct aji_client *client, int timeout)
1389 {
1390         int len, ret;
1391         char buf[NET_IO_BUF_SIZE - 1];
1392         char newbuf[NET_IO_BUF_SIZE - 1];
1393         int pos = 0;
1394         int newbufpos = 0;
1395         unsigned char c;
1396
1397         memset(buf, 0, sizeof(buf));
1398         memset(newbuf, 0, sizeof(newbuf));
1399
1400         while (1) {
1401                 len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
1402                 if (len < 0) return IKS_NET_RWERR;
1403                 if (len == 0) return IKS_NET_EXPIRED;
1404                 buf[len] = '\0';
1405
1406                 /* our iksemel parser won't work as expected if we feed
1407                    it with XML packets that contain multiple whitespace
1408                    characters between tags */
1409                 while (pos < len) {
1410                         c = buf[pos];
1411                         /* if we stumble on the ending tag character,
1412                            we skip any whitespace that follows it*/
1413                         if (c == '>') {
1414                                 while (isspace(buf[pos+1])) {
1415                                         pos++;
1416                                 }
1417                         }
1418                         newbuf[newbufpos] = c;
1419                         newbufpos ++;
1420                         pos++;
1421                 }
1422                 pos = 0;
1423                 newbufpos = 0;
1424
1425                 /* Log the message here, because iksemel's logHook is
1426                    unaccessible */
1427                 aji_log_hook(client, buf, len, 1);
1428
1429                 /* let iksemel deal with the string length,
1430                    and reset our buffer */
1431                 ret = iks_parse(client->p, newbuf, 0, 0);
1432                 memset(newbuf, 0, sizeof(newbuf));
1433
1434                 switch (ret) {
1435                 case IKS_NOMEM:
1436                         ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
1437                         break;
1438                 case IKS_BADXML:
1439                         ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
1440                         break;
1441                 case IKS_HOOK:
1442                         ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
1443                         break;
1444                 }
1445                 if (ret != IKS_OK) {
1446                         return ret;
1447                 }
1448                 ast_debug(3, "XML parsing successful\n");
1449         }
1450         return IKS_OK;
1451 }
1452
1453 /*!
1454  * \internal
1455  * \brief Sends XMPP header to the server
1456  * \param client the configured XMPP client we use to connect to a XMPP server
1457  * \param to the target XMPP server
1458  * \return IKS_OK on success, any other value on failure
1459  */
1460 static int aji_send_header(struct aji_client *client, const char *to)
1461 {
1462         char *msg;
1463         int len, err;
1464
1465         len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
1466         msg = iks_malloc(len);
1467         if (!msg)
1468                 return IKS_NOMEM;
1469         sprintf(msg, "<?xml version='1.0'?>"
1470                 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
1471                 "%s' to='%s' version='1.0'>", client->name_space, to);
1472         err = aji_send_raw(client, msg);
1473         iks_free(msg);
1474         if (err != IKS_OK)
1475                 return err;
1476
1477         return IKS_OK;
1478 }
1479
1480 /*!
1481  * \brief Wraps raw sending
1482  * \param client the configured XMPP client we use to connect to a XMPP server
1483  * \param x the XMPP packet to send
1484  * \return IKS_OK on success, any other value on failure
1485  */
1486 int ast_aji_send(struct aji_client *client, iks *x)
1487 {
1488         return aji_send_raw(client, iks_string(iks_stack(x), x));
1489 }
1490
1491 /*!
1492  * \internal
1493  * \brief Sends an XML string over an XMPP connection
1494  * \param client the configured XMPP client we use to connect to a XMPP server
1495  * \param xmlstr the XML string to send
1496  * The XML data is sent whether the connection is secured or not. In the
1497  * latter case, we just call iks_send_raw().
1498  * \return IKS_OK on success, any other value on failure
1499  */
1500 static int aji_send_raw(struct aji_client *client, const char *xmlstr)
1501 {
1502         int ret;
1503 #ifdef HAVE_OPENSSL
1504         int len = strlen(xmlstr);
1505
1506         if (aji_is_secure(client)) {
1507                 ret = SSL_write(client->ssl_session, xmlstr, len);
1508                 if (ret) {
1509                         /* Log the message here, because iksemel's logHook is
1510                            unaccessible */
1511                         aji_log_hook(client, xmlstr, len, 0);
1512                         return IKS_OK;
1513                 }
1514         }
1515 #endif
1516         /* If needed, data will be sent unencrypted, and logHook will
1517            be called inside iks_send_raw */
1518         ret = iks_send_raw(client->p, xmlstr);
1519         if (ret != IKS_OK) {
1520                 return ret;
1521         }
1522
1523         return IKS_OK;
1524 }
1525
1526 /*!
1527  * \internal
1528  * \brief the debug loop.
1529  * \param data void
1530  * \param xmpp xml data as string
1531  * \param size size of string
1532  * \param is_incoming direction of packet 1 for inbound 0 for outbound.
1533  */
1534 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
1535 {
1536         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1537
1538         if (client->debug) {
1539                 if (is_incoming) {
1540                         ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
1541                 } else {
1542                         if (strlen(xmpp) == 1) {
1543                                 if (option_debug > 2  && xmpp[0] == ' ') {
1544                                         ast_verbose("\nJABBER: Keep alive packet\n");
1545                                 }
1546                         } else {
1547                                 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
1548                         }
1549                 }
1550
1551         }
1552         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1553 }
1554
1555 /*!
1556  * \internal
1557  * \brief A wrapper function for iks_start_sasl
1558  * \param client the configured XMPP client we use to connect to a XMPP server
1559  * \param type the SASL authentication type. Supported types are PLAIN and MD5
1560  * \param username
1561  * \param pass password.
1562  *
1563  * \return IKS_OK on success, IKSNET_NOTSUPP on failure.
1564  */
1565 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
1566 {
1567         iks *x = NULL;
1568         int len;
1569         char *s;
1570         char *base64;
1571
1572         /* trigger SASL DIGEST-MD5 only over an unsecured connection.
1573            iks_start_sasl is an iksemel API function and relies on GnuTLS,
1574            whereas we use OpenSSL */
1575         if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
1576                 return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
1577         if (!(type & IKS_STREAM_SASL_PLAIN)) {
1578                 ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
1579                 return IKS_NET_NOTSUPP;
1580         }
1581
1582         x = iks_new("auth"); 
1583         if (!x) {
1584                 ast_log(LOG_ERROR, "Out of memory.\n");
1585                 return IKS_NET_NOTSUPP;
1586         }
1587
1588         iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
1589         len = strlen(username) + strlen(pass) + 3;
1590         s = ast_alloca(len);
1591         base64 = ast_alloca((len + 2) * 4 / 3);
1592         iks_insert_attrib(x, "mechanism", "PLAIN");
1593         snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
1594
1595         /* exclude the NULL training byte from the base64 encoding operation
1596            as some XMPP servers will refuse it.
1597            The format for authentication is [authzid]\0authcid\0password
1598            not [authzid]\0authcid\0password\0 */
1599         ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
1600         iks_insert_cdata(x, base64, 0);
1601         ast_aji_send(client, x);
1602         iks_delete(x);
1603
1604         return IKS_OK;
1605 }
1606
1607 /*!
1608  * \internal
1609  * \brief The action hook parses the inbound packets, constantly running.
1610  * \param data aji client structure 
1611  * \param type type of packet 
1612  * \param node the actual packet.
1613  * \return IKS_OK or IKS_HOOK .
1614  */
1615 static int aji_act_hook(void *data, int type, iks *node)
1616 {
1617         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1618         ikspak *pak = NULL;
1619         iks *auth = NULL;
1620         int features = 0;
1621
1622         if (!node) {
1623                 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
1624                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
1625                 return IKS_HOOK;
1626         }
1627
1628         if (client->state == AJI_DISCONNECTING) {
1629                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
1630                 return IKS_HOOK;
1631         }
1632
1633         pak = iks_packet(node);
1634
1635         /* work around iksemel's impossibility to recognize node names
1636          * containing a semicolon. Set the namespace of the corresponding
1637          * node accordingly. */
1638         if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
1639                 char *node_ns = NULL;
1640                 char attr[AJI_MAX_ATTRLEN];
1641                 char *node_name = iks_name(iks_child(node));
1642                 char *aux = strchr(node_name, ':') + 1;
1643                 snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
1644                 node_ns = iks_find_attrib(iks_child(node), attr);
1645                 if (node_ns) {
1646                         pak->ns = node_ns;
1647                         pak->query = iks_child(node);
1648                 }
1649         }
1650
1651
1652         if (!client->component) { /*client */
1653                 switch (type) {
1654                 case IKS_NODE_START:
1655                         if (client->usetls && !aji_is_secure(client)) {
1656 #ifndef HAVE_OPENSSL
1657                                 ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n");
1658                                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
1659                                 return IKS_HOOK;
1660 #else
1661                                 if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
1662                                         ast_log(LOG_ERROR, "Could not start TLS\n");
1663                                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1664                                         return IKS_HOOK;
1665                                 }
1666                                 break;
1667 #endif
1668                         }
1669                         if (!client->usesasl) {
1670                                 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
1671                                 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
1672                                 if (auth) {
1673                                         iks_insert_attrib(auth, "id", client->mid);
1674                                         iks_insert_attrib(auth, "to", client->jid->server);
1675                                         ast_aji_increment_mid(client->mid);
1676                                         ast_aji_send(client, auth);
1677                                         iks_delete(auth);
1678                                 } else {
1679                                         ast_log(LOG_ERROR, "Out of memory.\n");
1680                                 }
1681                         }
1682                         break;
1683
1684                 case IKS_NODE_NORMAL:
1685 #ifdef HAVE_OPENSSL
1686                         if (client->stream_flags & TRY_SECURE) {
1687                                 if (!strcmp("proceed", iks_name(node))) {
1688                                         return aji_tls_handshake(client);
1689                                 }
1690                         }
1691 #endif
1692                         if (!strcmp("stream:features", iks_name(node))) {
1693                                 features = iks_stream_features(node);
1694                                 if (client->usesasl) {
1695                                         if (client->usetls && !aji_is_secure(client)) {
1696                                                 break;
1697                                         }
1698                                         if (client->authorized) {
1699                                                 if (features & IKS_STREAM_BIND) {
1700                                                         iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
1701                                                         auth = iks_make_resource_bind(client->jid);
1702                                                         if (auth) {
1703                                                                 iks_insert_attrib(auth, "id", client->mid);
1704                                                                 ast_aji_increment_mid(client->mid);
1705                                                                 ast_aji_send(client, auth);
1706                                                                 iks_delete(auth);
1707                                                         } else {
1708                                                                 ast_log(LOG_ERROR, "Out of memory.\n");
1709                                                                 break;
1710                                                         }
1711                                                 }
1712                                                 if (features & IKS_STREAM_SESSION) {
1713                                                         iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1714                                                         auth = iks_make_session();
1715                                                         if (auth) {
1716                                                                 iks_insert_attrib(auth, "id", "auth");
1717                                                                 ast_aji_increment_mid(client->mid);
1718                                                                 ast_aji_send(client, auth);
1719                                                                 iks_delete(auth);
1720                                                         } else {
1721                                                                 ast_log(LOG_ERROR, "Out of memory.\n");
1722                                                         }
1723                                                 }
1724                                         } else {
1725                                                 int ret;
1726                                                 if (!client->jid->user) {
1727                                                         ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
1728                                                         break;
1729                                                 }
1730
1731                                                 ret = aji_start_sasl(client, features, client->jid->user, client->password);
1732                                                 if (ret != IKS_OK) {
1733                                                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1734                                                         return IKS_HOOK;
1735                                                 }
1736                                                 break;
1737                                         }
1738                                 }
1739                         } else if (!strcmp("failure", iks_name(node))) {
1740                                 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
1741                         } else if (!strcmp("success", iks_name(node))) {
1742                                 client->authorized = 1;
1743                                 aji_send_header(client, client->jid->server);
1744                         }
1745                         break;
1746                 case IKS_NODE_ERROR:
1747                         ast_log(LOG_ERROR, "JABBER: Node Error\n");
1748                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1749                         return IKS_HOOK;
1750                         break;
1751                 case IKS_NODE_STOP:
1752                         ast_log(LOG_WARNING, "JABBER: Disconnected\n");
1753                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1754                         return IKS_HOOK;
1755                         break;
1756                 }
1757         } else if (client->state != AJI_CONNECTED && client->component) {
1758                 switch (type) {
1759                 case IKS_NODE_START:
1760                         if (client->state == AJI_DISCONNECTED) {
1761                                 char secret[160], shasum[320], *handshake;
1762
1763                                 sprintf(secret, "%s%s", pak->id, client->password);
1764                                 ast_sha1_hash(shasum, secret);
1765                                 if (ast_asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
1766                                         aji_send_raw(client, handshake);
1767                                         ast_free(handshake);
1768                                 }
1769                                 client->state = AJI_CONNECTING;
1770                                 if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
1771                                         client->state = AJI_CONNECTED;
1772                                 else
1773                                         ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
1774                                 break;
1775                         }
1776                         break;
1777
1778                 case IKS_NODE_NORMAL:
1779                         break;
1780
1781                 case IKS_NODE_ERROR:
1782                         ast_log(LOG_ERROR, "JABBER: Node Error\n");
1783                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1784                         return IKS_HOOK;
1785
1786                 case IKS_NODE_STOP:
1787                         ast_log(LOG_WARNING, "JABBER: Disconnected\n");
1788                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1789                         return IKS_HOOK;
1790                 }
1791         }
1792
1793         switch (pak->type) {
1794         case IKS_PAK_NONE:
1795                 ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
1796                 break;
1797         case IKS_PAK_MESSAGE:
1798                 aji_handle_message(client, pak);
1799                 ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
1800                 break;
1801         case IKS_PAK_PRESENCE:
1802                 aji_handle_presence(client, pak);
1803                 ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
1804                 break;
1805         case IKS_PAK_S10N:
1806                 aji_handle_subscribe(client, pak);
1807                 ast_debug(1, "JABBER: Handling paktype S10N\n");
1808                 break;
1809         case IKS_PAK_IQ:
1810                 ast_debug(1, "JABBER: Handling paktype IQ\n");
1811                 aji_handle_iq(client, node);
1812                 break;
1813         default:
1814                 ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
1815                 break;
1816         }
1817
1818         iks_filter_packet(client->f, pak);
1819
1820         if (node)
1821                 iks_delete(node);
1822
1823         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1824         return IKS_OK;
1825 }
1826 /*!
1827  * \internal
1828  * \brief Unknown
1829  * \param data void
1830  * \param pak ikspak
1831  * \return IKS_FILTER_EAT.
1832 */
1833 static int aji_register_approve_handler(void *data, ikspak *pak)
1834 {
1835         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1836         iks *iq = NULL, *presence = NULL, *x = NULL;
1837
1838         iq = iks_new("iq");
1839         presence = iks_new("presence");
1840         x = iks_new("x");
1841         if (client && iq && presence && x) {
1842                 if (!iks_find(pak->query, "remove")) {
1843                         iks_insert_attrib(iq, "from", client->jid->full);
1844                         iks_insert_attrib(iq, "to", pak->from->full);
1845                         iks_insert_attrib(iq, "id", pak->id);
1846                         iks_insert_attrib(iq, "type", "result");
1847                         ast_aji_send(client, iq);
1848
1849                         iks_insert_attrib(presence, "from", client->jid->full);
1850                         iks_insert_attrib(presence, "to", pak->from->partial);
1851                         iks_insert_attrib(presence, "id", client->mid);
1852                         ast_aji_increment_mid(client->mid);
1853                         iks_insert_attrib(presence, "type", "subscribe");
1854                         iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
1855                         iks_insert_node(presence, x);
1856                         ast_aji_send(client, presence);
1857                 }
1858         } else {
1859                 ast_log(LOG_ERROR, "Out of memory.\n");
1860         }
1861
1862         iks_delete(iq);
1863         iks_delete(presence);
1864         iks_delete(x);
1865
1866         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1867         return IKS_FILTER_EAT;
1868 }
1869 /*!
1870  * \internal
1871  * \brief register handler for incoming querys (IQ's)
1872  * \param data incoming aji_client request
1873  * \param pak ikspak
1874  * \return IKS_FILTER_EAT.
1875 */
1876 static int aji_register_query_handler(void *data, ikspak *pak)
1877 {
1878         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1879         struct aji_buddy *buddy = NULL;
1880         iks *iq = NULL, *query = NULL;
1881
1882         client = (struct aji_client *) data;
1883
1884         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
1885         if (!buddy) {
1886                 iks  *error = NULL, *notacceptable = NULL;
1887
1888                 ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
1889                 iq = iks_new("iq");
1890                 query = iks_new("query");
1891                 error = iks_new("error");
1892                 notacceptable = iks_new("not-acceptable");
1893                 if (iq && query && error && notacceptable) {
1894                         iks_insert_attrib(iq, "type", "error");
1895                         iks_insert_attrib(iq, "from", client->user);
1896                         iks_insert_attrib(iq, "to", pak->from->full);
1897                         iks_insert_attrib(iq, "id", pak->id);
1898                         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
1899                         iks_insert_attrib(error, "code" , "406");
1900                         iks_insert_attrib(error, "type", "modify");
1901                         iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
1902                         iks_insert_node(iq, query);
1903                         iks_insert_node(iq, error);
1904                         iks_insert_node(error, notacceptable);
1905                         ast_aji_send(client, iq);
1906                 } else {
1907                         ast_log(LOG_ERROR, "Out of memory.\n");
1908                 }
1909
1910                 iks_delete(error);
1911                 iks_delete(notacceptable);
1912         } else if (!iks_find_attrib(pak->query, "node")) {
1913                 iks *instructions = NULL;
1914                 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
1915                 iq = iks_new("iq");
1916                 query = iks_new("query");
1917                 instructions = iks_new("instructions");
1918                 if (iq && query && instructions && client) {
1919                         iks_insert_attrib(iq, "from", client->user);
1920                         iks_insert_attrib(iq, "to", pak->from->full);
1921                         iks_insert_attrib(iq, "id", pak->id);
1922                         iks_insert_attrib(iq, "type", "result");
1923                         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
1924                         iks_insert_cdata(instructions, explain, 0);
1925                         iks_insert_node(iq, query);
1926                         iks_insert_node(query, instructions);
1927                         ast_aji_send(client, iq);
1928                 } else {
1929                         ast_log(LOG_ERROR, "Out of memory.\n");
1930                 }
1931
1932                 iks_delete(instructions);
1933         }
1934         iks_delete(iq);
1935         iks_delete(query);
1936         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
1937         ASTOBJ_UNREF(client, ast_aji_client_destroy);
1938         return IKS_FILTER_EAT;
1939 }
1940
1941 /*!
1942  * \internal
1943  * \brief Handles stuff
1944  * \param data void
1945  * \param pak ikspak
1946  * \return IKS_FILTER_EAT.
1947 */
1948 static int aji_ditems_handler(void *data, ikspak *pak)
1949 {
1950         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1951         char *node = NULL;
1952
1953         if (!(node = iks_find_attrib(pak->query, "node"))) {
1954                 iks *iq = NULL, *query = NULL, *item = NULL;
1955                 iq = iks_new("iq");
1956                 query = iks_new("query");
1957                 item = iks_new("item");
1958
1959                 if (iq && query && item) {
1960                         iks_insert_attrib(iq, "from", client->user);
1961                         iks_insert_attrib(iq, "to", pak->from->full);
1962                         iks_insert_attrib(iq, "id", pak->id);
1963                         iks_insert_attrib(iq, "type", "result");
1964                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
1965                         iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
1966                         iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
1967                         iks_insert_attrib(item, "jid", client->user);
1968
1969                         iks_insert_node(iq, query);
1970                         iks_insert_node(query, item);
1971                         ast_aji_send(client, iq);
1972                 } else {
1973                         ast_log(LOG_ERROR, "Out of memory.\n");
1974                 }
1975
1976                 iks_delete(iq);
1977                 iks_delete(query);
1978                 iks_delete(item);
1979
1980         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
1981                 iks *iq, *query, *confirm;
1982                 iq = iks_new("iq");
1983                 query = iks_new("query");
1984                 confirm = iks_new("item");
1985                 if (iq && query && confirm && client) {
1986                         iks_insert_attrib(iq, "from", client->user);
1987                         iks_insert_attrib(iq, "to", pak->from->full);
1988                         iks_insert_attrib(iq, "id", pak->id);
1989                         iks_insert_attrib(iq, "type", "result");
1990                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
1991                         iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
1992                         iks_insert_attrib(confirm, "node", "confirmaccount");
1993                         iks_insert_attrib(confirm, "name", "Confirm AIM account");
1994                         iks_insert_attrib(confirm, "jid", "blog.astjab.org");
1995
1996                         iks_insert_node(iq, query);
1997                         iks_insert_node(query, confirm);
1998                         ast_aji_send(client, iq);
1999                 } else {
2000                         ast_log(LOG_ERROR, "Out of memory.\n");
2001                 }
2002
2003                 iks_delete(iq);
2004                 iks_delete(query);
2005                 iks_delete(confirm);
2006
2007         } else if (!strcasecmp(node, "confirmaccount")) {
2008                 iks *iq = NULL, *query = NULL, *feature = NULL;
2009
2010                 iq = iks_new("iq");
2011                 query = iks_new("query");
2012                 feature = iks_new("feature");
2013
2014                 if (iq && query && feature && client) {
2015                         iks_insert_attrib(iq, "from", client->user);
2016                         iks_insert_attrib(iq, "to", pak->from->full);
2017                         iks_insert_attrib(iq, "id", pak->id);
2018                         iks_insert_attrib(iq, "type", "result");
2019                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2020                         iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
2021                         iks_insert_node(iq, query);
2022                         iks_insert_node(query, feature);
2023                         ast_aji_send(client, iq);
2024                 } else {
2025                         ast_log(LOG_ERROR, "Out of memory.\n");
2026                 }
2027
2028                 iks_delete(iq);
2029                 iks_delete(query);
2030                 iks_delete(feature);
2031         }
2032
2033         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2034         return IKS_FILTER_EAT;
2035
2036 }
2037
2038 /*!
2039  * \internal
2040  * \brief Handle add extra info
2041  * \param data void
2042  * \param pak ikspak
2043  * \return IKS_FILTER_EAT
2044 */
2045 static int aji_client_info_handler(void *data, ikspak *pak)
2046 {
2047         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2048         struct aji_resource *resource = NULL;
2049         struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2050
2051         if (!buddy) {
2052                 ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
2053                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
2054                 return IKS_FILTER_EAT;
2055         }
2056
2057         resource = aji_find_resource(buddy, pak->from->resource);
2058         if (pak->subtype == IKS_TYPE_RESULT) {
2059                 if (!resource) {
2060                         ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
2061                         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2062                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2063                         return IKS_FILTER_EAT;
2064                 }
2065                 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
2066                         resource->cap->jingle = 1;
2067                 } else {
2068                         resource->cap->jingle = 0;
2069                 }
2070         } else if (pak->subtype == IKS_TYPE_GET) {
2071                 iks *iq, *disco, *ident, *google, *query;
2072                 iq = iks_new("iq");
2073                 query = iks_new("query");
2074                 ident = iks_new("identity");
2075                 disco = iks_new("feature");
2076                 google = iks_new("feature");
2077                 if (iq && ident && disco && google) {
2078                         iks_insert_attrib(iq, "from", client->jid->full);
2079                         iks_insert_attrib(iq, "to", pak->from->full);
2080                         iks_insert_attrib(iq, "type", "result");
2081                         iks_insert_attrib(iq, "id", pak->id);
2082                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2083                         iks_insert_attrib(ident, "category", "client");
2084                         iks_insert_attrib(ident, "type", "pc");
2085                         iks_insert_attrib(ident, "name", "asterisk");
2086                         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2087                         iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2088                         iks_insert_node(iq, query);
2089                         iks_insert_node(query, ident);
2090                         iks_insert_node(query, google);
2091                         iks_insert_node(query, disco);
2092                         ast_aji_send(client, iq);
2093                 } else {
2094                         ast_log(LOG_ERROR, "Out of Memory.\n");
2095                 }
2096
2097                 iks_delete(iq);
2098                 iks_delete(query);
2099                 iks_delete(ident);
2100                 iks_delete(google);
2101                 iks_delete(disco);
2102         } else if (pak->subtype == IKS_TYPE_ERROR) {
2103                 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
2104         }
2105         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2106         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2107         return IKS_FILTER_EAT;
2108 }
2109
2110 /*!
2111  * \internal
2112  * \brief Handler of the return info packet
2113  * \param data aji_client
2114  * \param pak ikspak
2115  * \return IKS_FILTER_EAT
2116 */
2117 static int aji_dinfo_handler(void *data, ikspak *pak)
2118 {
2119         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2120         char *node = NULL;
2121         struct aji_resource *resource = NULL;
2122         struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2123
2124         if (!buddy) {
2125                 ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
2126                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
2127                 return IKS_FILTER_EAT;
2128         }
2129
2130         if (pak->subtype == IKS_TYPE_ERROR) {
2131                 ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
2132                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
2133                 return IKS_FILTER_EAT;
2134         }
2135         resource = aji_find_resource(buddy, pak->from->resource);
2136         if (pak->subtype == IKS_TYPE_RESULT) {
2137                 if (!resource) {
2138                         ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
2139                         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2140                         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2141                         return IKS_FILTER_EAT;
2142                 }
2143                 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
2144                         resource->cap->jingle = 1;
2145                 } else {
2146                         resource->cap->jingle = 0;
2147                 }
2148         } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
2149                 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
2150
2151                 iq = iks_new("iq");
2152                 query = iks_new("query");
2153                 identity = iks_new("identity");
2154                 disco = iks_new("feature");
2155                 reg = iks_new("feature");
2156                 commands = iks_new("feature");
2157                 gateway = iks_new("feature");
2158                 version = iks_new("feature");
2159                 vcard = iks_new("feature");
2160                 search = iks_new("feature");
2161                 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
2162                         iks_insert_attrib(iq, "from", client->user);
2163                         iks_insert_attrib(iq, "to", pak->from->full);
2164                         iks_insert_attrib(iq, "id", pak->id);
2165                         iks_insert_attrib(iq, "type", "result");
2166                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2167                         iks_insert_attrib(identity, "category", "gateway");
2168                         iks_insert_attrib(identity, "type", "pstn");
2169                         iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2170                         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2171                         iks_insert_attrib(reg, "var", "jabber:iq:register");
2172                         iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2173                         iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2174                         iks_insert_attrib(version, "var", "jabber:iq:version");
2175                         iks_insert_attrib(vcard, "var", "vcard-temp");
2176                         iks_insert_attrib(search, "var", "jabber:iq:search");
2177
2178                         iks_insert_node(iq, query);
2179                         iks_insert_node(query, identity);
2180                         iks_insert_node(query, disco);
2181                         iks_insert_node(query, reg);
2182                         iks_insert_node(query, commands);
2183                         iks_insert_node(query, gateway);
2184                         iks_insert_node(query, version);
2185                         iks_insert_node(query, vcard);
2186                         iks_insert_node(query, search);
2187                         ast_aji_send(client, iq);
2188                 } else {
2189                         ast_log(LOG_ERROR, "Out of memory.\n");
2190                 }
2191
2192                 iks_delete(iq);
2193                 iks_delete(query);
2194                 iks_delete(identity);
2195                 iks_delete(disco);
2196                 iks_delete(reg);
2197                 iks_delete(commands);
2198                 iks_delete(gateway);
2199                 iks_delete(version);
2200                 iks_delete(vcard);
2201                 iks_delete(search);
2202         } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
2203                 iks *iq, *query, *confirm;
2204                 iq = iks_new("iq");
2205                 query = iks_new("query");
2206                 confirm = iks_new("item");
2207
2208                 if (iq && query && confirm && client) {
2209                         iks_insert_attrib(iq, "from", client->user);
2210                         iks_insert_attrib(iq, "to", pak->from->full);
2211                         iks_insert_attrib(iq, "id", pak->id);
2212                         iks_insert_attrib(iq, "type", "result");
2213                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2214                         iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2215                         iks_insert_attrib(confirm, "node", "confirmaccount");
2216                         iks_insert_attrib(confirm, "name", "Confirm AIM account");
2217                         iks_insert_attrib(confirm, "jid", client->user);
2218                         iks_insert_node(iq, query);
2219                         iks_insert_node(query, confirm);
2220                         ast_aji_send(client, iq);
2221                 } else {
2222                         ast_log(LOG_ERROR, "Out of memory.\n");
2223                 }
2224
2225                 iks_delete(iq);
2226                 iks_delete(query);
2227                 iks_delete(confirm);
2228
2229         } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
2230                 iks *iq, *query, *feature;
2231
2232                 iq = iks_new("iq");
2233                 query = iks_new("query");
2234                 feature = iks_new("feature");
2235
2236                 if (iq && query && feature && client) {
2237                         iks_insert_attrib(iq, "from", client->user);
2238                         iks_insert_attrib(iq, "to", pak->from->full);
2239                         iks_insert_attrib(iq, "id", pak->id);
2240                         iks_insert_attrib(iq, "type", "result");
2241                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2242                         iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
2243                         iks_insert_node(iq, query);
2244                         iks_insert_node(query, feature);
2245                         ast_aji_send(client, iq);
2246                 } else {
2247                         ast_log(LOG_ERROR, "Out of memory.\n");
2248                 }
2249
2250                 iks_delete(iq);
2251                 iks_delete(query);
2252                 iks_delete(feature);
2253         }
2254
2255         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2256         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2257         return IKS_FILTER_EAT;
2258 }
2259
2260 /*!
2261  * \internal
2262  * \brief Handles \verbatim <iq> \endverbatim stanzas.
2263  * \param client the configured XMPP client we use to connect to a XMPP server
2264  * \param node iks
2265  * \return void.
2266  */
2267 static void aji_handle_iq(struct aji_client *client, iks *node)
2268 {
2269         /*Nothing to see here */
2270 }
2271
2272 /*!
2273  * \internal
2274  * \brief Handles \verbatim <message>\endverbatim stanzas.
2275  * Adds the incoming message to the client's message list.
2276  * \param client the configured XMPP client we use to connect to a XMPP server
2277  * \param pak ikspak the node
2278  */
2279 static void aji_handle_message(struct aji_client *client, ikspak *pak)
2280 {
2281         struct aji_message *insert;
2282         int deleted = 0;
2283         struct ast_msg *msg;
2284
2285         ast_debug(3, "client %s received a message\n", client->name);
2286
2287         if (!(insert = ast_calloc(1, sizeof(*insert)))) {
2288                 return;
2289         }
2290
2291         insert->arrived = ast_tvnow();
2292
2293         /* wake up threads waiting for messages */
2294         ast_mutex_lock(&messagelock);
2295         ast_cond_broadcast(&message_received_condition);
2296         ast_mutex_unlock(&messagelock);
2297
2298         if (iks_find_cdata(pak->x, "body")) {
2299                 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
2300         }
2301         if (pak->id) {
2302                 ast_copy_string(insert->id, pak->id, sizeof(insert->id));
2303         }
2304         if (pak->from){
2305                 /* insert will furtherly be added to message list */
2306                 insert->from = ast_strdup(pak->from->full);
2307                 if (!insert->from) {
2308                         ast_free(insert);
2309                         ast_log(LOG_ERROR, "Memory allocation failure\n");
2310                         return;
2311                 }
2312                 ast_debug(3, "message comes from %s\n", insert->from);
2313         }
2314
2315         if (client->send_to_dialplan) {
2316                 if ((msg = ast_msg_alloc())) {
2317                         int res;
2318
2319                         res = ast_msg_set_to(msg, "xmpp:%s", client->user);
2320                         res |= ast_msg_set_from(msg, "xmpp:%s", insert->from);
2321                         res |= ast_msg_set_body(msg, "%s", insert->message);
2322                         res |= ast_msg_set_context(msg, "%s", client->context);
2323
2324                         if (res) {
2325                                 ast_msg_destroy(msg);
2326                         } else {
2327                                 ast_msg_queue(msg);
2328                         }
2329
2330                         msg = NULL;
2331                 }
2332         }
2333
2334         /* remove old messages received from this JID
2335          * and insert received message */
2336         deleted = delete_old_messages(client, pak->from->partial);
2337         ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
2338         AST_LIST_LOCK(&client->messages);
2339         AST_LIST_INSERT_HEAD(&client->messages, insert, list);
2340         AST_LIST_UNLOCK(&client->messages);
2341 }
2342
2343 /*!
2344  * \internal
2345  * \brief handles \verbatim <presence>\endverbatim stanzas.
2346  * \param client the configured XMPP client we use to connect to a XMPP server
2347  * \param pak ikspak
2348  */
2349 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
2350 {
2351         int status, priority;
2352         struct aji_buddy *buddy;
2353         struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
2354         char *ver, *node, *descrip, *type;
2355
2356         if (client->state != AJI_CONNECTED)
2357                 aji_create_buddy(pak->from->partial, client);
2358
2359         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2360         if (!buddy && pak->from->partial) {
2361                 /* allow our jid to be used to log in with another resource */
2362                 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
2363                         aji_create_buddy(pak->from->partial, client);
2364                 else
2365                         ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
2366                 return;
2367         }
2368         type = iks_find_attrib(pak->x, "type");
2369         if (client->component && type &&!strcasecmp("probe", type)) {
2370                 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
2371                 ast_verbose("what i was looking for \n");
2372         }
2373         ASTOBJ_WRLOCK(buddy);
2374         status = (pak->show) ? pak->show : 6;
2375         priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
2376         tmp = buddy->resources;
2377         descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
2378
2379         while (tmp && pak->from->resource) {
2380                 if (!strcasecmp(tmp->resource, pak->from->resource)) {
2381                         tmp->status = status;
2382                         if (tmp->description) {
2383                                 ast_free(tmp->description);
2384                         }
2385                         tmp->description = descrip;
2386                         found = tmp;
2387                         if (status == 6) {      /* Sign off Destroy resource */
2388                                 if (last && found->next) {
2389                                         last->next = found->next;
2390                                 } else if (!last) {
2391                                         if (found->next) {
2392                                                 buddy->resources = found->next;
2393                                         } else {
2394                                                 buddy->resources = NULL;
2395                                         }
2396                                 } else if (!found->next) {
2397                                         if (last) {
2398                                                 last->next = NULL;
2399                                         } else {
2400                                                 buddy->resources = NULL;
2401                                         }
2402                                 }
2403                                 ast_free(found);
2404                                 found = NULL;
2405                                 break;
2406                         }
2407                         /* resource list is sorted by descending priority */
2408                         if (tmp->priority != priority) {
2409                                 found->priority = priority;
2410                                 if (!last && !found->next) {
2411                                         /* resource was found to be unique,
2412                                            leave loop */
2413                                         break;
2414                                 }
2415                                 /* search for resource in our list
2416                                    and take it out for the moment */
2417                                 if (last) {
2418                                         last->next = found->next;
2419                                 } else {
2420                                         buddy->resources = found->next;
2421                                 }
2422
2423                                 last = NULL;
2424                                 tmp = buddy->resources;
2425                                 if (!buddy->resources) {
2426                                         buddy->resources = found;
2427                                 }
2428                                 /* priority processing */
2429                                 while (tmp) {
2430                                         /* insert resource back according to
2431                                            its priority value */
2432                                         if (found->priority > tmp->priority) {
2433                                                 if (last) {
2434                                                         /* insert within list */
2435                                                         last->next = found;
2436                                                 }
2437                                                 found->next = tmp;
2438                                                 if (!last) {
2439                                                         /* insert on top */
2440                                                         buddy->resources = found;
2441                                                 }
2442                                                 break;
2443                                         }
2444                                         if (!tmp->next) {
2445                                                 /* insert at the end of the list */
2446                                                 tmp->next = found;
2447                                                 found->next = NULL;
2448                                                 break;
2449                                         }
2450                                         last = tmp;
2451                                         tmp = tmp->next;
2452                                 }
2453                         }
2454                         break;
2455                 }
2456                 last = tmp;
2457                 tmp = tmp->next;
2458         }
2459
2460         /* resource not found in our list, create it */
2461         if (!found && status != 6 && pak->from->resource) {
2462                 found = ast_calloc(1, sizeof(*found));
2463
2464                 if (!found) {
2465                         ast_log(LOG_ERROR, "Out of memory!\n");
2466                         ASTOBJ_UNLOCK(buddy);
2467                         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2468                         return;
2469                 }
2470                 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
2471                 found->status = status;
2472                 found->description = descrip;
2473                 found->priority = priority;
2474                 found->next = NULL;
2475                 last = NULL;
2476                 tmp = buddy->resources;
2477                 while (tmp) {
2478                         if (found->priority > tmp->priority) {
2479                                 if (last) {
2480                                         last->next = found;
2481                                 }
2482                                 found->next = tmp;
2483                                 if (!last) {
2484                                         buddy->resources = found;
2485                                 }
2486                                 break;
2487                         }
2488                         if (!tmp->next) {
2489                                 tmp->next = found;
2490                                 break;
2491                         }
2492                         last = tmp;
2493                         tmp = tmp->next;
2494                 }
2495                 if (!tmp) {
2496                         buddy->resources = found;
2497                 }
2498         }
2499
2500         ASTOBJ_UNLOCK(buddy);
2501         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2502
2503         node = iks_find_attrib(iks_find(pak->x, "c"), "node");
2504         ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
2505
2506         /* handle gmail client's special caps:c tag */
2507         if (!node && !ver) {
2508                 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
2509                 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
2510         }
2511
2512         /* retrieve capabilites of the new resource */
2513         if (status != 6 && found && !found->cap) {
2514                 found->cap = aji_find_version(node, ver, pak);
2515                 if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
2516                         found->cap->jingle = 1;
2517                 }
2518                 if (found->cap->jingle) {
2519                         ast_debug(1, "Special case for google till they support discover.\n");
2520                 } else {
2521                         iks *iq, *query;
2522                         iq = iks_new("iq");
2523                         query = iks_new("query");
2524                         if (query && iq) {
2525                                 iks_insert_attrib(iq, "type", "get");
2526                                 iks_insert_attrib(iq, "to", pak->from->full);
2527                                 iks_insert_attrib(iq, "from", client->jid->full);
2528                                 iks_insert_attrib(iq, "id", client->mid);
2529                                 ast_aji_increment_mid(client->mid);
2530                                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2531                                 iks_insert_node(iq, query);
2532                                 ast_aji_send(client, iq);
2533                         } else {
2534                                 ast_log(LOG_ERROR, "Out of memory.\n");
2535                         }
2536                         iks_delete(query);
2537                         iks_delete(iq);
2538                 }
2539         }
2540         switch (pak->subtype) {
2541         case IKS_TYPE_AVAILABLE:
2542                 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
2543                 break;
2544         case IKS_TYPE_UNAVAILABLE:
2545                 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
2546                 break;
2547         default:
2548                 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
2549         }
2550         switch (pak->show) {
2551         case IKS_SHOW_UNAVAILABLE:
2552                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2553                 break;
2554         case IKS_SHOW_AVAILABLE:
2555                 ast_debug(3, "JABBER: type is available\n");
2556                 break;
2557         case IKS_SHOW_CHAT:
2558                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2559                 break;
2560         case IKS_SHOW_AWAY:
2561                 ast_debug(3, "JABBER: type is away\n");
2562                 break;
2563         case IKS_SHOW_XA:
2564                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2565                 break;
2566         case IKS_SHOW_DND:
2567                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2568                 break;
2569         default:
2570                 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
2571         }
2572
2573         if (found) {
2574                 manager_event(EVENT_FLAG_USER, "JabberStatus",
2575                         "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
2576                         "\r\nDescription: %s\r\n",
2577                         client->name, pak->from->partial, found->resource, found->status,
2578                         found->priority, S_OR(found->description, ""));
2579         } else {
2580                 manager_event(EVENT_FLAG_USER, "JabberStatus",
2581                         "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
2582                         client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
2583         }
2584 }
2585
2586 /*!
2587  * \internal
2588  * \brief handles subscription requests.
2589  * \param client the configured XMPP client we use to connect to a XMPP server
2590  * \param pak ikspak iksemel packet.
2591  * \return void.
2592  */
2593 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
2594 {
2595         iks *presence = NULL, *status = NULL;
2596         struct aji_buddy* buddy = NULL;
2597
2598         switch (pak->subtype) {
2599         case IKS_TYPE_SUBSCRIBE:
2600                 if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
2601                         presence = iks_new("presence");
2602                         status = iks_new("status");
2603                         if (presence && status) {
2604                                 iks_insert_attrib(presence, "type", "subscribed");
2605                                 iks_insert_attrib(presence, "to", pak->from->full);
2606                                 iks_insert_attrib(presence, "from", client->jid->full);
2607                                 if (pak->id)
2608                                         iks_insert_attrib(presence, "id", pak->id);
2609                                 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
2610                                 iks_insert_node(presence, status);
2611                                 ast_aji_send(client, presence);
2612                         } else {
2613                                 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
2614                         }
2615
2616                         iks_delete(presence);
2617                         iks_delete(status);
2618                 }
2619
2620                 if (client->component)
2621                         aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
2622         case IKS_TYPE_SUBSCRIBED:
2623                 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2624                 if (!buddy && pak->from->partial) {
2625                         aji_create_buddy(pak->from->partial, client);
2626                 } else if (buddy) {
2627                         ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
2628                 }
2629         default:
2630                 ast_verb(5, "JABBER: This is a subcription of type %i\n", pak->subtype);
2631         }
2632 }
2633
2634 /*!
2635  * \brief sends messages.
2636  * \param client the configured XMPP client we use to connect to a XMPP server
2637  * \param address
2638  * \param message
2639  * \retval IKS_OK success
2640  * \retval -1 failure
2641  */
2642 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
2643 {
2644         return aji_send_raw_chat(client, 0, NULL, address, message);
2645 }
2646
2647 /*!
2648 * \brief sends message to a groupchat
2649 * Prior to sending messages to a groupchat, one must be connected to it.
2650 * \param client the configured XMPP client we use to connect to a XMPP server
2651 * \param nick the nickname we use in the chatroom
2652 * \param address the user the messages must be sent to
2653 * \param message the message to send
2654 * \return IKS_OK on success, any other value on failure
2655 */
2656 int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) {
2657         return aji_send_raw_chat(client, 1, nick, address, message);
2658 }
2659
2660 /*!
2661 * \brief sends messages.
2662 * \param client the configured XMPP client we use to connect to a XMPP server
2663 * \param groupchat 
2664 * \param nick the nickname we use in chatrooms
2665 * \param address
2666 * \param message
2667 * \return IKS_OK on success, any other value on failure
2668 */
2669 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message)
2670 {
2671         int res = 0;
2672         iks *message_packet = NULL;
2673         char from[AJI_MAX_JIDLEN];
2674         /* the nickname is used only in component mode */
2675         if (nick && client->component) {
2676                 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
2677         } else {
2678                 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
2679         }
2680
2681         if (client->state != AJI_CONNECTED) {
2682                 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
2683                 return -1;
2684         }
2685
2686         message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
2687         if (!message_packet) {
2688                 ast_log(LOG_ERROR, "Out of memory.\n");
2689                 return -1;
2690         }
2691         iks_insert_attrib(message_packet, "from", from);
2692         res = ast_aji_send(client, message_packet);
2693         iks_delete(message_packet);
2694
2695         return res;
2696 }
2697
2698 /*!
2699  * \brief create a chatroom.
2700  * \param client the configured XMPP client we use to connect to a XMPP server
2701  * \param room name of room
2702  * \param server name of server
2703  * \param topic topic for the room.
2704  * \return 0.
2705  */
2706 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
2707 {
2708         int res = 0;
2709         iks *iq = NULL;
2710         iq = iks_new("iq");
2711
2712         if (iq && client) {
2713                 iks_insert_attrib(iq, "type", "get");
2714                 iks_insert_attrib(iq, "to", server);
2715                 iks_insert_attrib(iq, "id", client->mid);
2716                 ast_aji_increment_mid(client->mid);
2717                 ast_aji_send(client, iq);
2718         } else {
2719                 ast_log(LOG_ERROR, "Out of memory.\n");
2720         }
2721
2722         iks_delete(iq);
2723
2724         return res;
2725 }
2726
2727 /*!
2728  * \brief join a chatroom.
2729  * \param client the configured XMPP client we use to connect to a XMPP server
2730  * \param room room to join
2731  * \param nick the nickname to use in this room
2732  * \return IKS_OK on success, any other value on failure.
2733  */
2734 int ast_aji_join_chat(struct aji_client *client, char *room, char *nick)
2735 {
2736         return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
2737 }
2738
2739 /*!
2740  * \brief leave a chatroom.
2741  * \param client the configured XMPP client we use to connect to a XMPP server
2742  * \param room room to leave
2743  * \param nick the nickname used in this room
2744  * \return IKS_OK on success, any other value on failure.
2745  */
2746 int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick)
2747 {
2748         return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
2749 }
2750 /*!
2751  * \brief invite to a chatroom.
2752  * \param client the configured XMPP client we use to connect to a XMPP server
2753  * \param user
2754  * \param room
2755  * \param message
2756  * \return res.
2757  */
2758 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
2759 {
2760         int res = 0;
2761         iks *invite, *body, *namespace;
2762
2763         invite = iks_new("message");
2764         body = iks_new("body");
2765         namespace = iks_new("x");
2766         if (client && invite && body && namespace) {
2767                 iks_insert_attrib(invite, "to", user);
2768                 iks_insert_attrib(invite, "id", client->mid);
2769                 ast_aji_increment_mid(client->mid);
2770                 iks_insert_cdata(body, message, 0);
2771                 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
2772                 iks_insert_attrib(namespace, "jid", room);
2773                 iks_insert_node(invite, body);
2774                 iks_insert_node(invite, namespace);
2775                 res = ast_aji_send(client, invite);
2776         } else {
2777                 ast_log(LOG_ERROR, "Out of memory.\n");
2778         }
2779
2780         iks_delete(body);
2781         iks_delete(namespace);
2782         iks_delete(invite);
2783
2784         return res;
2785 }
2786
2787 /*!
2788  * \internal
2789  * \brief receive message loop.
2790  * \param data void
2791  * \return void.
2792  */
2793 static void *aji_recv_loop(void *data)
2794 {
2795         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2796         int res = IKS_HOOK;
2797
2798         while (res != IKS_OK) {
2799                 ast_debug(3, "JABBER: Connecting.\n");
2800                 res = aji_reconnect(client);
2801                 sleep(4);
2802         }
2803
2804         do {
2805                 if (res == IKS_NET_RWERR || client->timeout == 0) {
2806                         while (res != IKS_OK) {
2807                                 ast_debug(3, "JABBER: reconnecting.\n");
2808                                 res = aji_reconnect(client);
2809                                 sleep(4);
2810                         }
2811                 }
2812
2813                 res = aji_recv(client, 1);
2814
2815                 if (client->state == AJI_DISCONNECTING) {
2816                         ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
2817                         pthread_exit(NULL);
2818                 }
2819
2820                 /* Decrease timeout if no data received, and delete
2821                  * old messages globally */
2822                 if (res == IKS_NET_EXPIRED) {
2823                         client->timeout--;
2824                         delete_old_messages_all(client);
2825                 }
2826                 if (res == IKS_HOOK) {
2827                         ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
2828                 } else if (res == IKS_NET_TLSFAIL) {
2829                         ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
2830                 } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
2831                         res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
2832                         if (res == IKS_OK) {
2833                                 client->timeout = 50;
2834                         } else {
2835                                 ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
2836                         }
2837                 } else if (res == IKS_NET_RWERR) {
2838                         ast_log(LOG_WARNING, "JABBER: socket read error\n");
2839                 }
2840         } while (client);
2841         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2842         return 0;
2843 }
2844
2845 /*!
2846  * \brief increments the mid field for messages and other events.
2847  * \param mid char.
2848  * \return void.
2849  */
2850 void ast_aji_increment_mid(char *mid)
2851 {
2852         int i = 0;
2853
2854         for (i = strlen(mid) - 1; i >= 0; i--) {
2855                 if (mid[i] != 'z') {
2856                         mid[i] = mid[i] + 1;
2857                         i = 0;
2858                 } else
2859                         mid[i] = 'a';
2860         }
2861 }
2862
2863 #if 0
2864 /*!
2865  * \brief attempts to register to a transport.
2866  * \param aji_client struct, and xml packet.
2867  * \return IKS_FILTER_EAT.
2868  */
2869 /*allows for registering to transport , was too sketch and is out for now. */
2870 static int aji_register_transport(void *data, ikspak *pak)
2871 {
2872         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2873         int res = 0;
2874         struct aji_buddy *buddy = NULL;
2875         iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
2876
2877         if (client && send) {
2878                 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2879                         ASTOBJ_RDLOCK(iterator); 
2880                         if (iterator->btype == AJI_TRANS) {
2881                                   buddy = iterator;
2882                         }
2883                         ASTOBJ_UNLOCK(iterator);
2884                 });
2885                 iks_filter_remove_hook(client->f, aji_register_transport);
2886                 iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE);
2887                 iks_insert_attrib(send, "to", buddy->host);
2888                 iks_insert_attrib(send, "id", client->mid);
2889                 ast_aji_increment_mid(client->mid);
2890                 iks_insert_attrib(send, "from", client->user);
2891                 res = ast_aji_send(client, send);
2892         } else 
2893                 ast_log(LOG_ERROR, "Out of memory.\n");
2894
2895         if (send)
2896                 iks_delete(send);
2897         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2898         return IKS_FILTER_EAT;
2899
2900 }
2901 /*!
2902  * \brief attempts to register to a transport step 2.
2903  * \param aji_client struct, and xml packet.
2904  * \return IKS_FILTER_EAT.
2905  */
2906 /* more of the same blob of code, too wonky for now*/
2907 static int aji_register_transport2(void *data, ikspak *pak)
2908 {
2909         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2910         int res = 0;
2911         struct aji_buddy *buddy = NULL;
2912
2913         iks *regiq = iks_new("iq");
2914         iks *regquery = iks_new("query");
2915         iks *reguser = iks_new("username");
2916         iks *regpass = iks_new("password");
2917
2918         if (client && regquery && reguser && regpass && regiq) {
2919                 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2920                         ASTOBJ_RDLOCK(iterator);
2921                         if (iterator->btype == AJI_TRANS)
2922                                 buddy = iterator; ASTOBJ_UNLOCK(iterator);
2923                 });
2924                 iks_filter_remove_hook(client->f, aji_register_transport2);
2925                 iks_insert_attrib(regiq, "to", buddy->host);
2926                 iks_insert_attrib(regiq, "type", "set");
2927                 iks_insert_attrib(regiq, "id", client->mid);
2928                 ast_aji_increment_mid(client->mid);
2929                 iks_insert_attrib(regiq, "from", client->user);
2930                 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
2931                 iks_insert_cdata(reguser, buddy->user, 0);
2932                 iks_insert_cdata(regpass, buddy->pass, 0);
2933                 iks_insert_node(regiq, regquery);
2934                 iks_insert_node(regquery, reguser);
2935                 iks_insert_node(regquery, regpass);
2936                 res = ast_aji_send(client, regiq);
2937         } else
2938                 ast_log(LOG_ERROR, "Out of memory.\n");
2939         if (regiq)
2940                 iks_delete(regiq);
2941         if (regquery)
2942                 iks_delete(regquery);
2943         if (reguser)
2944                 iks_delete(reguser);
2945         if (regpass)
2946                 iks_delete(regpass);
2947         ASTOBJ_UNREF(client, ast_aji_client_destroy);
2948         return IKS_FILTER_EAT;
2949 }
2950 #endif
2951
2952 /*!
2953  * \internal
2954  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
2955  * \param client the configured XMPP client we use to connect to a XMPP server
2956  * \return void.
2957  * \note The messages here should be configurable.
2958  */
2959 static void aji_pruneregister(struct aji_client *client)
2960 {
2961         iks *removeiq = iks_new("iq");
2962         iks *removequery = iks_new("query");
2963         iks *removeitem = iks_new("item");
2964         iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
2965         if (!client || !removeiq || !removequery || !removeitem || !send) {
2966                 ast_log(LOG_ERROR, "Out of memory.\n");
2967                 goto safeout;
2968         }
2969
2970         iks_insert_node(removeiq, removequery);
2971         iks_insert_node(removequery, removeitem);
2972         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2973                 ASTOBJ_RDLOCK(iterator);
2974                 /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
2975                  * be called at the same time */
2976                 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
2977                         ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
2978                                                                  "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
2979                                                                  " so I am no longer subscribing to your presence.\n"));
2980                         ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
2981                                                                  "GoodBye.  You are no longer in the Asterisk config file so I am removing"
2982                                                                  " your access to my presence.\n"));
2983                         iks_insert_attrib(removeiq, "from", client->jid->full);
2984                         iks_insert_attrib(removeiq, "type", "set");
2985                         iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
2986                         iks_insert_attrib(removeitem, "jid", iterator->name);
2987                         iks_insert_attrib(removeitem, "subscription", "remove");
2988                         ast_aji_send(client, removeiq);
2989                 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
2990                         ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
2991                                                                  "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
2992                         ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
2993                 }
2994                 ASTOBJ_UNLOCK(iterator);
2995         });
2996
2997  safeout:
2998         iks_delete(removeiq);
2999         iks_delete(removequery);
3000         iks_delete(removeitem);
3001         iks_delete(send);
3002
3003         ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
3004 }
3005
3006 /*!
3007  * \internal
3008  * \brief filters the roster packet we get back from server.
3009  * \param data void
3010  * \param pak ikspak iksemel packet.
3011  * \return IKS_FILTER_EAT.
3012  */
3013 static int aji_filter_roster(void *data, ikspak *pak)
3014 {
3015         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
3016         int flag = 0;
3017         iks *x = NULL;
3018         struct aji_buddy *buddy;
3019
3020         client->state = AJI_CONNECTED;
3021         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
3022                 ASTOBJ_RDLOCK(iterator);
3023                 x = iks_child(pak->query);
3024                 flag = 0;
3025                 while (x) {
3026                         if (!iks_strcmp(iks_name(x), "item")) {
3027                                 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
3028                                         flag = 1;
3029                                         ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
3030                                 }
3031                         }
3032                         x = iks_next(x);
3033                 }
3034                 if (!flag) {
3035                         ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
3036                 }
3037                 iks_delete(x);
3038
3039                 ASTOBJ_UNLOCK(iterator);
3040         });
3041
3042         x = iks_child(pak->query);
3043         while (x) {
3044                 flag = 0;
3045                 if (iks_strcmp(iks_name(x), "item") == 0) {
3046                         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
3047                                 ASTOBJ_RDLOCK(iterator);
3048                                 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
3049                                         flag = 1;
3050                                 ASTOBJ_UNLOCK(iterator);
3051                         });
3052
3053                         if (flag) {
3054                                 /* found buddy, don't create a new one */
3055                                 x = iks_next(x);
3056                                 continue;
3057                         }
3058
3059                         buddy = ast_calloc(1, sizeof(*buddy));
3060                         if (!buddy) {
3061                                 ast_log(LOG_WARNING, "Out of memory\n");
3062                                 ASTOBJ_UNREF(client, ast_aji_client_destroy);
3063                                 return 0;
3064                         }
3065                         ASTOBJ_INIT(buddy);
3066                         ASTOBJ_WRLOCK(buddy);
3067                         ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
3068                         ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
3069                         if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
3070                                 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
3071                                 ASTOBJ_MARK(buddy);