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
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "asterisk.h"
00044
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413587 $")
00046
00047 #include <sys/socket.h>
00048 #include <fcntl.h>
00049 #include <netdb.h>
00050 #include <netinet/in.h>
00051 #include <arpa/inet.h>
00052 #include <sys/signal.h>
00053 #include <iksemel.h>
00054 #include <pthread.h>
00055 #include <ctype.h>
00056
00057 #include "asterisk/lock.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/sched.h"
00063 #include "asterisk/io.h"
00064 #include "asterisk/rtp_engine.h"
00065 #include "asterisk/stun.h"
00066 #include "asterisk/acl.h"
00067 #include "asterisk/callerid.h"
00068 #include "asterisk/file.h"
00069 #include "asterisk/cli.h"
00070 #include "asterisk/app.h"
00071 #include "asterisk/musiconhold.h"
00072 #include "asterisk/manager.h"
00073 #include "asterisk/stringfields.h"
00074 #include "asterisk/utils.h"
00075 #include "asterisk/causes.h"
00076 #include "asterisk/astobj.h"
00077 #include "asterisk/abstract_jb.h"
00078 #include "asterisk/jabber.h"
00079 #include "asterisk/jingle.h"
00080 #include "asterisk/features.h"
00081
00082 #define GOOGLE_CONFIG "gtalk.conf"
00083
00084
00085 static struct ast_jb_conf default_jbconf =
00086 {
00087 .flags = 0,
00088 .max_size = -1,
00089 .resync_threshold = -1,
00090 .impl = "",
00091 .target_extra = -1,
00092 };
00093 static struct ast_jb_conf global_jbconf;
00094
00095 enum gtalk_protocol {
00096 AJI_PROTOCOL_UDP = 1,
00097 AJI_PROTOCOL_SSLTCP = 2,
00098 };
00099
00100 enum gtalk_connect_type {
00101 AJI_CONNECT_STUN = 1,
00102 AJI_CONNECT_LOCAL = 2,
00103 AJI_CONNECT_RELAY = 3,
00104 };
00105
00106 struct gtalk_pvt {
00107 ast_mutex_t lock;
00108 time_t laststun;
00109 struct gtalk *parent;
00110 char sid[100];
00111 char us[AJI_MAX_JIDLEN];
00112 char them[AJI_MAX_JIDLEN];
00113 char ring[10];
00114 iksrule *ringrule;
00115 int initiator;
00116 int alreadygone;
00117 struct ast_codec_pref prefs;
00118 struct gtalk_candidate *theircandidates;
00119 struct gtalk_candidate *ourcandidates;
00120 char cid_num[80];
00121 char cid_name[80];
00122 char exten[80];
00123 struct ast_channel *owner;
00124 struct ast_rtp_instance *rtp;
00125 struct ast_rtp_instance *vrtp;
00126 struct ast_format_cap *cap;
00127 struct ast_format_cap *jointcap;
00128 struct ast_format_cap *peercap;
00129 struct gtalk_pvt *next;
00130 };
00131
00132 struct gtalk_candidate {
00133 char name[100];
00134 enum gtalk_protocol protocol;
00135 double preference;
00136 char username[100];
00137 char password[100];
00138 enum gtalk_connect_type type;
00139 char network[6];
00140 int generation;
00141 char ip[16];
00142 int port;
00143 int receipt;
00144 struct gtalk_candidate *next;
00145 };
00146
00147 struct gtalk {
00148 ASTOBJ_COMPONENTS(struct gtalk);
00149 struct aji_client *connection;
00150 struct aji_buddy *buddy;
00151 struct gtalk_pvt *p;
00152 struct ast_codec_pref prefs;
00153 int amaflags;
00154 char user[AJI_MAX_JIDLEN];
00155 char context[AST_MAX_CONTEXT];
00156 char parkinglot[AST_MAX_CONTEXT];
00157 char accountcode[AST_MAX_ACCOUNT_CODE];
00158 struct ast_format_cap *cap;
00159 ast_group_t callgroup;
00160 ast_group_t pickupgroup;
00161 int callingpres;
00162 int allowguest;
00163 char language[MAX_LANGUAGE];
00164 char musicclass[MAX_MUSICCLASS];
00165 };
00166
00167 struct gtalk_container {
00168 ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
00169 };
00170
00171 static const char desc[] = "Gtalk Channel";
00172 static const char DEFAULT_CONTEXT[] = "default";
00173 static const int DEFAULT_ALLOWGUEST = 1;
00174
00175 static struct ast_format_cap *global_capability;
00176
00177 AST_MUTEX_DEFINE_STATIC(gtalklock);
00178
00179
00180 static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00181
00182 static int gtalk_sendtext(struct ast_channel *ast, const char *text);
00183 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
00184 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00185 static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout);
00186 static int gtalk_hangup(struct ast_channel *ast);
00187 static int gtalk_answer(struct ast_channel *ast);
00188 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);
00189 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);
00190 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
00191 static struct ast_frame *gtalk_read(struct ast_channel *ast);
00192 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
00193 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00194 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00195 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00196 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
00197 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p);
00198
00199 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00200 static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00201 static int gtalk_update_externip(void);
00202 static int gtalk_parser(void *data, ikspak *pak);
00203 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to);
00204
00205
00206 static struct ast_channel_tech gtalk_tech = {
00207 .type = "Gtalk",
00208 .description = "Gtalk Channel Driver",
00209 .requester = gtalk_request,
00210 .send_text = gtalk_sendtext,
00211 .send_digit_begin = gtalk_digit_begin,
00212 .send_digit_end = gtalk_digit_end,
00213
00214
00215
00216
00217 .call = gtalk_call,
00218 .hangup = gtalk_hangup,
00219 .answer = gtalk_answer,
00220 .read = gtalk_read,
00221 .write = gtalk_write,
00222 .exception = gtalk_read,
00223 .indicate = gtalk_indicate,
00224 .fixup = gtalk_fixup,
00225 .send_html = gtalk_sendhtml,
00226 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00227 };
00228
00229 static struct sockaddr_in bindaddr = { 0, };
00230
00231 static struct ast_sched_context *sched;
00232 static struct io_context *io;
00233 static struct in_addr __ourip;
00234
00235 static struct ast_cli_entry gtalk_cli[] = {
00236
00237 AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
00238 AST_CLI_DEFINE(gtalk_show_settings, "Show GoogleTalk global settings"),
00239 };
00240
00241 static char externip[16];
00242 static char global_context[AST_MAX_CONTEXT];
00243 static char global_parkinglot[AST_MAX_CONTEXT];
00244 static int global_allowguest;
00245 static struct sockaddr_in stunaddr;
00246 static int global_stunaddr;
00247
00248 static struct gtalk_container gtalk_list;
00249
00250 static void gtalk_member_destroy(struct gtalk *obj)
00251 {
00252 obj->cap = ast_format_cap_destroy(obj->cap);
00253 if (obj->connection) {
00254 ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
00255 }
00256 if (obj->buddy) {
00257 ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
00258 }
00259 ast_free(obj);
00260 }
00261
00262
00263
00264 static struct gtalk *find_gtalk(char *name, char *connection)
00265 {
00266 struct gtalk *gtalk = NULL;
00267 char *domain = NULL , *s = NULL;
00268
00269 if (strchr(connection, '@')) {
00270 s = ast_strdupa(connection);
00271 domain = strsep(&s, "@");
00272 ast_verbose("OOOOH domain = %s\n", domain);
00273 }
00274 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
00275 if (!gtalk && strchr(name, '@'))
00276 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
00277
00278 if (!gtalk) {
00279
00280 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
00281 ASTOBJ_RDLOCK(iterator);
00282 if (!strcasecmp(iterator->name, "guest")) {
00283 gtalk = iterator;
00284 }
00285 ASTOBJ_UNLOCK(iterator);
00286
00287 if (gtalk)
00288 break;
00289 });
00290
00291 }
00292 return gtalk;
00293 }
00294
00295
00296 static int add_codec_to_answer(const struct gtalk_pvt *p, struct ast_format *codec, iks *dcodecs)
00297 {
00298 int res = 0;
00299 const char *format = ast_getformatname(codec);
00300
00301 if (!strcasecmp("ulaw", format)) {
00302 iks *payload_eg711u, *payload_pcmu;
00303 payload_pcmu = iks_new("payload-type");
00304 payload_eg711u = iks_new("payload-type");
00305
00306 if(!payload_eg711u || !payload_pcmu) {
00307 iks_delete(payload_pcmu);
00308 iks_delete(payload_eg711u);
00309 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00310 return -1;
00311 }
00312 iks_insert_attrib(payload_pcmu, "id", "0");
00313 iks_insert_attrib(payload_pcmu, "name", "PCMU");
00314 iks_insert_attrib(payload_pcmu, "clockrate","8000");
00315 iks_insert_attrib(payload_pcmu, "bitrate","64000");
00316 iks_insert_attrib(payload_eg711u, "id", "100");
00317 iks_insert_attrib(payload_eg711u, "name", "EG711U");
00318 iks_insert_attrib(payload_eg711u, "clockrate","8000");
00319 iks_insert_attrib(payload_eg711u, "bitrate","64000");
00320 iks_insert_node(dcodecs, payload_pcmu);
00321 iks_insert_node(dcodecs, payload_eg711u);
00322 res ++;
00323 }
00324 if (!strcasecmp("alaw", format)) {
00325 iks *payload_eg711a, *payload_pcma;
00326 payload_pcma = iks_new("payload-type");
00327 payload_eg711a = iks_new("payload-type");
00328 if(!payload_eg711a || !payload_pcma) {
00329 iks_delete(payload_eg711a);
00330 iks_delete(payload_pcma);
00331 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00332 return -1;
00333 }
00334 iks_insert_attrib(payload_pcma, "id", "8");
00335 iks_insert_attrib(payload_pcma, "name", "PCMA");
00336 iks_insert_attrib(payload_pcma, "clockrate","8000");
00337 iks_insert_attrib(payload_pcma, "bitrate","64000");
00338 payload_eg711a = iks_new("payload-type");
00339 iks_insert_attrib(payload_eg711a, "id", "101");
00340 iks_insert_attrib(payload_eg711a, "name", "EG711A");
00341 iks_insert_attrib(payload_eg711a, "clockrate","8000");
00342 iks_insert_attrib(payload_eg711a, "bitrate","64000");
00343 iks_insert_node(dcodecs, payload_pcma);
00344 iks_insert_node(dcodecs, payload_eg711a);
00345 res ++;
00346 }
00347 if (!strcasecmp("ilbc", format)) {
00348 iks *payload_ilbc = iks_new("payload-type");
00349 if(!payload_ilbc) {
00350 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00351 return -1;
00352 }
00353 iks_insert_attrib(payload_ilbc, "id", "97");
00354 iks_insert_attrib(payload_ilbc, "name", "iLBC");
00355 iks_insert_attrib(payload_ilbc, "clockrate","8000");
00356 iks_insert_attrib(payload_ilbc, "bitrate","13300");
00357 iks_insert_node(dcodecs, payload_ilbc);
00358 res ++;
00359 }
00360 if (!strcasecmp("g723", format)) {
00361 iks *payload_g723 = iks_new("payload-type");
00362 if(!payload_g723) {
00363 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00364 return -1;
00365 }
00366 iks_insert_attrib(payload_g723, "id", "4");
00367 iks_insert_attrib(payload_g723, "name", "G723");
00368 iks_insert_attrib(payload_g723, "clockrate","8000");
00369 iks_insert_attrib(payload_g723, "bitrate","6300");
00370 iks_insert_node(dcodecs, payload_g723);
00371 res ++;
00372 }
00373 if (!strcasecmp("speex", format)) {
00374 iks *payload_speex = iks_new("payload-type");
00375 if(!payload_speex) {
00376 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00377 return -1;
00378 }
00379 iks_insert_attrib(payload_speex, "id", "110");
00380 iks_insert_attrib(payload_speex, "name", "speex");
00381 iks_insert_attrib(payload_speex, "clockrate","8000");
00382 iks_insert_attrib(payload_speex, "bitrate","11000");
00383 iks_insert_node(dcodecs, payload_speex);
00384 res++;
00385 }
00386 if (!strcasecmp("gsm", format)) {
00387 iks *payload_gsm = iks_new("payload-type");
00388 if(!payload_gsm) {
00389 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00390 return -1;
00391 }
00392 iks_insert_attrib(payload_gsm, "id", "103");
00393 iks_insert_attrib(payload_gsm, "name", "gsm");
00394 iks_insert_node(dcodecs, payload_gsm);
00395 res++;
00396 }
00397
00398 return res;
00399 }
00400
00401 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
00402 {
00403 struct gtalk *client = p->parent;
00404 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00405 int x;
00406 struct ast_format_cap *alreadysent;
00407 int codecs_num = 0;
00408 char *lowerto = NULL;
00409 struct ast_format tmpfmt;
00410
00411 iq = iks_new("iq");
00412 gtalk = iks_new("session");
00413 dcodecs = iks_new("description");
00414 transport = iks_new("transport");
00415 payload_telephone = iks_new("payload-type");
00416 if (!(iq && gtalk && dcodecs && transport && payload_telephone)) {
00417 iks_delete(iq);
00418 iks_delete(gtalk);
00419 iks_delete(dcodecs);
00420 iks_delete(transport);
00421 iks_delete(payload_telephone);
00422
00423 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00424 return 0;
00425 }
00426 iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
00427 iks_insert_attrib(dcodecs, "xml:lang", "en");
00428
00429 if (!(alreadysent = ast_format_cap_alloc_nolock())) {
00430 return 0;
00431 }
00432 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00433 if (!(ast_codec_pref_index(&client->prefs, x, &tmpfmt))) {
00434 break;
00435 }
00436 if (!(ast_format_cap_iscompatible(client->cap, &tmpfmt))) {
00437 continue;
00438 }
00439 if (ast_format_cap_iscompatible(alreadysent, &tmpfmt)) {
00440 continue;
00441 }
00442 codecs_num = add_codec_to_answer(p, &tmpfmt, dcodecs);
00443 ast_format_cap_add(alreadysent, &tmpfmt);
00444 }
00445 alreadysent = ast_format_cap_destroy(alreadysent);
00446
00447 if (codecs_num) {
00448
00449 iks_insert_attrib(payload_telephone, "id", "101");
00450 iks_insert_attrib(payload_telephone, "name", "telephone-event");
00451 iks_insert_attrib(payload_telephone, "clockrate", "8000");
00452 }
00453 iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
00454
00455 iks_insert_attrib(iq, "type", "set");
00456 iks_insert_attrib(iq, "to", to);
00457 iks_insert_attrib(iq, "from", from);
00458 iks_insert_attrib(iq, "id", client->connection->mid);
00459 ast_aji_increment_mid(client->connection->mid);
00460
00461 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00462 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00463
00464
00465 if (!initiator) {
00466 char c;
00467 char *t = lowerto = ast_strdupa(to);
00468 while (((c = *t) != '/') && (*t++ = tolower(c)));
00469 }
00470 iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
00471 iks_insert_attrib(gtalk, "id", sid);
00472 iks_insert_node(iq, gtalk);
00473 iks_insert_node(gtalk, dcodecs);
00474 iks_insert_node(dcodecs, payload_telephone);
00475
00476 ast_aji_send(client->connection, iq);
00477
00478 iks_delete(payload_telephone);
00479 iks_delete(transport);
00480 iks_delete(dcodecs);
00481 iks_delete(gtalk);
00482 iks_delete(iq);
00483 return 1;
00484 }
00485
00486 static int gtalk_ringing_ack(void *data, ikspak *pak)
00487 {
00488 struct gtalk_pvt *p = data;
00489 struct ast_channel *owner;
00490
00491 ast_mutex_lock(&p->lock);
00492
00493 if (p->ringrule) {
00494 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00495 }
00496 p->ringrule = NULL;
00497
00498
00499 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
00500 char *name = NULL;
00501 char *redirect = NULL;
00502 iks *traversenodes = NULL;
00503 traversenodes = pak->query;
00504 while (traversenodes) {
00505 if (!(name = iks_name(traversenodes))) {
00506 break;
00507 }
00508 if (!strcasecmp(name, "error") &&
00509 ((redirect = iks_find_cdata(traversenodes, "redirect")) ||
00510 (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
00511 (redirect = strstr(redirect, "xmpp:"))) {
00512 redirect += 5;
00513 ast_debug(1, "redirect %s\n", redirect);
00514 ast_copy_string(p->them, redirect, sizeof(p->them));
00515
00516 gtalk_invite(p, p->them, p->us, p->sid, 1);
00517 break;
00518 }
00519 traversenodes = iks_next_tag(traversenodes);
00520 }
00521 }
00522 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
00523 owner = p->owner;
00524 ast_mutex_unlock(&p->lock);
00525
00526 if (owner) {
00527 ast_queue_control(owner, AST_CONTROL_RINGING);
00528 }
00529
00530 return IKS_FILTER_EAT;
00531 }
00532
00533 static int gtalk_answer(struct ast_channel *ast)
00534 {
00535 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
00536 int res = 0;
00537
00538 ast_debug(1, "Answer!\n");
00539 ast_mutex_lock(&p->lock);
00540 gtalk_invite(p, p->them, p->us,p->sid, 0);
00541 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
00542 ast_channel_name(ast), "GTALK", p->sid);
00543 ast_mutex_unlock(&p->lock);
00544 return res;
00545 }
00546
00547 static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
00548 {
00549 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
00550 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
00551
00552 if (!p)
00553 return res;
00554
00555 ast_mutex_lock(&p->lock);
00556 if (p->rtp){
00557 ao2_ref(p->rtp, +1);
00558 *instance = p->rtp;
00559 res = AST_RTP_GLUE_RESULT_LOCAL;
00560 }
00561 ast_mutex_unlock(&p->lock);
00562
00563 return res;
00564 }
00565
00566 static void gtalk_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
00567 {
00568 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
00569 ast_mutex_lock(&p->lock);
00570 ast_format_cap_copy(result, p->peercap);
00571 ast_mutex_unlock(&p->lock);
00572 }
00573
00574 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *cap, int nat_active)
00575 {
00576 struct gtalk_pvt *p;
00577
00578 p = ast_channel_tech_pvt(chan);
00579 if (!p)
00580 return -1;
00581 ast_mutex_lock(&p->lock);
00582
00583
00584
00585
00586
00587
00588
00589
00590 ast_mutex_unlock(&p->lock);
00591 return 0;
00592 }
00593
00594 static struct ast_rtp_glue gtalk_rtp_glue = {
00595 .type = "Gtalk",
00596 .get_rtp_info = gtalk_get_rtp_peer,
00597 .get_codec = gtalk_get_codec,
00598 .update_peer = gtalk_set_rtp_peer,
00599 };
00600
00601 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
00602 {
00603 iks *response = NULL, *error = NULL, *reason = NULL;
00604 int res = -1;
00605
00606 response = iks_new("iq");
00607 if (response) {
00608 iks_insert_attrib(response, "type", "result");
00609 iks_insert_attrib(response, "from", from);
00610 iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
00611 iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
00612 if (reasonstr) {
00613 error = iks_new("error");
00614 if (error) {
00615 iks_insert_attrib(error, "type", "cancel");
00616 reason = iks_new(reasonstr);
00617 if (reason)
00618 iks_insert_node(error, reason);
00619 iks_insert_node(response, error);
00620 }
00621 }
00622 ast_aji_send(client->connection, response);
00623 res = 0;
00624 }
00625
00626 iks_delete(reason);
00627 iks_delete(error);
00628 iks_delete(response);
00629
00630 return res;
00631 }
00632
00633 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
00634 {
00635 struct gtalk_pvt *tmp = NULL;
00636 char *from;
00637 iks *codec;
00638 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00639 int peernoncodeccapability;
00640
00641 ast_debug(1, "The client is %s\n", client->name);
00642
00643
00644 for (tmp = client->p; tmp; tmp = tmp->next) {
00645 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00646 break;
00647 } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
00648 break;
00649 }
00650 }
00651
00652 if (!tmp) {
00653 ast_log(LOG_WARNING, "Could not find session in iq\n");
00654 return -1;
00655 }
00656
00657
00658 codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00659 while (codec) {
00660 char *codec_id = iks_find_attrib(codec, "id");
00661 char *codec_name = iks_find_attrib(codec, "name");
00662 if (!codec_id || !codec_name) {
00663 codec = iks_next_tag(codec);
00664 continue;
00665 }
00666
00667 ast_rtp_codecs_payloads_set_m_type(
00668 ast_rtp_instance_get_codecs(tmp->rtp),
00669 tmp->rtp,
00670 atoi(codec_id));
00671 ast_rtp_codecs_payloads_set_rtpmap_type(
00672 ast_rtp_instance_get_codecs(tmp->rtp),
00673 tmp->rtp,
00674 atoi(codec_id),
00675 "audio",
00676 codec_name,
00677 0);
00678 codec = iks_next_tag(codec);
00679 }
00680
00681
00682 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), tmp->peercap, &peernoncodeccapability);
00683
00684
00685
00686 ast_format_cap_joint_copy(tmp->cap, tmp->peercap, tmp->jointcap);
00687 if (ast_format_cap_is_empty(tmp->jointcap)) {
00688 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->cap),
00689 ast_getformatname_multiple(s2, BUFSIZ, tmp->peercap),
00690 ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcap));
00691
00692 ast_queue_hangup(tmp->owner);
00693
00694 return -1;
00695
00696 }
00697
00698 from = iks_find_attrib(pak->x, "to");
00699 if (!from) {
00700 from = client->connection->jid->full;
00701 }
00702
00703 if (tmp->owner) {
00704 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00705 }
00706 gtalk_update_stun(tmp->parent, tmp);
00707 gtalk_response(client, from, pak, NULL, NULL);
00708 return 1;
00709 }
00710
00711 static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
00712 {
00713 struct gtalk_pvt *tmp;
00714 char *from;
00715
00716 ast_debug(1, "The client is %s\n", client->name);
00717
00718 for (tmp = client->p; tmp; tmp = tmp->next) {
00719 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00720 break;
00721 }
00722 }
00723
00724 from = iks_find_attrib(pak->x, "to");
00725 if (!from) {
00726 from = client->connection->jid->full;
00727 }
00728
00729 if (tmp) {
00730 gtalk_update_stun(tmp->parent, tmp);
00731 } else {
00732 ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
00733 }
00734
00735
00736 gtalk_response(client, from, pak, NULL, NULL);
00737 return 1;
00738 }
00739
00740 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
00741 {
00742 struct gtalk_pvt *tmp;
00743 iks *dtmfnode = NULL, *dtmfchild = NULL;
00744 char *dtmf;
00745 char *from;
00746
00747 for (tmp = client->p; tmp; tmp = tmp->next) {
00748 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00749 break;
00750 }
00751 from = iks_find_attrib(pak->x, "to");
00752 if (!from) {
00753 from = client->connection->jid->full;
00754 }
00755
00756 if (tmp) {
00757 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00758 gtalk_response(client, from, pak,
00759 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00760 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00761 return -1;
00762 }
00763 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00764 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00765 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00766 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00767 f.subclass.integer = dtmf[0];
00768 ast_queue_frame(tmp->owner, &f);
00769 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00770 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00771 struct ast_frame f = {AST_FRAME_DTMF_END, };
00772 f.subclass.integer = dtmf[0];
00773 ast_queue_frame(tmp->owner, &f);
00774 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00775 } else if(iks_find_attrib(pak->x, "dtmf")) {
00776 struct ast_frame f = {AST_FRAME_DTMF, };
00777 f.subclass.integer = dtmf[0];
00778 ast_queue_frame(tmp->owner, &f);
00779 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00780 }
00781 }
00782 } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00783 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00784 if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00785 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00786 struct ast_frame f = {AST_FRAME_DTMF_END, };
00787 f.subclass.integer = dtmf[0];
00788 ast_queue_frame(tmp->owner, &f);
00789 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00790 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00791 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00792 f.subclass.integer = dtmf[0];
00793 ast_queue_frame(tmp->owner, &f);
00794 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00795 }
00796 }
00797 }
00798 }
00799 gtalk_response(client, from, pak, NULL, NULL);
00800 return 1;
00801 } else {
00802 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00803 }
00804
00805 gtalk_response(client, from, pak, NULL, NULL);
00806 return 1;
00807 }
00808
00809 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
00810 {
00811 struct gtalk_pvt *tmp;
00812 char *from;
00813
00814 ast_debug(1, "The client is %s\n", client->name);
00815
00816 for (tmp = client->p; tmp; tmp = tmp->next) {
00817 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
00818 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
00819 break;
00820 }
00821 }
00822 from = iks_find_attrib(pak->x, "to");
00823 if (!from) {
00824 from = client->connection->jid->full;
00825 }
00826
00827 if (tmp) {
00828 tmp->alreadygone = 1;
00829 if (tmp->owner) {
00830 ast_queue_hangup(tmp->owner);
00831 }
00832 } else {
00833 ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
00834 }
00835 gtalk_response(client, from, pak, NULL, NULL);
00836 return 1;
00837 }
00838
00839 static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
00840 {
00841 struct ast_sockaddr root;
00842 struct ast_sockaddr bindaddr_tmp;
00843 struct ast_sockaddr *addrs;
00844
00845
00846 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
00847 if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
00848 ast_sockaddr_copy(ourip, &bindaddr_tmp);
00849 return 0;
00850 }
00851
00852
00853
00854 if (ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET) > 0) {
00855 ast_sockaddr_copy(&root, &addrs[0]);
00856 ast_free(addrs);
00857 if (!ast_ouraddrfor(&root, ourip)) {
00858 return 0;
00859 }
00860 }
00861
00862
00863 return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
00864 }
00865
00866 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
00867 {
00868 struct gtalk_candidate *tmp;
00869 struct aji_client *c = client->connection;
00870 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00871 struct sockaddr_in sin = { 0, };
00872 struct ast_sockaddr sin_tmp;
00873 struct ast_sockaddr us;
00874 iks *iq, *gtalk, *candidate, *transport;
00875 char user[17], pass[17], preference[5], port[7];
00876 char *lowerfrom = NULL;
00877
00878 iq = iks_new("iq");
00879 gtalk = iks_new("session");
00880 candidate = iks_new("candidate");
00881 transport = iks_new("transport");
00882 if (!iq || !gtalk || !candidate || !transport) {
00883 ast_log(LOG_ERROR, "Memory allocation error\n");
00884 goto safeout;
00885 }
00886 ours1 = ast_calloc(1, sizeof(*ours1));
00887 ours2 = ast_calloc(1, sizeof(*ours2));
00888 if (!ours1 || !ours2)
00889 goto safeout;
00890
00891 iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
00892 iks_insert_node(iq, gtalk);
00893 iks_insert_node(gtalk,candidate);
00894 iks_insert_node(gtalk,transport);
00895
00896 for (; p; p = p->next) {
00897 if (!strcasecmp(p->sid, sid))
00898 break;
00899 }
00900
00901 if (!p) {
00902 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00903 goto safeout;
00904 }
00905
00906 ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
00907 ast_sockaddr_to_sin(&sin_tmp, &sin);
00908
00909 gtalk_get_local_ip(&us);
00910
00911 if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
00912 ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.\n");
00913 }
00914
00915
00916 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00917 ours1->port = ntohs(sin.sin_port);
00918 ours1->preference = 1;
00919 snprintf(user, sizeof(user), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
00920 snprintf(pass, sizeof(pass), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
00921 ast_copy_string(ours1->username, user, sizeof(ours1->username));
00922 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00923 ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
00924 sizeof(ours1->ip));
00925 ours1->protocol = AJI_PROTOCOL_UDP;
00926 ours1->type = AJI_CONNECT_LOCAL;
00927 ours1->generation = 0;
00928 p->ourcandidates = ours1;
00929
00930
00931
00932
00933 gtalk_update_externip();
00934 if (!ast_strlen_zero(externip)) {
00935 ast_copy_string(ours2->username, user, sizeof(ours2->username));
00936 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00937 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00938 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00939 ours2->port = ntohs(sin.sin_port);
00940 ours2->preference = 0.9;
00941 ours2->protocol = AJI_PROTOCOL_UDP;
00942 ours2->type = AJI_CONNECT_STUN;
00943 ours2->generation = 0;
00944 ours1->next = ours2;
00945 ours2 = NULL;
00946 }
00947 ours1 = NULL;
00948
00949 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00950 snprintf(port, sizeof(port), "%d", tmp->port);
00951 snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00952 iks_insert_attrib(iq, "from", to);
00953 iks_insert_attrib(iq, "to", from);
00954 iks_insert_attrib(iq, "type", "set");
00955 iks_insert_attrib(iq, "id", c->mid);
00956 ast_aji_increment_mid(c->mid);
00957 iks_insert_attrib(gtalk, "type", "candidates");
00958 iks_insert_attrib(gtalk, "id", sid);
00959
00960
00961 if (!p->initiator) {
00962 char cur;
00963 char *t = lowerfrom = ast_strdupa(from);
00964 while (((cur = *t) != '/') && (*t++ = tolower(cur)));
00965 }
00966 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
00967 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00968 iks_insert_attrib(candidate, "name", tmp->name);
00969 iks_insert_attrib(candidate, "address", tmp->ip);
00970 iks_insert_attrib(candidate, "port", port);
00971 iks_insert_attrib(candidate, "username", tmp->username);
00972 iks_insert_attrib(candidate, "password", tmp->password);
00973 iks_insert_attrib(candidate, "preference", preference);
00974 if (tmp->protocol == AJI_PROTOCOL_UDP)
00975 iks_insert_attrib(candidate, "protocol", "udp");
00976 if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00977 iks_insert_attrib(candidate, "protocol", "ssltcp");
00978 if (tmp->type == AJI_CONNECT_STUN)
00979 iks_insert_attrib(candidate, "type", "stun");
00980 if (tmp->type == AJI_CONNECT_LOCAL)
00981 iks_insert_attrib(candidate, "type", "local");
00982 if (tmp->type == AJI_CONNECT_RELAY)
00983 iks_insert_attrib(candidate, "type", "relay");
00984 iks_insert_attrib(candidate, "network", "0");
00985 iks_insert_attrib(candidate, "generation", "0");
00986 ast_aji_send(c, iq);
00987 }
00988 p->laststun = 0;
00989
00990 safeout:
00991 if (ours1)
00992 ast_free(ours1);
00993 if (ours2)
00994 ast_free(ours2);
00995 iks_delete(iq);
00996 iks_delete(gtalk);
00997 iks_delete(candidate);
00998 iks_delete(transport);
00999
01000 return 1;
01001 }
01002
01003 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
01004 {
01005 struct gtalk_pvt *tmp = NULL;
01006 struct aji_resource *resources = NULL;
01007 struct aji_buddy *buddy = NULL;
01008 char idroster[200] = "";
01009 char *data, *exten = NULL;
01010 struct ast_sockaddr bindaddr_tmp;
01011
01012 ast_debug(1, "The client is %s for alloc\n", client->name);
01013 if (!sid && !strchr(them, '/')) {
01014 if (!strcasecmp(client->name, "guest")) {
01015 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
01016 if (buddy) {
01017 resources = buddy->resources;
01018 }
01019 } else if (client->buddy) {
01020 resources = client->buddy->resources;
01021 }
01022
01023 while (resources) {
01024 if (resources->cap->jingle) {
01025 break;
01026 }
01027 resources = resources->next;
01028 }
01029 if (resources) {
01030 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
01031 } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
01032 snprintf(idroster, sizeof(idroster), "%s", them);
01033 } else {
01034 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
01035 if (buddy) {
01036 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01037 }
01038 return NULL;
01039 }
01040 if (buddy) {
01041 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01042 }
01043 }
01044 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
01045 return NULL;
01046 }
01047 tmp->cap = ast_format_cap_alloc_nolock();
01048 tmp->jointcap = ast_format_cap_alloc_nolock();
01049 tmp->peercap = ast_format_cap_alloc_nolock();
01050 if (!tmp->jointcap || !tmp->peercap || !tmp->cap) {
01051 tmp->cap = ast_format_cap_destroy(tmp->cap);
01052 tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
01053 tmp->peercap = ast_format_cap_destroy(tmp->peercap);
01054 ast_free(tmp);
01055 return NULL;
01056 }
01057
01058 memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
01059
01060 if (sid) {
01061 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
01062 ast_copy_string(tmp->them, them, sizeof(tmp->them));
01063 ast_copy_string(tmp->us, us, sizeof(tmp->us));
01064 } else {
01065 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
01066 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
01067 ast_copy_string(tmp->us, us, sizeof(tmp->us));
01068 tmp->initiator = 1;
01069 }
01070
01071 bindaddr.sin_family = AF_INET;
01072 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
01073 if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
01074 ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
01075 ast_free(tmp);
01076 return NULL;
01077 }
01078 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
01079 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
01080 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
01081 ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
01082 ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
01083
01084
01085 if (!(ast_format_cap_is_empty(client->cap))) {
01086 ast_format_cap_copy(tmp->cap, client->cap);
01087 } else if (!(ast_format_cap_is_empty(global_capability))) {
01088 ast_format_cap_copy(tmp->cap, global_capability);
01089 }
01090
01091 tmp->parent = client;
01092 if (!tmp->rtp) {
01093 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
01094 ast_free(tmp);
01095 return NULL;
01096 }
01097
01098
01099 ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
01100
01101 if(strchr(tmp->us, '/')) {
01102 data = ast_strdupa(tmp->us);
01103 exten = strsep(&data, "/");
01104 } else {
01105 exten = tmp->us;
01106 }
01107 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
01108 ast_mutex_init(&tmp->lock);
01109 ast_mutex_lock(>alklock);
01110 tmp->next = client->p;
01111 client->p = tmp;
01112 ast_mutex_unlock(>alklock);
01113 return tmp;
01114 }
01115
01116
01117 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
01118 {
01119 struct ast_channel *tmp;
01120 const char *n2;
01121 struct ast_format_cap *what;
01122 struct ast_format tmpfmt;
01123
01124 if (title)
01125 n2 = title;
01126 else
01127 n2 = i->us;
01128 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid,
01129 client->accountcode, i->exten, client->context, client->amaflags,
01130 "Gtalk/%s-%04lx", n2, (long unsigned)(ast_random() & 0xffff));
01131 if (!tmp) {
01132 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01133 return NULL;
01134 }
01135 ast_channel_tech_set(tmp, >alk_tech);
01136
01137
01138
01139 if (!(ast_format_cap_is_empty(i->jointcap))) {
01140 what = i->jointcap;
01141 } else if (i->cap) {
01142 what = i->cap;
01143 } else {
01144 what = global_capability;
01145 }
01146
01147
01148 if (i->rtp) {
01149 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
01150 }
01151
01152 ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
01153 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
01154
01155 ast_format_cap_iter_start(i->jointcap);
01156 while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
01157 if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
01158 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
01159 }
01160 }
01161 ast_format_cap_iter_end(i->jointcap);
01162
01163 if (i->rtp) {
01164 ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
01165 ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
01166 }
01167 if (i->vrtp) {
01168 ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
01169 ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
01170 }
01171 if (state == AST_STATE_RING)
01172 ast_channel_rings_set(tmp, 1);
01173 ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
01174
01175 ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
01176 ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
01177 ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
01178 ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
01179 ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
01180 ast_channel_tech_pvt_set(tmp, i);
01181
01182 ast_channel_callgroup_set(tmp, client->callgroup);
01183 ast_channel_pickupgroup_set(tmp, client->pickupgroup);
01184 ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
01185 ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
01186 if (!ast_strlen_zero(client->accountcode))
01187 ast_channel_accountcode_set(tmp, client->accountcode);
01188 if (client->amaflags)
01189 ast_channel_amaflags_set(tmp, client->amaflags);
01190 if (!ast_strlen_zero(client->language))
01191 ast_channel_language_set(tmp, client->language);
01192 if (!ast_strlen_zero(client->musicclass))
01193 ast_channel_musicclass_set(tmp, client->musicclass);
01194 if (!ast_strlen_zero(client->parkinglot))
01195 ast_channel_parkinglot_set(tmp, client->parkinglot);
01196 i->owner = tmp;
01197 ast_module_ref(ast_module_info->self);
01198 ast_channel_context_set(tmp, client->context);
01199 ast_channel_exten_set(tmp, i->exten);
01200
01201 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
01202 ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
01203 }
01204 ast_channel_priority_set(tmp, 1);
01205 if (i->rtp)
01206 ast_jb_configure(tmp, &global_jbconf);
01207 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01208 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
01209 ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
01210 ast_hangup(tmp);
01211 tmp = NULL;
01212 } else {
01213 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01214 "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01215 i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
01216 }
01217 return tmp;
01218 }
01219
01220 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
01221 {
01222 iks *request, *session = NULL;
01223 int res = -1;
01224 char *lowerthem = NULL;
01225
01226 request = iks_new("iq");
01227 if (request) {
01228 iks_insert_attrib(request, "type", "set");
01229 iks_insert_attrib(request, "from", p->us);
01230 iks_insert_attrib(request, "to", p->them);
01231 iks_insert_attrib(request, "id", client->connection->mid);
01232 ast_aji_increment_mid(client->connection->mid);
01233 session = iks_new("session");
01234 if (session) {
01235 iks_insert_attrib(session, "type", action);
01236 iks_insert_attrib(session, "id", p->sid);
01237
01238
01239 if (!p->initiator) {
01240 char c;
01241 char *t = lowerthem = ast_strdupa(p->them);
01242 while (((c = *t) != '/') && (*t++ = tolower(c)));
01243 }
01244 iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01245 iks_insert_attrib(session, "xmlns", GOOGLE_NS);
01246 iks_insert_node(request, session);
01247 ast_aji_send(client->connection, request);
01248 res = 0;
01249 }
01250 }
01251
01252 iks_delete(session);
01253 iks_delete(request);
01254
01255 return res;
01256 }
01257
01258 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
01259 {
01260 struct gtalk_candidate *last;
01261 while (candidate) {
01262 last = candidate;
01263 candidate = candidate->next;
01264 ast_free(last);
01265 }
01266 }
01267
01268 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
01269 {
01270 struct gtalk_pvt *cur, *prev = NULL;
01271 cur = client->p;
01272 while (cur) {
01273 if (cur == p) {
01274 if (prev)
01275 prev->next = p->next;
01276 else
01277 client->p = p->next;
01278 break;
01279 }
01280 prev = cur;
01281 cur = cur->next;
01282 }
01283 if (p->ringrule)
01284 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01285 if (p->owner)
01286 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01287 if (p->rtp)
01288 ast_rtp_instance_destroy(p->rtp);
01289 if (p->vrtp)
01290 ast_rtp_instance_destroy(p->vrtp);
01291 gtalk_free_candidates(p->theircandidates);
01292 p->cap = ast_format_cap_destroy(p->cap);
01293 p->jointcap = ast_format_cap_destroy(p->jointcap);
01294 p->peercap = ast_format_cap_destroy(p->peercap);
01295 ast_free(p);
01296 }
01297
01298
01299 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
01300 {
01301 struct gtalk_pvt *p, *tmp = client->p;
01302 struct ast_channel *chan;
01303 int res;
01304 iks *codec;
01305 char *from = NULL;
01306 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01307 int peernoncodeccapability;
01308 char *sid;
01309
01310
01311 from = iks_find_attrib(pak->x,"to");
01312 if (!from) {
01313 from = client->connection->jid->full;
01314 }
01315
01316 while (tmp) {
01317 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01318 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01319 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01320 gtalk_response(client, from, pak, "out-of-order", NULL);
01321 return -1;
01322 }
01323 tmp = tmp->next;
01324 }
01325
01326 if (!strcasecmp(client->name, "guest")){
01327
01328
01329 if (client->connection) {
01330 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01331 }
01332 client->connection = ast_aji_get_client(from);
01333 if (!client->connection) {
01334 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01335 return -1;
01336 }
01337 }
01338
01339 if (!(sid = iks_find_attrib(pak->query, "id"))) {
01340 ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
01341 return -1;
01342 }
01343
01344 p = gtalk_alloc(client, from, pak->from->full, sid);
01345 if (!p) {
01346 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01347 return -1;
01348 }
01349
01350 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
01351 if (!chan) {
01352 gtalk_free_pvt(client, p);
01353 return -1;
01354 }
01355
01356 ast_mutex_lock(&p->lock);
01357 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01358 ast_copy_string(p->sid, sid, sizeof(p->sid));
01359
01360
01361 codec = iks_first_tag(iks_first_tag(pak->query));
01362
01363 while (codec) {
01364 char *codec_id = iks_find_attrib(codec, "id");
01365 char *codec_name = iks_find_attrib(codec, "name");
01366 if (!codec_id || !codec_name) {
01367 codec = iks_next_tag(codec);
01368 continue;
01369 }
01370 if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
01371 ast_rtp_codecs_payloads_set_m_type(
01372 ast_rtp_instance_get_codecs(p->vrtp),
01373 p->vrtp,
01374 atoi(codec_id));
01375 ast_rtp_codecs_payloads_set_rtpmap_type(
01376 ast_rtp_instance_get_codecs(p->vrtp),
01377 p->vrtp,
01378 atoi(codec_id),
01379 "video",
01380 codec_name,
01381 0);
01382 } else {
01383 ast_rtp_codecs_payloads_set_m_type(
01384 ast_rtp_instance_get_codecs(p->rtp),
01385 p->rtp,
01386 atoi(codec_id));
01387 ast_rtp_codecs_payloads_set_rtpmap_type(
01388 ast_rtp_instance_get_codecs(p->rtp),
01389 p->rtp,
01390 atoi(codec_id),
01391 "audio",
01392 codec_name,
01393 0);
01394 }
01395 codec = iks_next_tag(codec);
01396 }
01397
01398
01399 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), p->peercap, &peernoncodeccapability);
01400 ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap);
01401 ast_mutex_unlock(&p->lock);
01402
01403 ast_setstate(chan, AST_STATE_RING);
01404 if (ast_format_cap_is_empty(p->jointcap)) {
01405 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap),
01406 ast_getformatname_multiple(s2, BUFSIZ, p->peercap),
01407 ast_getformatname_multiple(s3, BUFSIZ, p->jointcap));
01408
01409 gtalk_action(client, p, "reject");
01410 p->alreadygone = 1;
01411 gtalk_hangup(chan);
01412 ast_channel_release(chan);
01413 return -1;
01414 }
01415
01416 res = ast_pbx_start(chan);
01417
01418 switch (res) {
01419 case AST_PBX_FAILED:
01420 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01421 gtalk_response(client, from, pak, "service-unavailable", NULL);
01422 break;
01423 case AST_PBX_CALL_LIMIT:
01424 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01425 gtalk_response(client, from, pak, "service-unavailable", NULL);
01426 break;
01427 case AST_PBX_SUCCESS:
01428 gtalk_response(client, from, pak, NULL, NULL);
01429 gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01430
01431 break;
01432 }
01433
01434 return 1;
01435 }
01436
01437 static int gtalk_update_externip(void)
01438 {
01439 int sock;
01440 char *newaddr;
01441 struct sockaddr_in answer = { 0, };
01442 struct sockaddr_in *dst;
01443 struct ast_sockaddr tmp_dst;
01444
01445 if (!stunaddr.sin_addr.s_addr) {
01446 return -1;
01447 }
01448 dst = &stunaddr;
01449
01450 sock = socket(AF_INET, SOCK_DGRAM, 0);
01451 if (sock < 0) {
01452 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
01453 return -1;
01454 }
01455
01456 ast_sockaddr_from_sin(&tmp_dst, dst);
01457 if (ast_connect(sock, &tmp_dst) != 0) {
01458 ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
01459 close(sock);
01460 return -1;
01461 }
01462
01463 if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
01464 close(sock);
01465 return -1;
01466 }
01467
01468 newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
01469 memcpy(externip, newaddr, sizeof(externip));
01470
01471 close(sock);
01472 return 0;
01473
01474 }
01475
01476 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
01477 {
01478 struct gtalk_candidate *tmp;
01479 struct hostent *hp;
01480 struct ast_hostent ahp;
01481 struct sockaddr_in sin = { 0, };
01482 struct sockaddr_in aux = { 0, };
01483 struct ast_sockaddr sin_tmp;
01484 struct ast_sockaddr aux_tmp;
01485
01486 if (time(NULL) == p->laststun)
01487 return 0;
01488
01489 tmp = p->theircandidates;
01490 p->laststun = time(NULL);
01491 while (tmp) {
01492 char username[256];
01493
01494
01495 if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
01496 ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
01497 tmp = tmp->next;
01498 continue;
01499 }
01500 sin.sin_family = AF_INET;
01501 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01502 sin.sin_port = htons(tmp->port);
01503 snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
01504
01505
01506 ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
01507 ast_sockaddr_to_sin(&aux_tmp, &aux);
01508
01509
01510
01511
01512 if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
01513 ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
01514 } else {
01515 ast_sockaddr_from_sin(&sin_tmp, &sin);
01516 ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
01517 }
01518 if (aux.sin_addr.s_addr) {
01519 ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01520 ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01521 }
01522
01523 tmp = tmp->next;
01524 }
01525 return 1;
01526 }
01527
01528 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
01529 {
01530 struct gtalk_pvt *p = NULL, *tmp = NULL;
01531 struct aji_client *c = client->connection;
01532 struct gtalk_candidate *newcandidate = NULL;
01533 iks *traversenodes = NULL, *receipt = NULL;
01534 char *from;
01535
01536 from = iks_find_attrib(pak->x,"to");
01537 if (!from) {
01538 from = c->jid->full;
01539 }
01540
01541 for (tmp = client->p; tmp; tmp = tmp->next) {
01542 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01543 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01544 p = tmp;
01545 break;
01546 }
01547 }
01548
01549 if (!p) {
01550 return -1;
01551 }
01552 traversenodes = pak->query;
01553 while(traversenodes) {
01554 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
01555 traversenodes = iks_first_tag(traversenodes);
01556 continue;
01557 }
01558 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
01559 traversenodes = iks_child(traversenodes);
01560 continue;
01561 }
01562 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
01563 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01564 if (!newcandidate)
01565 return 0;
01566 ast_copy_string(newcandidate->name,
01567 S_OR(iks_find_attrib(traversenodes, "name"), ""),
01568 sizeof(newcandidate->name));
01569 ast_copy_string(newcandidate->ip,
01570 S_OR(iks_find_attrib(traversenodes, "address"), ""),
01571 sizeof(newcandidate->ip));
01572 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01573 ast_copy_string(newcandidate->username,
01574 S_OR(iks_find_attrib(traversenodes, "username"), ""),
01575 sizeof(newcandidate->username));
01576 ast_copy_string(newcandidate->password,
01577 S_OR(iks_find_attrib(traversenodes, "password"), ""),
01578 sizeof(newcandidate->password));
01579 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01580 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
01581 newcandidate->protocol = AJI_PROTOCOL_UDP;
01582 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
01583 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01584
01585 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
01586 newcandidate->type = AJI_CONNECT_STUN;
01587 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
01588 newcandidate->type = AJI_CONNECT_LOCAL;
01589 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
01590 newcandidate->type = AJI_CONNECT_RELAY;
01591 ast_copy_string(newcandidate->network,
01592 S_OR(iks_find_attrib(traversenodes, "network"), ""),
01593 sizeof(newcandidate->network));
01594 newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
01595 newcandidate->next = NULL;
01596
01597 newcandidate->next = p->theircandidates;
01598 p->theircandidates = newcandidate;
01599 p->laststun = 0;
01600 gtalk_update_stun(p->parent, p);
01601 newcandidate = NULL;
01602 }
01603 traversenodes = iks_next_tag(traversenodes);
01604 }
01605
01606 receipt = iks_new("iq");
01607 iks_insert_attrib(receipt, "type", "result");
01608 iks_insert_attrib(receipt, "from", from);
01609 iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
01610 iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
01611 ast_aji_send(c, receipt);
01612
01613 iks_delete(receipt);
01614
01615 return 1;
01616 }
01617
01618 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
01619 {
01620 struct ast_frame *f;
01621
01622 if (!p->rtp) {
01623 return &ast_null_frame;
01624 }
01625 f = ast_rtp_instance_read(p->rtp, 0);
01626 gtalk_update_stun(p->parent, p);
01627 if (p->owner) {
01628
01629 if (f->frametype == AST_FRAME_VOICE) {
01630 if (!ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) {
01631 ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
01632 ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
01633 ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
01634 ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
01635 ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
01636 }
01637
01638
01639
01640
01641
01642 }
01643 }
01644 return f;
01645 }
01646
01647 static struct ast_frame *gtalk_read(struct ast_channel *ast)
01648 {
01649 struct ast_frame *fr;
01650 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01651
01652 ast_mutex_lock(&p->lock);
01653 fr = gtalk_rtp_read(ast, p);
01654 ast_mutex_unlock(&p->lock);
01655 return fr;
01656 }
01657
01658
01659 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
01660 {
01661 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01662 int res = 0;
01663 char buf[256];
01664
01665 switch (frame->frametype) {
01666 case AST_FRAME_VOICE:
01667 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
01668 ast_log(LOG_WARNING,
01669 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01670 ast_getformatname(&frame->subclass.format),
01671 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
01672 ast_getformatname(ast_channel_readformat(ast)),
01673 ast_getformatname(ast_channel_writeformat(ast)));
01674 return 0;
01675 }
01676 if (p) {
01677 ast_mutex_lock(&p->lock);
01678 if (p->rtp) {
01679 res = ast_rtp_instance_write(p->rtp, frame);
01680 }
01681 ast_mutex_unlock(&p->lock);
01682 }
01683 break;
01684 case AST_FRAME_VIDEO:
01685 if (p) {
01686 ast_mutex_lock(&p->lock);
01687 if (p->vrtp) {
01688 res = ast_rtp_instance_write(p->vrtp, frame);
01689 }
01690 ast_mutex_unlock(&p->lock);
01691 }
01692 break;
01693 case AST_FRAME_IMAGE:
01694 return 0;
01695 break;
01696 default:
01697 ast_log(LOG_WARNING, "Can't send %u type frames with Gtalk write\n",
01698 frame->frametype);
01699 return 0;
01700 }
01701
01702 return res;
01703 }
01704
01705 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01706 {
01707 struct gtalk_pvt *p = ast_channel_tech_pvt(newchan);
01708 ast_mutex_lock(&p->lock);
01709
01710 if ((p->owner != oldchan)) {
01711 ast_mutex_unlock(&p->lock);
01712 return -1;
01713 }
01714 if (p->owner == oldchan)
01715 p->owner = newchan;
01716 ast_mutex_unlock(&p->lock);
01717 return 0;
01718 }
01719
01720 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01721 {
01722 int res = 0;
01723
01724 switch (condition) {
01725 case AST_CONTROL_HOLD:
01726 ast_moh_start(ast, data, NULL);
01727 break;
01728 case AST_CONTROL_UNHOLD:
01729 ast_moh_stop(ast);
01730 break;
01731 default:
01732 ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
01733
01734 case AST_CONTROL_PVT_CAUSE_CODE:
01735 res = -1;
01736 }
01737
01738 return res;
01739 }
01740
01741 static int gtalk_sendtext(struct ast_channel *chan, const char *text)
01742 {
01743 int res = 0;
01744 struct aji_client *client = NULL;
01745 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01746
01747 if (!p->parent) {
01748 ast_log(LOG_ERROR, "Parent channel not found\n");
01749 return -1;
01750 }
01751 if (!p->parent->connection) {
01752 ast_log(LOG_ERROR, "XMPP client not found\n");
01753 return -1;
01754 }
01755 client = p->parent->connection;
01756 res = ast_aji_send_chat(client, p->them, text);
01757 return res;
01758 }
01759
01760 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
01761 {
01762 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01763 int res = 0;
01764
01765 ast_mutex_lock(&p->lock);
01766 if (p->rtp) {
01767 ast_rtp_instance_dtmf_begin(p->rtp, digit);
01768 } else {
01769 res = -1;
01770 }
01771 ast_mutex_unlock(&p->lock);
01772
01773 return res;
01774 }
01775
01776 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01777 {
01778 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01779 int res = 0;
01780
01781 ast_mutex_lock(&p->lock);
01782 if (p->rtp) {
01783 ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
01784 } else {
01785 res = -1;
01786 }
01787 ast_mutex_unlock(&p->lock);
01788
01789 return res;
01790 }
01791
01792
01793
01794
01795 #if 0
01796 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
01797 {
01798 struct gtalk_pvt *p = ast->tech_pvt;
01799 struct gtalk *client = p->parent;
01800 iks *iq, *gtalk, *dtmf;
01801 char buffer[2] = {digit, '\0'};
01802 char *lowerthem = NULL;
01803 iq = iks_new("iq");
01804 gtalk = iks_new("gtalk");
01805 dtmf = iks_new("dtmf");
01806 if(!iq || !gtalk || !dtmf) {
01807 iks_delete(iq);
01808 iks_delete(gtalk);
01809 iks_delete(dtmf);
01810 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01811 return -1;
01812 }
01813
01814 iks_insert_attrib(iq, "type", "set");
01815 iks_insert_attrib(iq, "to", p->them);
01816 iks_insert_attrib(iq, "from", p->us);
01817 iks_insert_attrib(iq, "id", client->connection->mid);
01818 ast_aji_increment_mid(client->connection->mid);
01819 iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01820 iks_insert_attrib(gtalk, "action", "session-info");
01821
01822
01823 if (!p->initiator) {
01824 char c;
01825 char *t = lowerthem = ast_strdupa(p->them);
01826 while (((c = *t) != '/') && (*t++ = tolower(c)));
01827 }
01828 iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
01829 iks_insert_attrib(gtalk, "sid", p->sid);
01830 iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01831 iks_insert_attrib(dtmf, "code", buffer);
01832 iks_insert_node(iq, gtalk);
01833 iks_insert_node(gtalk, dtmf);
01834
01835 ast_mutex_lock(&p->lock);
01836 if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01837 iks_insert_attrib(dtmf, "action", "button-down");
01838 } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01839 iks_insert_attrib(dtmf, "action", "button-up");
01840 }
01841 ast_aji_send(client->connection, iq);
01842
01843 iks_delete(iq);
01844 iks_delete(gtalk);
01845 iks_delete(dtmf);
01846 ast_mutex_unlock(&p->lock);
01847 return 0;
01848 }
01849 #endif
01850
01851 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
01852 {
01853 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01854
01855 return -1;
01856 }
01857
01858
01859
01860 static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout)
01861 {
01862 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01863
01864 if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
01865 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
01866 return -1;
01867 }
01868
01869 ast_setstate(ast, AST_STATE_RING);
01870 if (!p->ringrule) {
01871 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01872 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01873 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01874 } else {
01875 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01876 }
01877
01878 gtalk_invite(p, p->them, p->us, p->sid, 1);
01879
01880 return 0;
01881 }
01882
01883
01884 static int gtalk_hangup(struct ast_channel *ast)
01885 {
01886 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01887 struct gtalk *client;
01888
01889 ast_mutex_lock(&p->lock);
01890 client = p->parent;
01891 p->owner = NULL;
01892 ast_channel_tech_pvt_set(ast, NULL);
01893 if (!p->alreadygone) {
01894 gtalk_action(client, p, "terminate");
01895 }
01896 ast_mutex_unlock(&p->lock);
01897
01898 gtalk_free_pvt(client, p);
01899 ast_module_unref(ast_module_info->self);
01900
01901 return 0;
01902 }
01903
01904
01905 static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
01906 {
01907 struct gtalk_pvt *p = NULL;
01908 struct gtalk *client = NULL;
01909 char *sender = NULL, *to = NULL, *s = NULL;
01910 struct ast_channel *chan = NULL;
01911
01912 if (data) {
01913 s = ast_strdupa(data);
01914 sender = strsep(&s, "/");
01915 if (sender && (sender[0] != '\0')) {
01916 to = strsep(&s, "/");
01917 }
01918 if (!to) {
01919 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", data);
01920 return NULL;
01921 }
01922 if (!to) {
01923 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01924 return NULL;
01925 }
01926 }
01927
01928 client = find_gtalk(to, sender);
01929 if (!client) {
01930 ast_log(LOG_WARNING, "Could not find recipient.\n");
01931 return NULL;
01932 }
01933 if (!strcasecmp(client->name, "guest")){
01934
01935
01936 if (client->connection) {
01937 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01938 }
01939 client->connection = ast_aji_get_client(sender);
01940 if (!client->connection) {
01941 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01942 ASTOBJ_UNREF(client, gtalk_member_destroy);
01943 return NULL;
01944 }
01945 }
01946
01947 ASTOBJ_WRLOCK(client);
01948 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01949 if (p) {
01950 chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
01951 }
01952 ASTOBJ_UNLOCK(client);
01953 return chan;
01954 }
01955
01956
01957 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01958 {
01959 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
01960 struct gtalk_pvt *p;
01961 struct ast_channel *chan;
01962 int numchans = 0;
01963 char them[AJI_MAX_JIDLEN];
01964 char *jid = NULL;
01965 char *resource = NULL;
01966
01967 switch (cmd) {
01968 case CLI_INIT:
01969 e->command = "gtalk show channels";
01970 e->usage =
01971 "Usage: gtalk show channels\n"
01972 " Shows current state of the Gtalk channels.\n";
01973 return NULL;
01974 case CLI_GENERATE:
01975 return NULL;
01976 }
01977
01978 if (a->argc != 3)
01979 return CLI_SHOWUSAGE;
01980
01981 ast_mutex_lock(>alklock);
01982 ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01983 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01984 ASTOBJ_WRLOCK(iterator);
01985 p = iterator->p;
01986 while(p) {
01987 chan = p->owner;
01988 ast_copy_string(them, p->them, sizeof(them));
01989 jid = them;
01990 resource = strchr(them, '/');
01991 if (!resource)
01992 resource = "None";
01993 else {
01994 *resource = '\0';
01995 resource ++;
01996 }
01997 if (chan)
01998 ast_cli(a->fd, FORMAT,
01999 ast_channel_name(chan),
02000 jid,
02001 resource,
02002 ast_getformatname(ast_channel_readformat(chan)),
02003 ast_getformatname(ast_channel_writeformat(chan))
02004 );
02005 else
02006 ast_log(LOG_WARNING, "No available channel\n");
02007 numchans ++;
02008 p = p->next;
02009 }
02010 ASTOBJ_UNLOCK(iterator);
02011 });
02012
02013 ast_mutex_unlock(>alklock);
02014
02015 ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
02016 return CLI_SUCCESS;
02017 #undef FORMAT
02018 }
02019
02020
02021 static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02022 {
02023 char codec_buf[BUFSIZ];
02024 switch (cmd) {
02025 case CLI_INIT:
02026 e->command = "gtalk show settings";
02027 e->usage =
02028 "Usage: gtalk show settings\n"
02029 " Provides detailed list of the configuration on the GoogleTalk channel.\n";
02030 return NULL;
02031 case CLI_GENERATE:
02032 return NULL;
02033 }
02034
02035 if (a->argc != 3) {
02036 return CLI_SHOWUSAGE;
02037 }
02038
02039 #define FORMAT " %-25.20s %-15.30s\n"
02040
02041 ast_cli(a->fd, "\nGlobal Settings:\n");
02042 ast_cli(a->fd, "----------------\n");
02043 ast_cli(a->fd, FORMAT, "UDP Bindaddress:", ast_inet_ntoa(bindaddr.sin_addr));
02044 ast_cli(a->fd, FORMAT, "Stun Address:", global_stunaddr != 0 ? ast_inet_ntoa(stunaddr.sin_addr) : "Disabled");
02045 ast_cli(a->fd, FORMAT, "External IP:", S_OR(externip, "Disabled"));
02046 ast_cli(a->fd, FORMAT, "Context:", global_context);
02047 ast_cli(a->fd, FORMAT, "Codecs:", ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, global_capability));
02048 ast_cli(a->fd, FORMAT, "Parking Lot:", global_parkinglot);
02049 ast_cli(a->fd, FORMAT, "Allow Guest:", AST_CLI_YESNO(global_allowguest));
02050 ast_cli(a->fd, "\n----\n");
02051
02052 return CLI_SUCCESS;
02053 #undef FORMAT
02054 }
02055
02056
02057
02058 #if 0
02059 static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02060 {
02061 switch (cmd) {
02062 case CLI_INIT:
02063 e->command = "gtalk reload";
02064 e->usage =
02065 "Usage: gtalk reload\n"
02066 " Reload gtalk channel driver.\n";
02067 return NULL;
02068 case CLI_GENERATE:
02069 return NULL;
02070 }
02071
02072 ast_verbose("IT DOES WORK!\n");
02073 return CLI_SUCCESS;
02074 }
02075 #endif
02076
02077 static int gtalk_parser(void *data, ikspak *pak)
02078 {
02079 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
02080 int res;
02081 iks *tmp;
02082
02083 if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
02084 ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
02085 pak->query = tmp;
02086 }
02087
02088 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
02089 ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
02090 }
02091
02092 if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
02093 ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n");
02094 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
02095
02096 gtalk_newcall(client, pak);
02097 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
02098 ast_debug(3, "About to add candidate!\n");
02099 res = gtalk_add_candidate(client, pak);
02100 if (!res) {
02101 ast_log(LOG_WARNING, "Could not add any candidate\n");
02102 } else {
02103 ast_debug(3, "Candidate Added!\n");
02104 }
02105 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
02106 gtalk_is_answered(client, pak);
02107 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
02108 gtalk_is_accepted(client, pak);
02109 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
02110 gtalk_handle_dtmf(client, pak);
02111 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
02112 gtalk_hangup_farend(client, pak);
02113 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
02114 gtalk_hangup_farend(client, pak);
02115 }
02116 ASTOBJ_UNREF(client, gtalk_member_destroy);
02117 return IKS_FILTER_EAT;
02118 }
02119
02120 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
02121 struct ast_codec_pref prefs, char *context,
02122 struct gtalk *member)
02123 {
02124 struct aji_client *client;
02125
02126 if (!member)
02127 ast_log(LOG_WARNING, "Out of memory.\n");
02128
02129 ast_copy_string(member->name, label, sizeof(member->name));
02130 ast_copy_string(member->user, label, sizeof(member->user));
02131 ast_copy_string(member->context, context, sizeof(member->context));
02132 member->allowguest = allowguest;
02133 member->prefs = prefs;
02134 while (var) {
02135 if (!strcasecmp(var->name, "username"))
02136 ast_copy_string(member->user, var->value, sizeof(member->user));
02137 else if (!strcasecmp(var->name, "disallow"))
02138 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
02139 else if (!strcasecmp(var->name, "allow"))
02140 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
02141 else if (!strcasecmp(var->name, "context"))
02142 ast_copy_string(member->context, var->value, sizeof(member->context));
02143 else if (!strcasecmp(var->name, "parkinglot"))
02144 ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
02145 else if (!strcasecmp(var->name, "connection")) {
02146 if ((client = ast_aji_get_client(var->value))) {
02147 member->connection = client;
02148 iks_filter_add_rule(client->f, gtalk_parser, member,
02149 IKS_RULE_TYPE, IKS_PAK_IQ,
02150 IKS_RULE_FROM_PARTIAL, member->user,
02151 IKS_RULE_NS, GOOGLE_NS,
02152 IKS_RULE_DONE);
02153 } else {
02154 ast_log(LOG_ERROR, "connection referenced not found!\n");
02155 return 0;
02156 }
02157 }
02158 var = var->next;
02159 }
02160 if (member->connection && member->user)
02161 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
02162 else {
02163 ast_log(LOG_ERROR, "No Connection or Username!\n");
02164 }
02165 return 1;
02166 }
02167
02168 static int gtalk_load_config(void)
02169 {
02170 char *cat = NULL;
02171 struct ast_config *cfg = NULL;
02172 struct ast_variable *var;
02173 struct gtalk *member;
02174 struct ast_codec_pref prefs;
02175 struct aji_client_container *clients;
02176 struct gtalk_candidate *global_candidates = NULL;
02177 struct hostent *hp;
02178 struct ast_hostent ahp;
02179 struct ast_flags config_flags = { 0 };
02180
02181 cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
02182 if (!cfg) {
02183 return 0;
02184 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02185 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG);
02186 return 0;
02187 }
02188
02189
02190 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02191
02192
02193 memset(&prefs, 0, sizeof(prefs));
02194 memset(&stunaddr, 0, sizeof(stunaddr));
02195 global_stunaddr = 0;
02196 global_allowguest = DEFAULT_ALLOWGUEST;
02197 ast_copy_string(global_context, DEFAULT_CONTEXT, sizeof(global_context));
02198 ast_copy_string(global_parkinglot, DEFAULT_PARKINGLOT, sizeof(global_parkinglot));
02199
02200 cat = ast_category_browse(cfg, NULL);
02201 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02202
02203 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) {
02204 continue;
02205 }
02206
02207 if (!strcasecmp(var->name, "allowguest")) {
02208 global_allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
02209 } else if (!strcasecmp(var->name, "disallow")) {
02210 ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
02211 } else if (!strcasecmp(var->name, "allow")) {
02212 ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
02213 } else if (!strcasecmp(var->name, "context")) {
02214 ast_copy_string(global_context, var->value, sizeof(global_context));
02215 } else if (!strcasecmp(var->name, "externip")) {
02216 ast_copy_string(externip, var->value, sizeof(externip));
02217 } else if (!strcasecmp(var->name, "parkinglot")) {
02218 ast_copy_string(global_parkinglot, var->value, sizeof(global_parkinglot));
02219 } else if (!strcasecmp(var->name, "bindaddr")) {
02220 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
02221 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
02222 } else {
02223 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
02224 }
02225 } else if (!strcasecmp(var->name, "stunaddr")) {
02226 stunaddr.sin_port = htons(STANDARD_STUN_PORT);
02227 global_stunaddr = 1;
02228 if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
02229 ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
02230 }
02231 }
02232 }
02233 while (cat) {
02234 if (strcasecmp(cat, "general")) {
02235 var = ast_variable_browse(cfg, cat);
02236 member = ast_calloc(1, sizeof(*member));
02237 ASTOBJ_INIT(member);
02238 ASTOBJ_WRLOCK(member);
02239 member->cap = ast_format_cap_alloc_nolock();
02240 if (!strcasecmp(cat, "guest")) {
02241 ast_copy_string(member->name, "guest", sizeof(member->name));
02242 ast_copy_string(member->user, "guest", sizeof(member->user));
02243 ast_copy_string(member->context, global_context, sizeof(member->context));
02244 ast_copy_string(member->parkinglot, global_parkinglot, sizeof(member->parkinglot));
02245 member->allowguest = global_allowguest;
02246 member->prefs = prefs;
02247 while (var) {
02248 if (!strcasecmp(var->name, "disallow")) {
02249 ast_parse_allow_disallow(&member->prefs, member->cap,
02250 var->value, 0);
02251 } else if (!strcasecmp(var->name, "allow")) {
02252 ast_parse_allow_disallow(&member->prefs, member->cap,
02253 var->value, 1);
02254 } else if (!strcasecmp(var->name, "context")) {
02255 ast_copy_string(member->context, var->value,
02256 sizeof(member->context));
02257 } else if (!strcasecmp(var->name, "parkinglot")) {
02258 ast_copy_string(member->parkinglot, var->value,
02259 sizeof(member->parkinglot));
02260 }
02261 var = var->next;
02262 }
02263 ASTOBJ_UNLOCK(member);
02264 clients = ast_aji_get_clients();
02265 if (clients) {
02266 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02267 ASTOBJ_WRLOCK(iterator);
02268 ASTOBJ_WRLOCK(member);
02269 if (member->connection) {
02270 ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
02271 }
02272 member->connection = NULL;
02273 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
02274 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
02275 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
02276 ASTOBJ_UNLOCK(member);
02277 ASTOBJ_UNLOCK(iterator);
02278 });
02279 ASTOBJ_CONTAINER_LINK(>alk_list, member);
02280 ASTOBJ_UNREF(member, gtalk_member_destroy);
02281 } else {
02282 ASTOBJ_UNLOCK(member);
02283 ASTOBJ_UNREF(member, gtalk_member_destroy);
02284 }
02285 } else {
02286 ASTOBJ_UNLOCK(member);
02287 if (gtalk_create_member(cat, var, global_allowguest, prefs, global_context, member)) {
02288 ASTOBJ_CONTAINER_LINK(>alk_list, member);
02289 }
02290 ASTOBJ_UNREF(member, gtalk_member_destroy);
02291 }
02292 }
02293 cat = ast_category_browse(cfg, cat);
02294 }
02295
02296 ast_config_destroy(cfg);
02297 gtalk_update_externip();
02298 gtalk_free_candidates(global_candidates);
02299 return 1;
02300 }
02301
02302
02303 static int load_module(void)
02304 {
02305 struct ast_sockaddr bindaddr_tmp;
02306 struct ast_sockaddr ourip_tmp;
02307 char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02308 struct ast_format tmpfmt;
02309
02310 if (!(gtalk_tech.capabilities = ast_format_cap_alloc())) {
02311 return AST_MODULE_LOAD_DECLINE;
02312 }
02313 if (!(global_capability = ast_format_cap_alloc())) {
02314 return AST_MODULE_LOAD_DECLINE;
02315 }
02316
02317 ast_format_cap_add_all_by_type(gtalk_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
02318 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
02319 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
02320 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
02321 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
02322
02323 free(jabber_loaded);
02324 if (!jabber_loaded) {
02325
02326 jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02327 free(jabber_loaded);
02328 if (!jabber_loaded) {
02329 ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02330 return AST_MODULE_LOAD_DECLINE;
02331 }
02332 }
02333
02334 ASTOBJ_CONTAINER_INIT(>alk_list);
02335 if (!gtalk_load_config()) {
02336 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02337 return 0;
02338 }
02339
02340 sched = ast_sched_context_create();
02341 if (!sched) {
02342 ast_log(LOG_WARNING, "Unable to create schedule context\n");
02343 }
02344
02345 io = io_context_create();
02346 if (!io) {
02347 ast_log(LOG_WARNING, "Unable to create I/O context\n");
02348 }
02349
02350 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02351 if (gtalk_get_local_ip(&ourip_tmp)) {
02352 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02353 return 0;
02354 }
02355 __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
02356
02357 ast_rtp_glue_register(>alk_rtp_glue);
02358 ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02359
02360
02361 if (ast_channel_register(>alk_tech)) {
02362 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02363 return -1;
02364 }
02365 return 0;
02366 }
02367
02368
02369
02370 #if 0
02371 static int reload(void)
02372 {
02373 return 0;
02374 }
02375 #endif
02376
02377 static int unload_module(void)
02378 {
02379 struct gtalk_pvt *privates = NULL;
02380 ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02381
02382 ast_channel_unregister(>alk_tech);
02383 ast_rtp_glue_unregister(>alk_rtp_glue);
02384
02385 if (!ast_mutex_lock(>alklock)) {
02386
02387 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
02388 ASTOBJ_WRLOCK(iterator);
02389 privates = iterator->p;
02390 while(privates) {
02391 if (privates->owner)
02392 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02393 privates = privates->next;
02394 }
02395 iterator->p = NULL;
02396 ASTOBJ_UNLOCK(iterator);
02397 });
02398 ast_mutex_unlock(>alklock);
02399 } else {
02400 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02401 return -1;
02402 }
02403 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
02404 ASTOBJ_CONTAINER_DESTROY(>alk_list);
02405 global_capability = ast_format_cap_destroy(global_capability);
02406 gtalk_tech.capabilities = ast_format_cap_destroy(gtalk_tech.capabilities);
02407 return 0;
02408 }
02409
02410 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver",
02411 .load = load_module,
02412 .unload = unload_module,
02413
02414 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
02415 );