00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 72554 $")
00037
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <iksemel.h>
00041
00042 #include "asterisk/channel.h"
00043 #include "asterisk/jabber.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/md5.h"
00054 #include "asterisk/acl.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/module.h"
00057 #include "asterisk/astobj.h"
00058 #include "asterisk/astdb.h"
00059 #include "asterisk/manager.h"
00060
00061 #define JABBER_CONFIG "jabber.conf"
00062
00063 #ifndef FALSE
00064 #define FALSE 0
00065 #endif
00066
00067 #ifndef TRUE
00068 #define TRUE 1
00069 #endif
00070
00071
00072 static int aji_highest_bit(int number);
00073 static void aji_buddy_destroy(struct aji_buddy *obj);
00074 static void aji_client_destroy(struct aji_client *obj);
00075 static int aji_send_exec(struct ast_channel *chan, void *data);
00076 static int aji_status_exec(struct ast_channel *chan, void *data);
00077 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00078 static int aji_act_hook(void *data, int type, iks *node);
00079 static void aji_handle_iq(struct aji_client *client, iks *node);
00080 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00081 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00082 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00083 static void *aji_recv_loop(void *data);
00084 static int aji_component_initialize(struct aji_client *client);
00085 static int aji_client_initialize(struct aji_client *client);
00086 static int aji_client_connect(void *data, ikspak *pak);
00087 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00088 static int aji_do_debug(int fd, int argc, char *argv[]);
00089 static int aji_do_reload(int fd, int argc, char *argv[]);
00090 static int aji_no_debug(int fd, int argc, char *argv[]);
00091 static int aji_test(int fd, int argc, char *argv[]);
00092 static int aji_show_clients(int fd, int argc, char *argv[]);
00093 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00094 static int aji_create_buddy(char *label, struct aji_client *client);
00095 static int aji_reload(void);
00096 static int aji_load_config(void);
00097 static void aji_pruneregister(struct aji_client *client);
00098 static int aji_filter_roster(void *data, ikspak *pak);
00099 static int aji_get_roster(struct aji_client *client);
00100 static int aji_client_info_handler(void *data, ikspak *pak);
00101 static int aji_dinfo_handler(void *data, ikspak *pak);
00102 static int aji_ditems_handler(void *data, ikspak *pak);
00103 static int aji_register_query_handler(void *data, ikspak *pak);
00104 static int aji_register_approve_handler(void *data, ikspak *pak);
00105 static int aji_reconnect(struct aji_client *client);
00106 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00107
00108
00109
00110
00111
00112
00113
00114 static char debug_usage[] =
00115 "Usage: jabber debug\n"
00116 " Enables dumping of Jabber packets for debugging purposes.\n";
00117
00118 static char no_debug_usage[] =
00119 "Usage: jabber debug off\n"
00120 " Disables dumping of Jabber packets for debugging purposes.\n";
00121
00122 static char reload_usage[] =
00123 "Usage: jabber reload\n"
00124 " Enables reloading of Jabber module.\n";
00125
00126 static char test_usage[] =
00127 "Usage: jabber test [client]\n"
00128 " Sends test message for debugging purposes. A specific client\n"
00129 " as configured in jabber.conf can be optionally specified.\n";
00130
00131 static struct ast_cli_entry aji_cli[] = {
00132 { { "jabber", "debug", NULL},
00133 aji_do_debug, "Enable Jabber debugging",
00134 debug_usage },
00135
00136 { { "jabber", "reload", NULL},
00137 aji_do_reload, "Reload Jabber configuration",
00138 reload_usage },
00139
00140 { { "jabber", "show", "connected", NULL},
00141 aji_show_clients, "Show state of clients and components",
00142 debug_usage },
00143
00144 { { "jabber", "debug", "off", NULL},
00145 aji_no_debug, "Disable Jabber debug",
00146 no_debug_usage },
00147
00148 { { "jabber", "test", NULL},
00149 aji_test, "Shows roster, but is generally used for mog's debugging.",
00150 test_usage },
00151 };
00152
00153 static char *app_ajisend = "JabberSend";
00154
00155 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
00156
00157 static char *ajisend_descrip =
00158 "JabberSend(Jabber,ScreenName,Message)\n"
00159 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00160 " ScreenName - User Name to message.\n"
00161 " Message - Message to be sent to the buddy\n";
00162
00163 static char *app_ajistatus = "JabberStatus";
00164
00165 static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
00166
00167 static char *ajistatus_descrip =
00168 "JabberStatus(Jabber,ScreenName,Variable)\n"
00169 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00170 " ScreenName - User Name to retrieve status from.\n"
00171 " Variable - Variable to store presence in will be 1-6.\n"
00172 " In order, Online, Chatty, Away, XAway, DND, Offline\n"
00173 " If not in roster variable will = 7\n";
00174
00175 struct aji_client_container clients;
00176 struct aji_capabilities *capabilities = NULL;
00177
00178
00179 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
00180 static int tls_initialized = FALSE;
00181
00182
00183
00184
00185
00186
00187 static void aji_client_destroy(struct aji_client *obj)
00188 {
00189 struct aji_message *tmp;
00190 ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00191 ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00192 iks_filter_delete(obj->f);
00193 iks_parser_delete(obj->p);
00194 iks_stack_delete(obj->stack);
00195 AST_LIST_LOCK(&obj->messages);
00196 while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00197 if (tmp->from)
00198 free(tmp->from);
00199 if (tmp->message)
00200 free(tmp->message);
00201 }
00202 AST_LIST_HEAD_DESTROY(&obj->messages);
00203 free(obj);
00204 }
00205
00206
00207
00208
00209
00210
00211 static void aji_buddy_destroy(struct aji_buddy *obj)
00212 {
00213 struct aji_resource *tmp;
00214
00215 while ((tmp = obj->resources)) {
00216 obj->resources = obj->resources->next;
00217 free(tmp->description);
00218 free(tmp);
00219 }
00220
00221 free(obj);
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00234 {
00235 struct aji_capabilities *list = NULL;
00236 struct aji_version *res = NULL;
00237
00238 list = capabilities;
00239
00240 if(!node)
00241 node = pak->from->full;
00242 if(!version)
00243 version = "none supplied.";
00244 while(list) {
00245 if(!strcasecmp(list->node, node)) {
00246 res = list->versions;
00247 while(res) {
00248 if(!strcasecmp(res->version, version))
00249 return res;
00250 res = res->next;
00251 }
00252
00253
00254 if(!res) {
00255 res = (struct aji_version *)malloc(sizeof(struct aji_version));
00256 if(!res) {
00257 ast_log(LOG_ERROR, "Out of memory!\n");
00258 return NULL;
00259 }
00260 res->jingle = 0;
00261 res->parent = list;
00262 ast_copy_string(res->version, version, sizeof(res->version));
00263 res->next = list->versions;
00264 list->versions = res;
00265 return res;
00266 }
00267 }
00268 list = list->next;
00269 }
00270
00271 if(!list) {
00272 list = (struct aji_capabilities *)malloc(sizeof(struct aji_capabilities));
00273 if(!list) {
00274 ast_log(LOG_ERROR, "Out of memory!\n");
00275 return NULL;
00276 }
00277 res = (struct aji_version *)malloc(sizeof(struct aji_version));
00278 if(!res) {
00279 ast_log(LOG_ERROR, "Out of memory!\n");
00280 return NULL;
00281 }
00282 ast_copy_string(list->node, node, sizeof(list->node));
00283 ast_copy_string(res->version, version, sizeof(res->version));
00284 res->jingle = 0;
00285 res->parent = list;
00286 res->next = NULL;
00287 list->versions = res;
00288 list->next = capabilities;
00289 capabilities = list;
00290 }
00291 return res;
00292 }
00293
00294 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00295 {
00296 struct aji_resource *res = NULL;
00297 if (!buddy || !name)
00298 return res;
00299 res = buddy->resources;
00300 while (res) {
00301 if (!strcasecmp(res->resource, name)) {
00302 break;
00303 }
00304 res = res->next;
00305 }
00306 return res;
00307 }
00308
00309 static int gtalk_yuck(iks *node)
00310 {
00311 if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00312 return 1;
00313 return 0;
00314 }
00315
00316
00317
00318
00319
00320
00321 static int aji_highest_bit(int number)
00322 {
00323 int x = sizeof(number) * 8 - 1;
00324 if (!number)
00325 return 0;
00326 for (; x > 0; x--) {
00327 if (number & (1 << x))
00328 break;
00329 }
00330 return (1 << x);
00331 }
00332
00333 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00334 {
00335 iks *x, *y;
00336 x = iks_new("iq");
00337 iks_insert_attrib(x, "type", "set");
00338 y = iks_insert(x, "query");
00339 iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00340 iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00341 iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00342 if (sid) {
00343 char buf[41];
00344 char sidpass[100];
00345 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00346 ast_sha1_hash(buf, sidpass);
00347 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00348 } else {
00349 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00350 }
00351 return x;
00352 }
00353
00354
00355
00356
00357
00358
00359
00360 static int aji_status_exec(struct ast_channel *chan, void *data)
00361 {
00362 struct aji_client *client = NULL;
00363 struct aji_buddy *buddy = NULL;
00364 struct aji_resource *r = NULL;
00365 char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
00366 int stat = 7;
00367 char status[2];
00368
00369 if (!data) {
00370 ast_log(LOG_ERROR, "This application requires arguments.\n");
00371 return 0;
00372 }
00373 s = ast_strdupa(data);
00374 if (s) {
00375 sender = strsep(&s, "|");
00376 if (sender && (sender[0] != '\0')) {
00377 jid = strsep(&s, "|");
00378 if (jid && (jid[0] != '\0')) {
00379 variable = s;
00380 } else {
00381 ast_log(LOG_ERROR, "Bad arguments\n");
00382 return -1;
00383 }
00384 }
00385 }
00386
00387 if(!strchr(jid, '/')) {
00388 resource = NULL;
00389 } else {
00390 screenname = strsep(&jid, "/");
00391 resource = jid;
00392 }
00393 client = ast_aji_get_client(sender);
00394 if (!client) {
00395 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00396 return -1;
00397 }
00398 if(!&client->buddies) {
00399 ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
00400 return -1;
00401 }
00402 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
00403 if (!buddy) {
00404 ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
00405 return -1;
00406 }
00407 r = aji_find_resource(buddy, resource);
00408 if(!r && buddy->resources)
00409 r = buddy->resources;
00410 if(!r)
00411 ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
00412 else
00413 stat = r->status;
00414 sprintf(status, "%d", stat);
00415 pbx_builtin_setvar_helper(chan, variable, status);
00416 return 0;
00417 }
00418
00419
00420
00421
00422
00423
00424 static int aji_send_exec(struct ast_channel *chan, void *data)
00425 {
00426 struct aji_client *client = NULL;
00427
00428 char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
00429
00430 if (!data) {
00431 ast_log(LOG_ERROR, "This application requires arguments.\n");
00432 return 0;
00433 }
00434 s = ast_strdupa(data);
00435 if (s) {
00436 sender = strsep(&s, "|");
00437 if (sender && (sender[0] != '\0')) {
00438 recipient = strsep(&s, "|");
00439 if (recipient && (recipient[0] != '\0')) {
00440 message = s;
00441 } else {
00442 ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
00443 return -1;
00444 }
00445 }
00446 }
00447 if (!(client = ast_aji_get_client(sender))) {
00448 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00449 return -1;
00450 }
00451 if (strchr(recipient, '@') && message)
00452 ast_aji_send(client, recipient, message);
00453 return 0;
00454 }
00455
00456
00457
00458
00459
00460 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00461 {
00462 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00463 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00464
00465 if (client->debug) {
00466 if (is_incoming)
00467 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00468 else {
00469 if( strlen(xmpp) == 1) {
00470 if(option_debug > 2 && xmpp[0] == ' ')
00471 ast_verbose("\nJABBER: Keep alive packet\n");
00472 } else
00473 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00474 }
00475
00476 }
00477 ASTOBJ_UNREF(client, aji_client_destroy);
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487 static int aji_act_hook(void *data, int type, iks *node)
00488 {
00489 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00490 ikspak *pak = NULL;
00491 iks *auth = NULL;
00492
00493 if(!node) {
00494 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
00495 ASTOBJ_UNREF(client, aji_client_destroy);
00496 return IKS_HOOK;
00497 }
00498
00499 if (client->state == AJI_DISCONNECTING) {
00500 ASTOBJ_UNREF(client, aji_client_destroy);
00501 return IKS_HOOK;
00502 }
00503
00504 pak = iks_packet(node);
00505
00506 if (!client->component) {
00507 switch (type) {
00508 case IKS_NODE_START:
00509 if (client->usetls && !iks_is_secure(client->p)) {
00510 if (iks_has_tls()) {
00511 iks_start_tls(client->p);
00512 tls_initialized = TRUE;
00513 } else
00514 ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00515 break;
00516 }
00517 if (!client->usesasl) {
00518 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);
00519 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00520 if (auth) {
00521 iks_insert_attrib(auth, "id", client->mid);
00522 iks_insert_attrib(auth, "to", client->jid->server);
00523 ast_aji_increment_mid(client->mid);
00524 iks_send(client->p, auth);
00525 iks_delete(auth);
00526 } else
00527 ast_log(LOG_ERROR, "Out of memory.\n");
00528 }
00529 break;
00530
00531 case IKS_NODE_NORMAL:
00532 {
00533 int features = 0;
00534 if (!strcmp("stream:features", iks_name(node))) {
00535 features = iks_stream_features(node);
00536 if (client->usesasl) {
00537 if (client->usetls && !iks_is_secure(client->p))
00538 break;
00539 if (client->authorized) {
00540 if (features & IKS_STREAM_BIND) {
00541 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);
00542 auth = iks_make_resource_bind(client->jid);
00543 if (auth) {
00544 iks_insert_attrib(auth, "id", client->mid);
00545 ast_aji_increment_mid(client->mid);
00546 iks_send(client->p, auth);
00547 iks_delete(auth);
00548 } else {
00549 ast_log(LOG_ERROR, "Out of memory.\n");
00550 break;
00551 }
00552 }
00553 if (features & IKS_STREAM_SESSION) {
00554 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);
00555 auth = iks_make_session();
00556 if (auth) {
00557 iks_insert_attrib(auth, "id", "auth");
00558 ast_aji_increment_mid(client->mid);
00559 iks_send(client->p, auth);
00560 iks_delete(auth);
00561 } else {
00562 ast_log(LOG_ERROR, "Out of memory.\n");
00563 }
00564 }
00565 } else {
00566 if (!client->jid->user) {
00567 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00568 break;
00569 }
00570 features = aji_highest_bit(features);
00571 if (features == IKS_STREAM_SASL_MD5)
00572 iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00573 else {
00574 if (features == IKS_STREAM_SASL_PLAIN) {
00575 iks *x = NULL;
00576 x = iks_new("auth");
00577 if (x) {
00578 int len = strlen(client->jid->user) + strlen(client->password) + 3;
00579
00580 char *s = ast_malloc(80 + len);
00581 char *base64 = ast_malloc(80 + len * 2);
00582 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00583 iks_insert_attrib(x, "mechanism", "PLAIN");
00584 sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00585 ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
00586 iks_insert_cdata(x, base64, 0);
00587 iks_send(client->p, x);
00588 iks_delete(x);
00589 if (base64)
00590 free(base64);
00591 if (s)
00592 free(s);
00593 } else {
00594 ast_log(LOG_ERROR, "Out of memory.\n");
00595 }
00596 }
00597 }
00598 }
00599 }
00600 } else if (!strcmp("failure", iks_name(node))) {
00601 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00602 } else if (!strcmp("success", iks_name(node))) {
00603 client->authorized = 1;
00604 iks_send_header(client->p, client->jid->server);
00605 }
00606 break;
00607 }
00608 case IKS_NODE_ERROR:
00609 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00610 ASTOBJ_UNREF(client, aji_client_destroy);
00611 return IKS_HOOK;
00612 break;
00613 case IKS_NODE_STOP:
00614 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00615 ASTOBJ_UNREF(client, aji_client_destroy);
00616 return IKS_HOOK;
00617 break;
00618 }
00619 } else if (client->state != AJI_CONNECTED && client->component) {
00620 switch (type) {
00621 case IKS_NODE_START:
00622 if (client->state == AJI_DISCONNECTED) {
00623 char secret[160], shasum[320], *handshake;
00624
00625 sprintf(secret, "%s%s", pak->id, client->password);
00626 ast_sha1_hash(shasum, secret);
00627 handshake = NULL;
00628 asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00629 if (handshake) {
00630 iks_send_raw(client->p, handshake);
00631 free(handshake);
00632 handshake = NULL;
00633 }
00634 client->state = AJI_CONNECTING;
00635 if(iks_recv(client->p,1) == 2)
00636 client->state = AJI_CONNECTED;
00637 else
00638 ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00639 break;
00640 }
00641 break;
00642
00643 case IKS_NODE_NORMAL:
00644 break;
00645
00646 case IKS_NODE_ERROR:
00647 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00648 ASTOBJ_UNREF(client, aji_client_destroy);
00649 return IKS_HOOK;
00650
00651 case IKS_NODE_STOP:
00652 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00653 ASTOBJ_UNREF(client, aji_client_destroy);
00654 return IKS_HOOK;
00655 }
00656 }
00657
00658 switch (pak->type) {
00659 case IKS_PAK_NONE:
00660 if (option_debug)
00661 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00662 break;
00663 case IKS_PAK_MESSAGE:
00664 aji_handle_message(client, pak);
00665 if (option_debug)
00666 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00667 break;
00668 case IKS_PAK_PRESENCE:
00669 aji_handle_presence(client, pak);
00670 if (option_debug)
00671 ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00672 break;
00673 case IKS_PAK_S10N:
00674 aji_handle_subscribe(client, pak);
00675 if (option_debug)
00676 ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00677 break;
00678 case IKS_PAK_IQ:
00679 if (option_debug)
00680 ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00681 aji_handle_iq(client, node);
00682 break;
00683 default:
00684 if (option_debug)
00685 ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00686 break;
00687 }
00688
00689 iks_filter_packet(client->f, pak);
00690
00691 if (node)
00692 iks_delete(node);
00693
00694 ASTOBJ_UNREF(client, aji_client_destroy);
00695 return IKS_OK;
00696 }
00697
00698 static int aji_register_approve_handler(void *data, ikspak *pak)
00699 {
00700 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00701 iks *iq = NULL, *presence = NULL, *x = NULL;
00702
00703 iq = iks_new("iq");
00704 presence = iks_new("presence");
00705 x = iks_new("x");
00706 if (client && iq && presence && x) {
00707 if (!iks_find(pak->query, "remove")) {
00708 iks_insert_attrib(iq, "from", client->jid->full);
00709 iks_insert_attrib(iq, "to", pak->from->full);
00710 iks_insert_attrib(iq, "id", pak->id);
00711 iks_insert_attrib(iq, "type", "result");
00712 iks_send(client->p, iq);
00713
00714 iks_insert_attrib(presence, "from", client->jid->full);
00715 iks_insert_attrib(presence, "to", pak->from->partial);
00716 iks_insert_attrib(presence, "id", client->mid);
00717 ast_aji_increment_mid(client->mid);
00718 iks_insert_attrib(presence, "type", "subscribe");
00719 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00720 iks_insert_node(presence, x);
00721 iks_send(client->p, presence);
00722 }
00723 } else {
00724 ast_log(LOG_ERROR, "Out of memory.\n");
00725 }
00726
00727 if (iq)
00728 iks_delete(iq);
00729 if(presence)
00730 iks_delete(presence);
00731 if (x)
00732 iks_delete(x);
00733 ASTOBJ_UNREF(client, aji_client_destroy);
00734 return IKS_FILTER_EAT;
00735 }
00736
00737 static int aji_register_query_handler(void *data, ikspak *pak)
00738 {
00739 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00740 struct aji_buddy *buddy = NULL;
00741 char *node = NULL;
00742
00743 client = (struct aji_client *) data;
00744
00745 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00746 if (!buddy) {
00747 iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00748 ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00749 iq = iks_new("iq");
00750 query = iks_new("query");
00751 error = iks_new("error");
00752 notacceptable = iks_new("not-acceptable");
00753 if(iq && query && error && notacceptable) {
00754 iks_insert_attrib(iq, "type", "error");
00755 iks_insert_attrib(iq, "from", client->user);
00756 iks_insert_attrib(iq, "to", pak->from->full);
00757 iks_insert_attrib(iq, "id", pak->id);
00758 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00759 iks_insert_attrib(error, "code" , "406");
00760 iks_insert_attrib(error, "type", "modify");
00761 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00762 iks_insert_node(iq, query);
00763 iks_insert_node(iq, error);
00764 iks_insert_node(error, notacceptable);
00765 iks_send(client->p, iq);
00766 } else {
00767 ast_log(LOG_ERROR, "Out of memory.\n");
00768 }
00769 if (iq)
00770 iks_delete(iq);
00771 if (query)
00772 iks_delete(query);
00773 if (error)
00774 iks_delete(error);
00775 if (notacceptable)
00776 iks_delete(notacceptable);
00777 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
00778 iks *iq = NULL, *query = NULL, *instructions = NULL;
00779 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00780 iq = iks_new("iq");
00781 query = iks_new("query");
00782 instructions = iks_new("instructions");
00783 if (iq && query && instructions && client) {
00784 iks_insert_attrib(iq, "from", client->user);
00785 iks_insert_attrib(iq, "to", pak->from->full);
00786 iks_insert_attrib(iq, "id", pak->id);
00787 iks_insert_attrib(iq, "type", "result");
00788 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00789 iks_insert_cdata(instructions, explain, 0);
00790 iks_insert_node(iq, query);
00791 iks_insert_node(query, instructions);
00792 iks_send(client->p, iq);
00793 } else {
00794 ast_log(LOG_ERROR, "Out of memory.\n");
00795 }
00796 if (iq)
00797 iks_delete(iq);
00798 if (query)
00799 iks_delete(query);
00800 if (instructions)
00801 iks_delete(instructions);
00802 }
00803 ASTOBJ_UNREF(client, aji_client_destroy);
00804 return IKS_FILTER_EAT;
00805 }
00806
00807 static int aji_ditems_handler(void *data, ikspak *pak)
00808 {
00809 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00810 char *node = NULL;
00811
00812 if (!(node = iks_find_attrib(pak->query, "node"))) {
00813 iks *iq = NULL, *query = NULL, *item = NULL;
00814 iq = iks_new("iq");
00815 query = iks_new("query");
00816 item = iks_new("item");
00817
00818 if (iq && query && item) {
00819 iks_insert_attrib(iq, "from", client->user);
00820 iks_insert_attrib(iq, "to", pak->from->full);
00821 iks_insert_attrib(iq, "id", pak->id);
00822 iks_insert_attrib(iq, "type", "result");
00823 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00824 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00825 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00826 iks_insert_attrib(item, "jid", client->user);
00827
00828 iks_insert_node(iq, query);
00829 iks_insert_node(query, item);
00830 iks_send(client->p, iq);
00831 } else {
00832 ast_log(LOG_ERROR, "Out of memory.\n");
00833 }
00834 if (iq)
00835 iks_delete(iq);
00836 if (query)
00837 iks_delete(query);
00838 if (item)
00839 iks_delete(item);
00840
00841 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00842 iks *iq, *query, *confirm;
00843 iq = iks_new("iq");
00844 query = iks_new("query");
00845 confirm = iks_new("item");
00846 if (iq && query && confirm && client) {
00847 iks_insert_attrib(iq, "from", client->user);
00848 iks_insert_attrib(iq, "to", pak->from->full);
00849 iks_insert_attrib(iq, "id", pak->id);
00850 iks_insert_attrib(iq, "type", "result");
00851 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00852 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00853 iks_insert_attrib(confirm, "node", "confirmaccount");
00854 iks_insert_attrib(confirm, "name", "Confirm AIM account");
00855 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00856
00857 iks_insert_node(iq, query);
00858 iks_insert_node(query, confirm);
00859 iks_send(client->p, iq);
00860 } else {
00861 ast_log(LOG_ERROR, "Out of memory.\n");
00862 }
00863 if (iq)
00864 iks_delete(iq);
00865 if (query)
00866 iks_delete(query);
00867 if (confirm)
00868 iks_delete(confirm);
00869
00870 } else if (!strcasecmp(node, "confirmaccount")) {
00871 iks *iq = NULL, *query = NULL, *feature = NULL;
00872
00873 iq = iks_new("iq");
00874 query = iks_new("query");
00875 feature = iks_new("feature");
00876
00877 if (iq && query && feature && client) {
00878 iks_insert_attrib(iq, "from", client->user);
00879 iks_insert_attrib(iq, "to", pak->from->full);
00880 iks_insert_attrib(iq, "id", pak->id);
00881 iks_insert_attrib(iq, "type", "result");
00882 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00883 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00884 iks_insert_node(iq, query);
00885 iks_insert_node(query, feature);
00886 iks_send(client->p, iq);
00887 } else {
00888 ast_log(LOG_ERROR, "Out of memory.\n");
00889 }
00890 if (iq)
00891 iks_delete(iq);
00892 if (query)
00893 iks_delete(query);
00894 if (feature)
00895 iks_delete(feature);
00896 }
00897
00898 ASTOBJ_UNREF(client, aji_client_destroy);
00899 return IKS_FILTER_EAT;
00900
00901 }
00902
00903 static int aji_client_info_handler(void *data, ikspak *pak)
00904 {
00905 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00906 struct aji_resource *resource = NULL;
00907 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00908
00909 resource = aji_find_resource(buddy, pak->from->resource);
00910 if (pak->subtype == IKS_TYPE_RESULT) {
00911 if (!resource) {
00912 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00913 ASTOBJ_UNREF(client, aji_client_destroy);
00914 return IKS_FILTER_EAT;
00915 }
00916 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00917 resource->cap->jingle = 1;
00918 } else
00919 resource->cap->jingle = 0;
00920 } else if (pak->subtype == IKS_TYPE_GET) {
00921 iks *iq, *disco, *ident, *google, *query;
00922 iq = iks_new("iq");
00923 query = iks_new("query");
00924 ident = iks_new("identity");
00925 disco = iks_new("feature");
00926 google = iks_new("feature");
00927 if (iq && ident && disco && google) {
00928 iks_insert_attrib(iq, "from", client->jid->full);
00929 iks_insert_attrib(iq, "to", pak->from->full);
00930 iks_insert_attrib(iq, "type", "result");
00931 iks_insert_attrib(iq, "id", pak->id);
00932 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00933 iks_insert_attrib(ident, "category", "client");
00934 iks_insert_attrib(ident, "type", "pc");
00935 iks_insert_attrib(ident, "name", "asterisk");
00936 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00937 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00938 iks_insert_node(iq, query);
00939 iks_insert_node(query, ident);
00940 iks_insert_node(query, google);
00941 iks_insert_node(query, disco);
00942 iks_send(client->p, iq);
00943 } else
00944 ast_log(LOG_ERROR, "Out of Memory.\n");
00945 if (iq)
00946 iks_delete(iq);
00947 if (query)
00948 iks_delete(query);
00949 if (ident)
00950 iks_delete(ident);
00951 if (google)
00952 iks_delete(google);
00953 if (disco)
00954 iks_delete(disco);
00955 } else if (pak->subtype == IKS_TYPE_ERROR) {
00956 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00957 }
00958 ASTOBJ_UNREF(client, aji_client_destroy);
00959 return IKS_FILTER_EAT;
00960 }
00961
00962 static int aji_dinfo_handler(void *data, ikspak *pak)
00963 {
00964 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00965 char *node = NULL;
00966 struct aji_resource *resource = NULL;
00967 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00968
00969 resource = aji_find_resource(buddy, pak->from->resource);
00970 if (pak->subtype == IKS_TYPE_ERROR) {
00971 ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00972 return IKS_FILTER_EAT;
00973 }
00974 if (pak->subtype == IKS_TYPE_RESULT) {
00975 if (!resource) {
00976 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00977 ASTOBJ_UNREF(client, aji_client_destroy);
00978 return IKS_FILTER_EAT;
00979 }
00980 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00981 resource->cap->jingle = 1;
00982 } else
00983 resource->cap->jingle = 0;
00984 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00985 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00986
00987 iq = iks_new("iq");
00988 query = iks_new("query");
00989 identity = iks_new("identity");
00990 disco = iks_new("feature");
00991 reg = iks_new("feature");
00992 commands = iks_new("feature");
00993 gateway = iks_new("feature");
00994 version = iks_new("feature");
00995 vcard = iks_new("feature");
00996 search = iks_new("feature");
00997
00998 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
00999 iks_insert_attrib(iq, "from", client->user);
01000 iks_insert_attrib(iq, "to", pak->from->full);
01001 iks_insert_attrib(iq, "id", pak->id);
01002 iks_insert_attrib(iq, "type", "result");
01003 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01004 iks_insert_attrib(identity, "category", "gateway");
01005 iks_insert_attrib(identity, "type", "pstn");
01006 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01007 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01008 iks_insert_attrib(reg, "var", "jabber:iq:register");
01009 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01010 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01011 iks_insert_attrib(version, "var", "jabber:iq:version");
01012 iks_insert_attrib(vcard, "var", "vcard-temp");
01013 iks_insert_attrib(search, "var", "jabber:iq:search");
01014
01015 iks_insert_node(iq, query);
01016 iks_insert_node(query, identity);
01017 iks_insert_node(query, disco);
01018 iks_insert_node(query, reg);
01019 iks_insert_node(query, commands);
01020 iks_insert_node(query, gateway);
01021 iks_insert_node(query, version);
01022 iks_insert_node(query, vcard);
01023 iks_insert_node(query, search);
01024 iks_send(client->p, iq);
01025 } else {
01026 ast_log(LOG_ERROR, "Out of memory.\n");
01027 }
01028
01029 if (iq)
01030 iks_delete(iq);
01031 if (query)
01032 iks_delete(query);
01033 if (identity)
01034 iks_delete(identity);
01035 if (disco)
01036 iks_delete(disco);
01037 if (reg)
01038 iks_delete(reg);
01039 if (commands)
01040 iks_delete(commands);
01041 if (gateway)
01042 iks_delete(gateway);
01043 if (version)
01044 iks_delete(version);
01045 if (vcard)
01046 iks_delete(vcard);
01047 if (search)
01048 iks_delete(search);
01049
01050 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01051 iks *iq, *query, *confirm;
01052 iq = iks_new("iq");
01053 query = iks_new("query");
01054 confirm = iks_new("item");
01055
01056 if (iq && query && confirm && client) {
01057 iks_insert_attrib(iq, "from", client->user);
01058 iks_insert_attrib(iq, "to", pak->from->full);
01059 iks_insert_attrib(iq, "id", pak->id);
01060 iks_insert_attrib(iq, "type", "result");
01061 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01062 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01063 iks_insert_attrib(confirm, "node", "confirmaccount");
01064 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01065 iks_insert_attrib(confirm, "jid", client->user);
01066 iks_insert_node(iq, query);
01067 iks_insert_node(query, confirm);
01068 iks_send(client->p, iq);
01069 } else {
01070 ast_log(LOG_ERROR, "Out of memory.\n");
01071 }
01072 if (iq)
01073 iks_delete(iq);
01074 if (query)
01075 iks_delete(query);
01076 if (confirm)
01077 iks_delete(confirm);
01078
01079 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01080 iks *iq, *query, *feature;
01081
01082 iq = iks_new("iq");
01083 query = iks_new("query");
01084 feature = iks_new("feature");
01085
01086 if (iq && query && feature && client) {
01087 iks_insert_attrib(iq, "from", client->user);
01088 iks_insert_attrib(iq, "to", pak->from->full);
01089 iks_insert_attrib(iq, "id", pak->id);
01090 iks_insert_attrib(iq, "type", "result");
01091 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01092 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01093 iks_insert_node(iq, query);
01094 iks_insert_node(query, feature);
01095 iks_send(client->p, iq);
01096 } else {
01097 ast_log(LOG_ERROR, "Out of memory.\n");
01098 }
01099 if (iq)
01100 iks_delete(iq);
01101 if (query)
01102 iks_delete(query);
01103 if (feature)
01104 iks_delete(feature);
01105 }
01106
01107 ASTOBJ_UNREF(client, aji_client_destroy);
01108 return IKS_FILTER_EAT;
01109 }
01110
01111
01112
01113
01114
01115
01116 static void aji_handle_iq(struct aji_client *client, iks *node)
01117 {
01118
01119 }
01120
01121
01122
01123
01124
01125
01126 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01127 {
01128 struct aji_message *insert, *tmp;
01129 int flag = 0;
01130
01131 if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01132 return;
01133 time(&insert->arrived);
01134 if (iks_find_cdata(pak->x, "body"))
01135 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01136 if(pak->id)
01137 ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01138 if (pak->from)
01139 insert->from = ast_strdup(pak->from->full);
01140 AST_LIST_LOCK(&client->messages);
01141 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01142 if (flag) {
01143 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01144 if (tmp->from)
01145 free(tmp->from);
01146 if (tmp->message)
01147 free(tmp->message);
01148 } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01149 flag = 1;
01150 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01151 if (tmp->from)
01152 free(tmp->from);
01153 if (tmp->message)
01154 free(tmp->message);
01155 }
01156 }
01157 AST_LIST_TRAVERSE_SAFE_END;
01158 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01159 AST_LIST_UNLOCK(&client->messages);
01160 }
01161
01162 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01163 {
01164 int status, priority;
01165 struct aji_buddy *buddy;
01166 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01167 char *ver, *node, *descrip, *type;
01168
01169 if(client->state != AJI_CONNECTED)
01170 aji_create_buddy(pak->from->partial, client);
01171
01172 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01173 if (!buddy) {
01174 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01175 return;
01176 }
01177 type = iks_find_attrib(pak->x, "type");
01178 if(client->component && type &&!strcasecmp("probe", type)) {
01179 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01180 ast_verbose("what i was looking for \n");
01181 }
01182 ASTOBJ_WRLOCK(buddy);
01183 status = (pak->show) ? pak->show : 6;
01184 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01185 tmp = buddy->resources;
01186 descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01187
01188 while (tmp) {
01189 if (!strcasecmp(tmp->resource, pak->from->resource)) {
01190 tmp->status = status;
01191 if (tmp->description) free(tmp->description);
01192 tmp->description = descrip;
01193 found = tmp;
01194 if (status == 6) {
01195 if (last && found->next) {
01196 last->next = found->next;
01197 } else if (!last) {
01198 if (found->next)
01199 buddy->resources = found->next;
01200 else
01201 buddy->resources = NULL;
01202 } else if (!found->next) {
01203 if (last)
01204 last->next = NULL;
01205 else
01206 buddy->resources = NULL;
01207 }
01208 free(found);
01209 found = NULL;
01210 break;
01211 }
01212 if (tmp->priority != priority) {
01213 found->priority = priority;
01214 if (!last && !found->next)
01215 break;
01216 if (last)
01217 last->next = found->next;
01218 else
01219 buddy->resources = found->next;
01220 last = NULL;
01221 tmp = buddy->resources;
01222 if (!buddy->resources)
01223 buddy->resources = found;
01224 while (tmp) {
01225 if (found->priority > tmp->priority) {
01226 if (last)
01227 last->next = found;
01228 found->next = tmp;
01229 if (!last)
01230 buddy->resources = found;
01231 break;
01232 }
01233 if (!tmp->next) {
01234 tmp->next = found;
01235 break;
01236 }
01237 last = tmp;
01238 tmp = tmp->next;
01239 }
01240 }
01241 break;
01242 }
01243 last = tmp;
01244 tmp = tmp->next;
01245 }
01246
01247 if (!found && status != 6) {
01248 found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01249 memset(found, 0, sizeof(struct aji_resource));
01250
01251 if (!found) {
01252 ast_log(LOG_ERROR, "Out of memory!\n");
01253 return;
01254 }
01255 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01256 found->status = status;
01257 found->description = descrip;
01258 found->priority = priority;
01259 found->next = NULL;
01260 last = NULL;
01261 tmp = buddy->resources;
01262 while (tmp) {
01263 if (found->priority > tmp->priority) {
01264 if (last)
01265 last->next = found;
01266 found->next = tmp;
01267 if (!last)
01268 buddy->resources = found;
01269 break;
01270 }
01271 if (!tmp->next) {
01272 tmp->next = found;
01273 break;
01274 }
01275 last = tmp;
01276 tmp = tmp->next;
01277 }
01278 if (!tmp)
01279 buddy->resources = found;
01280 }
01281 ASTOBJ_UNLOCK(buddy);
01282 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01283
01284 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01285 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01286
01287 if(status !=6 && !found->cap) {
01288 found->cap = aji_find_version(node, ver, pak);
01289 if(gtalk_yuck(pak->x))
01290 found->cap->jingle = 1;
01291 if(found->cap->jingle && option_debug > 4)
01292 ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01293 else {
01294 iks *iq, *query;
01295 iq = iks_new("iq");
01296 query = iks_new("query");
01297 if(query && iq) {
01298 iks_insert_attrib(iq, "type", "get");
01299 iks_insert_attrib(iq, "to", pak->from->full);
01300 iks_insert_attrib(iq,"from",iks_find_attrib(pak->x,"to"));
01301 iks_insert_attrib(iq, "id", client->mid);
01302 ast_aji_increment_mid(client->mid);
01303 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01304 iks_insert_node(iq, query);
01305 iks_send(client->p, iq);
01306
01307 } else
01308 ast_log(LOG_ERROR, "Out of memory.\n");
01309 if(query)
01310 iks_delete(query);
01311 if(iq)
01312 iks_delete(iq);
01313 }
01314 }
01315 if (option_verbose > 4) {
01316 switch (pak->subtype) {
01317 case IKS_TYPE_AVAILABLE:
01318 ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01319 break;
01320 case IKS_TYPE_UNAVAILABLE:
01321 ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01322 break;
01323 default:
01324 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01325 }
01326 switch (pak->show) {
01327 case IKS_SHOW_UNAVAILABLE:
01328 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01329 break;
01330 case IKS_SHOW_AVAILABLE:
01331 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01332 break;
01333 case IKS_SHOW_CHAT:
01334 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01335 break;
01336 case IKS_SHOW_AWAY:
01337 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01338 break;
01339 case IKS_SHOW_XA:
01340 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01341 break;
01342 case IKS_SHOW_DND:
01343 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01344 break;
01345 default:
01346 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01347 }
01348 }
01349 }
01350
01351
01352
01353
01354
01355
01356 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01357 {
01358 if(pak->subtype == IKS_TYPE_SUBSCRIBE) {
01359 iks *presence = NULL, *status = NULL;
01360 presence = iks_new("presence");
01361 status = iks_new("status");
01362 if(presence && status) {
01363 iks_insert_attrib(presence, "type", "subscribed");
01364 iks_insert_attrib(presence, "to", pak->from->full);
01365 iks_insert_attrib(presence, "from", client->jid->full);
01366 if(pak->id)
01367 iks_insert_attrib(presence, "id", pak->id);
01368 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01369 iks_insert_node(presence, status);
01370 iks_send(client->p, presence);
01371 } else
01372 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01373 if(presence)
01374 iks_delete(presence);
01375 if(status)
01376 iks_delete(status);
01377 if(client->component)
01378 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01379 }
01380 if (option_verbose > 4) {
01381 switch (pak->subtype) {
01382 case IKS_TYPE_SUBSCRIBE:
01383 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01384 break;
01385 case IKS_TYPE_SUBSCRIBED:
01386 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01387 break;
01388 case IKS_TYPE_UNSUBSCRIBE:
01389 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01390 break;
01391 case IKS_TYPE_UNSUBSCRIBED:
01392 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01393 break;
01394 default:
01395 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01396 break;
01397 }
01398 }
01399 }
01400
01401
01402
01403
01404
01405
01406 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
01407 {
01408 int res = 0;
01409 iks *message_packet = NULL;
01410 if (client->state == AJI_CONNECTED) {
01411 message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01412 if (message_packet) {
01413 iks_insert_attrib(message_packet, "from", client->jid->full);
01414 res = iks_send(client->p, message_packet);
01415 } else {
01416 ast_log(LOG_ERROR, "Out of memory.\n");
01417 }
01418 if (message_packet)
01419 iks_delete(message_packet);
01420 } else
01421 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01422 return 1;
01423 }
01424
01425
01426
01427
01428
01429
01430 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01431 {
01432 int res = 0;
01433 iks *iq = NULL;
01434 iq = iks_new("iq");
01435 if (iq && client) {
01436 iks_insert_attrib(iq, "type", "get");
01437 iks_insert_attrib(iq, "to", server);
01438 iks_insert_attrib(iq, "id", client->mid);
01439 ast_aji_increment_mid(client->mid);
01440 iks_send(client->p, iq);
01441 } else
01442 ast_log(LOG_ERROR, "Out of memory.\n");
01443 return res;
01444 }
01445
01446
01447
01448
01449
01450
01451 int ast_aji_join_chat(struct aji_client *client, char *room)
01452 {
01453 int res = 0;
01454 iks *presence = NULL, *priority = NULL;
01455 presence = iks_new("presence");
01456 priority = iks_new("priority");
01457 if (presence && priority && client) {
01458 iks_insert_cdata(priority, "0", 1);
01459 iks_insert_attrib(presence, "to", room);
01460 iks_insert_node(presence, priority);
01461 res = iks_send(client->p, presence);
01462 iks_insert_cdata(priority, "5", 1);
01463 iks_insert_attrib(presence, "to", room);
01464 res = iks_send(client->p, presence);
01465 } else
01466 ast_log(LOG_ERROR, "Out of memory.\n");
01467 if (presence)
01468 iks_delete(presence);
01469 if (priority)
01470 iks_delete(priority);
01471 return res;
01472 }
01473
01474
01475
01476
01477
01478
01479 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01480 {
01481 int res = 0;
01482 iks *invite, *body, *namespace;
01483
01484 invite = iks_new("message");
01485 body = iks_new("body");
01486 namespace = iks_new("x");
01487 if (client && invite && body && namespace) {
01488 iks_insert_attrib(invite, "to", user);
01489 iks_insert_attrib(invite, "id", client->mid);
01490 ast_aji_increment_mid(client->mid);
01491 iks_insert_cdata(body, message, 0);
01492 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01493 iks_insert_attrib(namespace, "jid", room);
01494 iks_insert_node(invite, body);
01495 iks_insert_node(invite, namespace);
01496 res = iks_send(client->p, invite);
01497 } else
01498 ast_log(LOG_ERROR, "Out of memory.\n");
01499 if (body)
01500 iks_delete(body);
01501 if (namespace)
01502 iks_delete(namespace);
01503 if (invite)
01504 iks_delete(invite);
01505 return res;
01506 }
01507
01508
01509
01510
01511
01512
01513
01514 static void *aji_recv_loop(void *data)
01515 {
01516 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01517 int res = IKS_HOOK;
01518 do {
01519 if (res != IKS_OK) {
01520 while(res != IKS_OK) {
01521 if(option_verbose > 3)
01522 ast_verbose("JABBER: reconnecting.\n");
01523 res = aji_reconnect(client);
01524 sleep(4);
01525 }
01526 }
01527
01528 res = iks_recv(client->p, 1);
01529
01530 if (client->state == AJI_DISCONNECTING) {
01531 if (option_debug > 1)
01532 ast_log(LOG_DEBUG, "Ending our Jabber client's thread due to a disconnect\n");
01533 pthread_exit(NULL);
01534 }
01535 client->timeout--;
01536 if (res == IKS_HOOK)
01537 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01538 else if (res == IKS_NET_TLSFAIL)
01539 ast_log(LOG_WARNING, "JABBER: Failure in TLS.\n");
01540 else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01541 res = iks_send_raw(client->p, " ");
01542 if(res == IKS_OK)
01543 client->timeout = 50;
01544 else
01545 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
01546 } else if (res == IKS_NET_RWERR)
01547 ast_log(LOG_WARNING, "JABBER: socket read error\n");
01548 } while (client);
01549 ASTOBJ_UNREF(client, aji_client_destroy);
01550 return 0;
01551 }
01552
01553
01554
01555
01556
01557
01558 void ast_aji_increment_mid(char *mid)
01559 {
01560 int i = 0;
01561
01562 for (i = strlen(mid) - 1; i >= 0; i--) {
01563 if (mid[i] != 'z') {
01564 mid[i] = mid[i] + 1;
01565 i = 0;
01566 } else
01567 mid[i] = 'a';
01568 }
01569 }
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665 static void aji_pruneregister(struct aji_client *client)
01666 {
01667 int res = 0;
01668 iks *removeiq = iks_new("iq");
01669 iks *removequery = iks_new("query");
01670 iks *removeitem = iks_new("item");
01671 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
01672
01673 if (client && removeiq && removequery && removeitem && send) {
01674 iks_insert_node(removeiq, removequery);
01675 iks_insert_node(removequery, removeitem);
01676 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01677 ASTOBJ_RDLOCK(iterator);
01678
01679
01680 if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
01681 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
01682 "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
01683 " so I am no longer subscribing to your presence.\n"));
01684 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
01685 "GoodBye you are no longer in the asterisk config file so I am removing"
01686 " your access to my presence.\n"));
01687 iks_insert_attrib(removeiq, "from", client->jid->full);
01688 iks_insert_attrib(removeiq, "type", "set");
01689 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
01690 iks_insert_attrib(removeitem, "jid", iterator->name);
01691 iks_insert_attrib(removeitem, "subscription", "remove");
01692 res = iks_send(client->p, removeiq);
01693 } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
01694 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
01695 "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
01696 ast_clear_flag(iterator, AJI_AUTOREGISTER);
01697 }
01698 ASTOBJ_UNLOCK(iterator);
01699 });
01700 } else
01701 ast_log(LOG_ERROR, "Out of memory.\n");
01702 if (removeiq)
01703 iks_delete(removeiq);
01704 if (removequery)
01705 iks_delete(removequery);
01706 if (removeitem)
01707 iks_delete(removeitem);
01708 if (send)
01709 iks_delete(send);
01710 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
01711 }
01712
01713
01714
01715
01716
01717
01718 static int aji_filter_roster(void *data, ikspak *pak)
01719 {
01720 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01721 int flag = 0;
01722 iks *x = NULL;
01723 struct aji_buddy *buddy;
01724
01725 client->state = AJI_CONNECTED;
01726 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01727 ASTOBJ_RDLOCK(iterator);
01728 x = iks_child(pak->query);
01729 flag = 0;
01730 while (x) {
01731 if (!iks_strcmp(iks_name(x), "item")) {
01732 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
01733 flag = 1;
01734 ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
01735 }
01736 }
01737 x = iks_next(x);
01738 }
01739 if (!flag)
01740 ast_copy_flags(iterator, client, AJI_AUTOREGISTER);
01741 if (x)
01742 iks_delete(x);
01743 ASTOBJ_UNLOCK(iterator);
01744 });
01745
01746 x = iks_child(pak->query);
01747 while (x) {
01748 flag = 0;
01749 if (iks_strcmp(iks_name(x), "item") == 0) {
01750 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01751 ASTOBJ_RDLOCK(iterator);
01752 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
01753 flag = 1;
01754 ASTOBJ_UNLOCK(iterator);
01755 });
01756
01757 if (!flag) {
01758 buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
01759 if (!buddy) {
01760 ast_log(LOG_WARNING, "Out of memory\n");
01761 return 0;
01762 }
01763 memset(buddy, 0, sizeof(struct aji_buddy));
01764 ASTOBJ_INIT(buddy);
01765 ASTOBJ_WRLOCK(buddy);
01766 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
01767 ast_clear_flag(buddy, AST_FLAGS_ALL);
01768 if(ast_test_flag(client, AJI_AUTOPRUNE)) {
01769 ast_set_flag(buddy, AJI_AUTOPRUNE);
01770 buddy->objflags |= ASTOBJ_FLAG_MARKED;
01771 } else
01772 ast_set_flag(buddy, AJI_AUTOREGISTER);
01773 ASTOBJ_UNLOCK(buddy);
01774 if (buddy) {
01775 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
01776 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01777 }
01778 }
01779 }
01780 x = iks_next(x);
01781 }
01782 if (x)
01783 iks_delete(x);
01784 aji_pruneregister(client);
01785
01786 ASTOBJ_UNREF(client, aji_client_destroy);
01787 return IKS_FILTER_EAT;
01788 }
01789
01790 static int aji_reconnect(struct aji_client *client)
01791 {
01792 int res = 0;
01793
01794 if (client->state)
01795 client->state = AJI_DISCONNECTED;
01796 client->timeout=50;
01797 if (client->p)
01798 iks_parser_reset(client->p);
01799 if (client->authorized)
01800 client->authorized = 0;
01801
01802 if(client->component)
01803 res = aji_component_initialize(client);
01804 else
01805 res = aji_client_initialize(client);
01806
01807 return res;
01808 }
01809
01810 static int aji_get_roster(struct aji_client *client)
01811 {
01812 iks *roster = NULL;
01813 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
01814 if(roster) {
01815 iks_insert_attrib(roster, "id", "roster");
01816 aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
01817 iks_send(client->p, roster);
01818 }
01819 if (roster)
01820 iks_delete(roster);
01821 return 1;
01822 }
01823
01824
01825
01826
01827
01828
01829 static int aji_client_connect(void *data, ikspak *pak)
01830 {
01831 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01832 int res = 0;
01833
01834 if (client) {
01835 if (client->state == AJI_DISCONNECTED) {
01836 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);
01837 client->state = AJI_CONNECTING;
01838 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
01839 iks_filter_remove_hook(client->f, aji_client_connect);
01840 if(!client->component)
01841 aji_get_roster(client);
01842 }
01843 } else
01844 ast_log(LOG_ERROR, "Out of memory.\n");
01845
01846 ASTOBJ_UNREF(client, aji_client_destroy);
01847 return res;
01848 }
01849
01850
01851
01852
01853
01854
01855 static int aji_client_initialize(struct aji_client *client)
01856 {
01857 int connected = 0;
01858
01859 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
01860
01861 if (connected == IKS_NET_NOCONN) {
01862 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01863 return IKS_HOOK;
01864 } else if (connected == IKS_NET_NODNS) {
01865 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01866 return IKS_HOOK;
01867 } else
01868 iks_recv(client->p, 30);
01869 return IKS_OK;
01870 }
01871
01872
01873
01874
01875
01876
01877 static int aji_component_initialize(struct aji_client *client)
01878 {
01879 int connected = 1;
01880
01881 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->user);
01882 if (connected == IKS_NET_NOCONN) {
01883 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01884 return IKS_HOOK;
01885 } else if (connected == IKS_NET_NODNS) {
01886 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01887 return IKS_HOOK;
01888 } else if (!connected)
01889 iks_recv(client->p, 30);
01890 return IKS_OK;
01891 }
01892
01893
01894
01895
01896
01897
01898 int ast_aji_disconnect(struct aji_client *client)
01899 {
01900 if (client) {
01901 if (option_verbose > 3)
01902 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Disconnecting\n");
01903 iks_disconnect(client->p);
01904 iks_parser_delete(client->p);
01905 ASTOBJ_UNREF(client, aji_client_destroy);
01906 }
01907
01908 return 1;
01909 }
01910
01911
01912
01913
01914
01915
01916 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
01917 {
01918 int res = 0;
01919 iks *presence = iks_make_pres(level, desc);
01920 iks *cnode = iks_new("c");
01921 iks *priority = iks_new("priority");
01922
01923 iks_insert_cdata(priority, "0", 1);
01924 if (presence && cnode && client) {
01925 if(to)
01926 iks_insert_attrib(presence, "to", to);
01927 if(from)
01928 iks_insert_attrib(presence, "from", from);
01929 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
01930 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
01931 iks_insert_attrib(cnode, "ext", "voice-v1");
01932 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
01933 iks_insert_node(presence, cnode);
01934 res = iks_send(client->p, presence);
01935 } else
01936 ast_log(LOG_ERROR, "Out of memory.\n");
01937 if (cnode)
01938 iks_delete(cnode);
01939 if (presence)
01940 iks_delete(presence);
01941 }
01942
01943
01944
01945
01946
01947
01948 static int aji_do_debug(int fd, int argc, char *argv[])
01949 {
01950 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01951 ASTOBJ_RDLOCK(iterator);
01952 iterator->debug = 1;
01953 ASTOBJ_UNLOCK(iterator);
01954 });
01955 ast_cli(fd, "Jabber Debugging Enabled.\n");
01956 return RESULT_SUCCESS;
01957 }
01958
01959
01960
01961
01962
01963
01964 static int aji_do_reload(int fd, int argc, char *argv[])
01965 {
01966 aji_reload();
01967 ast_cli(fd, "Jabber Reloaded.\n");
01968 return RESULT_SUCCESS;
01969 }
01970
01971
01972
01973
01974
01975
01976 static int aji_no_debug(int fd, int argc, char *argv[])
01977 {
01978 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01979 ASTOBJ_RDLOCK(iterator);
01980 iterator->debug = 0;
01981 ASTOBJ_UNLOCK(iterator);
01982 });
01983 ast_cli(fd, "Jabber Debugging Disabled.\n");
01984 return RESULT_SUCCESS;
01985 }
01986
01987
01988
01989
01990
01991
01992 static int aji_show_clients(int fd, int argc, char *argv[])
01993 {
01994 char *status;
01995 int count = 0;
01996 ast_cli(fd, "Jabber Users and their status:\n");
01997 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01998 ASTOBJ_RDLOCK(iterator);
01999 count++;
02000 switch (iterator->state) {
02001 case AJI_DISCONNECTED:
02002 status = "Disconnected";
02003 break;
02004 case AJI_CONNECTING:
02005 status = "Connecting";
02006 break;
02007 case AJI_CONNECTED:
02008 status = "Connected";
02009 break;
02010 default:
02011 status = "Unknown";
02012 }
02013 ast_cli(fd, " User: %s - %s\n", iterator->user, status);
02014 ASTOBJ_UNLOCK(iterator);
02015 });
02016 ast_cli(fd, "----\n");
02017 ast_cli(fd, " Number of users: %d\n", count);
02018 return RESULT_SUCCESS;
02019 }
02020
02021
02022
02023
02024
02025
02026 static int aji_test(int fd, int argc, char *argv[])
02027 {
02028 struct aji_client *client;
02029 struct aji_resource *resource;
02030 const char *name = "asterisk";
02031 struct aji_message *tmp;
02032
02033 if (argc > 3)
02034 return RESULT_SHOWUSAGE;
02035 else if (argc == 3)
02036 name = argv[2];
02037
02038 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02039 ast_cli(fd, "Unable to find client '%s'!\n", name);
02040 return RESULT_FAILURE;
02041 }
02042
02043
02044 ast_aji_send(client, "mogorman@astjab.org", "blahblah");
02045 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02046 ASTOBJ_RDLOCK(iterator);
02047 ast_verbose("User: %s\n", iterator->name);
02048 for (resource = iterator->resources; resource; resource = resource->next) {
02049 ast_verbose("Resource: %s\n", resource->resource);
02050 if(resource->cap) {
02051 ast_verbose(" client: %s\n", resource->cap->parent->node);
02052 ast_verbose(" version: %s\n", resource->cap->version);
02053 ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
02054 }
02055 ast_verbose(" Priority: %d\n", resource->priority);
02056 ast_verbose(" Status: %d\n", resource->status);
02057 ast_verbose(" Message: %s\n", S_OR(resource->description,""));
02058 }
02059 ASTOBJ_UNLOCK(iterator);
02060 });
02061 ast_verbose("\nOooh a working message stack!\n");
02062 AST_LIST_LOCK(&client->messages);
02063 AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02064 ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02065 }
02066 AST_LIST_UNLOCK(&client->messages);
02067 ASTOBJ_UNREF(client, aji_client_destroy);
02068
02069 return RESULT_SUCCESS;
02070 }
02071
02072
02073
02074
02075
02076
02077 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02078 {
02079 char *resource;
02080 struct aji_client *client = NULL;
02081 int flag = 0;
02082
02083 client = ASTOBJ_CONTAINER_FIND(&clients,label);
02084 if (!client) {
02085 flag = 1;
02086 client = (struct aji_client *) malloc(sizeof(struct aji_client));
02087 if (!client) {
02088 ast_log(LOG_ERROR, "Out of memory!\n");
02089 return 0;
02090 }
02091 memset(client, 0, sizeof(struct aji_client));
02092 ASTOBJ_INIT(client);
02093 ASTOBJ_WRLOCK(client);
02094 ASTOBJ_CONTAINER_INIT(&client->buddies);
02095 } else {
02096 ASTOBJ_WRLOCK(client);
02097 ASTOBJ_UNMARK(client);
02098 }
02099 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02100 ast_copy_string(client->name, label, sizeof(client->name));
02101 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02102
02103
02104 client->debug = debug;
02105 ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
02106 client->port = 5222;
02107 client->usetls = 1;
02108 client->usesasl = 1;
02109 client->forcessl = 0;
02110 client->keepalive = 1;
02111 client->timeout = 50;
02112 client->message_timeout = 100;
02113 AST_LIST_HEAD_INIT(&client->messages);
02114 client->component = 0;
02115 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02116
02117 if (flag) {
02118 client->authorized = 0;
02119 client->state = AJI_DISCONNECTED;
02120 }
02121 while (var) {
02122 if (!strcasecmp(var->name, "username"))
02123 ast_copy_string(client->user, var->value, sizeof(client->user));
02124 else if (!strcasecmp(var->name, "serverhost"))
02125 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02126 else if (!strcasecmp(var->name, "secret"))
02127 ast_copy_string(client->password, var->value, sizeof(client->password));
02128 else if (!strcasecmp(var->name, "statusmessage"))
02129 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02130 else if (!strcasecmp(var->name, "port"))
02131 client->port = atoi(var->value);
02132 else if (!strcasecmp(var->name, "timeout"))
02133 client->message_timeout = atoi(var->value);
02134 else if (!strcasecmp(var->name, "debug"))
02135 client->debug = (ast_false(var->value)) ? 0 : 1;
02136 else if (!strcasecmp(var->name, "type")) {
02137 if (!strcasecmp(var->value, "component"))
02138 client->component = 1;
02139 } else if (!strcasecmp(var->name, "usetls")) {
02140 client->usetls = (ast_false(var->value)) ? 0 : 1;
02141 } else if (!strcasecmp(var->name, "usesasl")) {
02142 client->usesasl = (ast_false(var->value)) ? 0 : 1;
02143 } else if (!strcasecmp(var->name, "forceoldssl"))
02144 client->forcessl = (ast_false(var->value)) ? 0 : 1;
02145 else if (!strcasecmp(var->name, "keepalive"))
02146 client->keepalive = (ast_false(var->value)) ? 0 : 1;
02147 else if (!strcasecmp(var->name, "autoprune"))
02148 ast_set2_flag(client, ast_true(var->value), AJI_AUTOPRUNE);
02149 else if (!strcasecmp(var->name, "autoregister"))
02150 ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
02151 else if (!strcasecmp(var->name, "buddy"))
02152 aji_create_buddy(var->value, client);
02153
02154
02155
02156
02157 var = var->next;
02158 }
02159 if (!flag) {
02160 ASTOBJ_UNLOCK(client);
02161 ASTOBJ_UNREF(client, aji_client_destroy);
02162 return 1;
02163 }
02164 client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
02165 if (!client->p) {
02166 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02167 return 0;
02168 }
02169 client->stack = iks_stack_new(8192, 8192);
02170 if (!client->stack) {
02171 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02172 return 0;
02173 }
02174 client->f = iks_filter_new();
02175 if (!client->f) {
02176 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02177 return 0;
02178 }
02179 if (!strchr(client->user, '/') && !client->component) {
02180 resource = NULL;
02181 asprintf(&resource, "%s/asterisk", client->user);
02182 if (resource) {
02183 client->jid = iks_id_new(client->stack, resource);
02184 free(resource);
02185 }
02186 } else
02187 client->jid = iks_id_new(client->stack, client->user);
02188 if (client->component) {
02189 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02190 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02191 iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02192 iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02193 } else {
02194 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02195 }
02196 if (!strchr(client->user, '/') && !client->component) {
02197 resource = NULL;
02198 asprintf(&resource, "%s/asterisk", client->user);
02199 if (resource) {
02200 client->jid = iks_id_new(client->stack, resource);
02201 free(resource);
02202 }
02203 } else
02204 client->jid = iks_id_new(client->stack, client->user);
02205 iks_set_log_hook(client->p, aji_log_hook);
02206 ASTOBJ_UNLOCK(client);
02207 ASTOBJ_CONTAINER_LINK(&clients,client);
02208 return 1;
02209 }
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268 static int aji_create_buddy(char *label, struct aji_client *client)
02269 {
02270 struct aji_buddy *buddy = NULL;
02271 int flag = 0;
02272 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02273 if (!buddy) {
02274 flag = 1;
02275 buddy = malloc(sizeof(struct aji_buddy));
02276 if(!buddy) {
02277 ast_log(LOG_WARNING, "Out of memory\n");
02278 return 0;
02279 }
02280 memset(buddy, 0, sizeof(struct aji_buddy));
02281 ASTOBJ_INIT(buddy);
02282 }
02283 ASTOBJ_WRLOCK(buddy);
02284 ast_copy_string(buddy->name, label, sizeof(buddy->name));
02285 ASTOBJ_UNLOCK(buddy);
02286 if(flag)
02287 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02288 else {
02289 ASTOBJ_UNMARK(buddy);
02290 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02291 }
02292 return 1;
02293 }
02294
02295
02296
02297
02298
02299
02300 static int aji_load_config(void)
02301 {
02302 char *cat = NULL;
02303 int debug = 1;
02304 struct ast_config *cfg = NULL;
02305 struct ast_variable *var = NULL;
02306
02307 cfg = ast_config_load(JABBER_CONFIG);
02308 if (!cfg) {
02309 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02310 return 0;
02311 }
02312
02313 cat = ast_category_browse(cfg, NULL);
02314 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02315 if (!strcasecmp(var->name, "debug"))
02316 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02317 else if (!strcasecmp(var->name, "autoprune"))
02318 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02319 else if (!strcasecmp(var->name, "autoregister"))
02320 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02321 }
02322
02323 while (cat) {
02324 if (strcasecmp(cat, "general")) {
02325 var = ast_variable_browse(cfg, cat);
02326 aji_create_client(cat, var, debug);
02327 }
02328 cat = ast_category_browse(cfg, cat);
02329 }
02330 return 1;
02331 }
02332
02333
02334
02335
02336
02337
02338 struct aji_client *ast_aji_get_client(const char *name)
02339 {
02340 struct aji_client *client = NULL;
02341
02342 client = ASTOBJ_CONTAINER_FIND(&clients, name);
02343 if (!client && !strchr(name, '@'))
02344 client = ASTOBJ_CONTAINER_FIND_FULL(&clients, name, user,,, strcasecmp);
02345 return client;
02346 }
02347
02348 struct aji_client_container *ast_aji_get_clients(void)
02349 {
02350 return &clients;
02351 }
02352
02353 static char mandescr_jabber_send[] =
02354 "Description: Sends a message to a Jabber Client.\n"
02355 "Variables: \n"
02356 " Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
02357 " ScreenName: User Name to message.\n"
02358 " Message: Message to be sent to the buddy\n";
02359
02360
02361 static int manager_jabber_send(struct mansession *s, const struct message *m)
02362 {
02363 struct aji_client *client = NULL;
02364 const char *id = astman_get_header(m,"ActionID");
02365 const char *jabber = astman_get_header(m,"Jabber");
02366 const char *screenname = astman_get_header(m,"ScreenName");
02367 const char *message = astman_get_header(m,"Message");
02368
02369 if (ast_strlen_zero(jabber)) {
02370 astman_send_error(s, m, "No transport specified");
02371 return 0;
02372 }
02373 if (ast_strlen_zero(screenname)) {
02374 astman_send_error(s, m, "No ScreenName specified");
02375 return 0;
02376 }
02377 if (ast_strlen_zero(message)) {
02378 astman_send_error(s, m, "No Message specified");
02379 return 0;
02380 }
02381
02382 astman_send_ack(s, m, "Attempting to send Jabber Message");
02383 client = ast_aji_get_client(jabber);
02384 if (!client) {
02385 astman_send_error(s, m, "Could not find Sender");
02386 return 0;
02387 }
02388 if (strchr(screenname, '@') && message){
02389 ast_aji_send(client, screenname, message);
02390 if (!ast_strlen_zero(id))
02391 astman_append(s, "ActionID: %s\r\n",id);
02392 astman_append(s, "Response: Success\r\n");
02393 return 0;
02394 }
02395 if (!ast_strlen_zero(id))
02396 astman_append(s, "ActionID: %s\r\n",id);
02397 astman_append(s, "Response: Failure\r\n");
02398 return 0;
02399 }
02400
02401
02402 static int aji_reload()
02403 {
02404 ASTOBJ_CONTAINER_MARKALL(&clients);
02405 if (!aji_load_config()) {
02406 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02407 return 0;
02408 }
02409 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02410 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02411 ASTOBJ_RDLOCK(iterator);
02412 if(iterator->state == AJI_DISCONNECTED) {
02413 if (!iterator->thread)
02414 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02415 } else if (iterator->state == AJI_CONNECTING)
02416 aji_get_roster(iterator);
02417 ASTOBJ_UNLOCK(iterator);
02418 });
02419
02420 return 1;
02421 }
02422
02423 static int unload_module(void)
02424 {
02425
02426
02427
02428
02429
02430
02431 if (tls_initialized) {
02432 ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02433 return 1;
02434 }
02435
02436 ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02437 ast_unregister_application(app_ajisend);
02438 ast_unregister_application(app_ajistatus);
02439 ast_manager_unregister("JabberSend");
02440
02441 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02442 ASTOBJ_RDLOCK(iterator);
02443 if (option_debug > 2)
02444 ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02445 iterator->state = AJI_DISCONNECTING;
02446 ast_aji_disconnect(iterator);
02447 pthread_join(iterator->thread, NULL);
02448 ASTOBJ_UNLOCK(iterator);
02449 });
02450
02451 ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02452 ASTOBJ_CONTAINER_DESTROY(&clients);
02453 return 0;
02454 }
02455
02456 static int load_module(void)
02457 {
02458 ASTOBJ_CONTAINER_INIT(&clients);
02459 if(!aji_reload())
02460 return AST_MODULE_LOAD_DECLINE;
02461 ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
02462 "Sends a message to a Jabber Client", mandescr_jabber_send);
02463 ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
02464 ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
02465 ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02466
02467 return 0;
02468 }
02469
02470 static int reload(void)
02471 {
02472 aji_reload();
02473 return 0;
02474 }
02475
02476 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
02477 .load = load_module,
02478 .unload = unload_module,
02479 .reload = reload,
02480 );