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