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