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