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: 87906 $")
00037
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <sys/socket.h>
00043 #include <errno.h>
00044 #include <stdlib.h>
00045 #include <fcntl.h>
00046 #include <netdb.h>
00047 #include <netinet/in.h>
00048 #include <arpa/inet.h>
00049 #include <sys/signal.h>
00050 #include <iksemel.h>
00051 #include <pthread.h>
00052
00053 #ifdef HAVE_GNUTLS
00054 #include <gcrypt.h>
00055 GCRY_THREAD_OPTION_PTHREAD_IMPL;
00056 #endif
00057
00058 #include "asterisk/lock.h"
00059 #include "asterisk/channel.h"
00060 #include "asterisk/config.h"
00061 #include "asterisk/logger.h"
00062 #include "asterisk/module.h"
00063 #include "asterisk/pbx.h"
00064 #include "asterisk/options.h"
00065 #include "asterisk/lock.h"
00066 #include "asterisk/sched.h"
00067 #include "asterisk/io.h"
00068 #include "asterisk/rtp.h"
00069 #include "asterisk/acl.h"
00070 #include "asterisk/callerid.h"
00071 #include "asterisk/file.h"
00072 #include "asterisk/cli.h"
00073 #include "asterisk/app.h"
00074 #include "asterisk/musiconhold.h"
00075 #include "asterisk/manager.h"
00076 #include "asterisk/stringfields.h"
00077 #include "asterisk/utils.h"
00078 #include "asterisk/causes.h"
00079 #include "asterisk/astobj.h"
00080 #include "asterisk/abstract_jb.h"
00081 #include "asterisk/jabber.h"
00082
00083 #define GOOGLE_CONFIG "gtalk.conf"
00084
00085 #define GOOGLE_NS "http://www.google.com/session"
00086
00087
00088
00089 static struct ast_jb_conf default_jbconf =
00090 {
00091 .flags = 0,
00092 .max_size = -1,
00093 .resync_threshold = -1,
00094 .impl = ""
00095 };
00096 static struct ast_jb_conf global_jbconf;
00097
00098 enum gtalk_protocol {
00099 AJI_PROTOCOL_UDP = 1,
00100 AJI_PROTOCOL_SSLTCP = 2,
00101 };
00102
00103 enum gtalk_connect_type {
00104 AJI_CONNECT_STUN = 1,
00105 AJI_CONNECT_LOCAL = 2,
00106 AJI_CONNECT_RELAY = 3,
00107 };
00108
00109 struct gtalk_pvt {
00110 ast_mutex_t lock;
00111 time_t laststun;
00112 struct gtalk *parent;
00113 char sid[100];
00114 char us[AJI_MAX_JIDLEN];
00115 char them[AJI_MAX_JIDLEN];
00116 char ring[10];
00117 iksrule *ringrule;
00118 int initiator;
00119 int alreadygone;
00120 int capability;
00121 struct ast_codec_pref prefs;
00122 struct gtalk_candidate *theircandidates;
00123 struct gtalk_candidate *ourcandidates;
00124 char cid_num[80];
00125 char cid_name[80];
00126 char exten[80];
00127 struct ast_channel *owner;
00128 struct ast_rtp *rtp;
00129 struct ast_rtp *vrtp;
00130 int jointcapability;
00131 int peercapability;
00132 struct gtalk_pvt *next;
00133 };
00134
00135 struct gtalk_candidate {
00136 char name[100];
00137 enum gtalk_protocol protocol;
00138 double preference;
00139 char username[100];
00140 char password[100];
00141 enum gtalk_connect_type type;
00142 char network[6];
00143 int generation;
00144 char ip[16];
00145 int port;
00146 int receipt;
00147 struct gtalk_candidate *next;
00148 };
00149
00150 struct gtalk {
00151 ASTOBJ_COMPONENTS(struct gtalk);
00152 struct aji_client *connection;
00153 struct aji_buddy *buddy;
00154 struct gtalk_pvt *p;
00155 struct ast_codec_pref prefs;
00156 int amaflags;
00157 char user[AJI_MAX_JIDLEN];
00158 char context[AST_MAX_CONTEXT];
00159 char accountcode[AST_MAX_ACCOUNT_CODE];
00160 int capability;
00161 ast_group_t callgroup;
00162 ast_group_t pickupgroup;
00163 int callingpres;
00164 int allowguest;
00165 char language[MAX_LANGUAGE];
00166 char musicclass[MAX_MUSICCLASS];
00167 };
00168
00169 struct gtalk_container {
00170 ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
00171 };
00172
00173 static const char desc[] = "Gtalk Channel";
00174
00175 static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
00176
00177 AST_MUTEX_DEFINE_STATIC(gtalklock);
00178
00179
00180 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
00181 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
00182 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
00183 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00184 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
00185 static int gtalk_hangup(struct ast_channel *ast);
00186 static int gtalk_answer(struct ast_channel *ast);
00187 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
00188 static struct ast_frame *gtalk_read(struct ast_channel *ast);
00189 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
00190 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00191 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00192 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00193 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
00194 static int gtalk_do_reload(int fd, int argc, char **argv);
00195 static int gtalk_show_channels(int fd, int argc, char **argv);
00196
00197 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
00198 struct ast_rtp *vrtp, int codecs, int nat_active);
00199 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
00200 static int gtalk_get_codec(struct ast_channel *chan);
00201
00202
00203 static const struct ast_channel_tech gtalk_tech = {
00204 .type = "Gtalk",
00205 .description = "Gtalk Channel Driver",
00206 .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
00207 .requester = gtalk_request,
00208 .send_digit_begin = gtalk_digit_begin,
00209 .send_digit_end = gtalk_digit_end,
00210 .bridge = ast_rtp_bridge,
00211 .call = gtalk_call,
00212 .hangup = gtalk_hangup,
00213 .answer = gtalk_answer,
00214 .read = gtalk_read,
00215 .write = gtalk_write,
00216 .exception = gtalk_read,
00217 .indicate = gtalk_indicate,
00218 .fixup = gtalk_fixup,
00219 .send_html = gtalk_sendhtml,
00220 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00221 };
00222
00223 static struct sockaddr_in bindaddr = { 0, };
00224
00225 static struct sched_context *sched;
00226 static struct io_context *io;
00227 static struct in_addr __ourip;
00228
00229
00230
00231 static struct ast_rtp_protocol gtalk_rtp = {
00232 type: "Gtalk",
00233 get_rtp_info: gtalk_get_rtp_peer,
00234 set_rtp_peer: gtalk_set_rtp_peer,
00235 get_codec: gtalk_get_codec,
00236 };
00237
00238 static char show_channels_usage[] =
00239 "Usage: gtalk show channels\n"
00240 " Shows current state of the Gtalk channels.\n";
00241
00242 static char reload_usage[] =
00243 "Usage: gtalk reload\n"
00244 " Reload gtalk channel driver.\n";
00245
00246
00247 static struct ast_cli_entry gtalk_cli[] = {
00248 {{ "gtalk", "reload", NULL}, gtalk_do_reload, "Reload GoogleTalk configuration", reload_usage },
00249 {{ "gtalk", "show", "channels", NULL}, gtalk_show_channels, "Show GoogleTalk channels", show_channels_usage },
00250 };
00251
00252
00253
00254 static char externip[16];
00255
00256 static struct gtalk_container gtalk_list;
00257
00258 static void gtalk_member_destroy(struct gtalk *obj)
00259 {
00260 free(obj);
00261 }
00262
00263 static struct gtalk *find_gtalk(char *name, char *connection)
00264 {
00265 struct gtalk *gtalk = NULL;
00266 char *domain = NULL , *s = NULL;
00267
00268 if(strchr(connection, '@')) {
00269 s = ast_strdupa(connection);
00270 domain = strsep(&s, "@");
00271 ast_verbose("OOOOH domain = %s\n", domain);
00272 }
00273 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
00274 if (!gtalk && strchr(name, '@'))
00275 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
00276
00277 if (!gtalk) {
00278 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
00279 ASTOBJ_RDLOCK(iterator);
00280 if (!strcasecmp(iterator->name, "guest")) {
00281 if (!strcasecmp(iterator->connection->jid->partial, connection)) {
00282 gtalk = iterator;
00283 } else if (!strcasecmp(iterator->connection->name, connection)) {
00284 gtalk = iterator;
00285 } else if (iterator->connection->component && !strcasecmp(iterator->connection->user,domain)) {
00286 gtalk = iterator;
00287 }
00288 }
00289 ASTOBJ_UNLOCK(iterator);
00290
00291 if (gtalk)
00292 break;
00293 });
00294
00295 }
00296 return gtalk;
00297 }
00298
00299
00300 static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
00301 {
00302 char *format = ast_getformatname(codec);
00303
00304 if (!strcasecmp("ulaw", format)) {
00305 iks *payload_eg711u, *payload_pcmu;
00306 payload_pcmu = iks_new("payload-type");
00307 payload_eg711u = iks_new("payload-type");
00308
00309 if(!payload_eg711u || !payload_pcmu) {
00310 if(payload_pcmu)
00311 iks_delete(payload_pcmu);
00312 if(payload_eg711u)
00313 iks_delete(payload_eg711u);
00314 ast_log(LOG_WARNING,"Failed to allocate iks node");
00315 return -1;
00316 }
00317 iks_insert_attrib(payload_pcmu, "id", "0");
00318 iks_insert_attrib(payload_pcmu, "name", "PCMU");
00319 iks_insert_attrib(payload_pcmu, "clockrate","8000");
00320 iks_insert_attrib(payload_pcmu, "bitrate","64000");
00321 iks_insert_attrib(payload_eg711u, "id", "100");
00322 iks_insert_attrib(payload_eg711u, "name", "EG711U");
00323 iks_insert_attrib(payload_eg711u, "clockrate","8000");
00324 iks_insert_attrib(payload_eg711u, "bitrate","64000");
00325 iks_insert_node(dcodecs, payload_pcmu);
00326 iks_insert_node(dcodecs, payload_eg711u);
00327 }
00328 if (!strcasecmp("alaw", format)) {
00329 iks *payload_eg711a, *payload_pcma;
00330 payload_pcma = iks_new("payload-type");
00331 payload_eg711a = iks_new("payload-type");
00332 if(!payload_eg711a || !payload_pcma) {
00333 if(payload_eg711a)
00334 iks_delete(payload_eg711a);
00335 if(payload_pcma)
00336 iks_delete(payload_pcma);
00337 ast_log(LOG_WARNING,"Failed to allocate iks node");
00338 return -1;
00339 }
00340 iks_insert_attrib(payload_pcma, "id", "8");
00341 iks_insert_attrib(payload_pcma, "name", "PCMA");
00342 iks_insert_attrib(payload_pcma, "clockrate","8000");
00343 iks_insert_attrib(payload_pcma, "bitrate","64000");
00344 payload_eg711a = iks_new("payload-type");
00345 iks_insert_attrib(payload_eg711a, "id", "101");
00346 iks_insert_attrib(payload_eg711a, "name", "EG711A");
00347 iks_insert_attrib(payload_eg711a, "clockrate","8000");
00348 iks_insert_attrib(payload_eg711a, "bitrate","64000");
00349 iks_insert_node(dcodecs, payload_pcma);
00350 iks_insert_node(dcodecs, payload_eg711a);
00351 }
00352 if (!strcasecmp("ilbc", format)) {
00353 iks *payload_ilbc = iks_new("payload-type");
00354 if(!payload_ilbc) {
00355 ast_log(LOG_WARNING,"Failed to allocate iks node");
00356 return -1;
00357 }
00358 iks_insert_attrib(payload_ilbc, "id", "97");
00359 iks_insert_attrib(payload_ilbc, "name", "iLBC");
00360 iks_insert_attrib(payload_ilbc, "clockrate","8000");
00361 iks_insert_attrib(payload_ilbc, "bitrate","13300");
00362 iks_insert_node(dcodecs, payload_ilbc);
00363 }
00364 if (!strcasecmp("g723", format)) {
00365 iks *payload_g723 = iks_new("payload-type");
00366 if(!payload_g723) {
00367 ast_log(LOG_WARNING,"Failed to allocate iks node");
00368 return -1;
00369 }
00370 iks_insert_attrib(payload_g723, "id", "4");
00371 iks_insert_attrib(payload_g723, "name", "G723");
00372 iks_insert_attrib(payload_g723, "clockrate","8000");
00373 iks_insert_attrib(payload_g723, "bitrate","6300");
00374 iks_insert_node(dcodecs, payload_g723);
00375 }
00376 if (!strcasecmp("speex", format)) {
00377 iks *payload_speex = iks_new("payload-type");
00378 if(!payload_speex) {
00379 ast_log(LOG_WARNING,"Failed to allocate iks node");
00380 return -1;
00381 }
00382 iks_insert_attrib(payload_speex, "id", "110");
00383 iks_insert_attrib(payload_speex, "name", "speex");
00384 iks_insert_attrib(payload_speex, "clockrate","8000");
00385 iks_insert_attrib(payload_speex, "bitrate","11000");
00386 iks_insert_node(dcodecs, payload_speex);
00387 }
00388 ast_rtp_lookup_code(p->rtp, 1, codec);
00389 return 0;
00390 }
00391
00392 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
00393 {
00394 struct gtalk *client = p->parent;
00395 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00396 int x;
00397 int pref_codec = 0;
00398 int alreadysent = 0;
00399
00400
00401 iq = iks_new("iq");
00402 gtalk = iks_new("session");
00403 dcodecs = iks_new("description");
00404 transport = iks_new("transport");
00405 payload_telephone = iks_new("payload-type");
00406 if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
00407 if(iq)
00408 iks_delete(iq);
00409 if(gtalk)
00410 iks_delete(gtalk);
00411 if(dcodecs)
00412 iks_delete(dcodecs);
00413 if(transport)
00414 iks_delete(transport);
00415 if(payload_telephone)
00416 iks_delete(payload_telephone);
00417
00418 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00419 return 0;
00420 }
00421 iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone");
00422 iks_insert_attrib(dcodecs, "xml:lang", "en");
00423
00424 for (x = 0; x < 32; x++) {
00425 if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
00426 break;
00427 if (!(client->capability & pref_codec))
00428 continue;
00429 if (alreadysent & pref_codec)
00430 continue;
00431 add_codec_to_answer(p, pref_codec, dcodecs);
00432 alreadysent |= pref_codec;
00433 }
00434
00435 iks_insert_attrib(payload_telephone, "id", "106");
00436 iks_insert_attrib(payload_telephone, "name", "telephone-event");
00437 iks_insert_attrib(payload_telephone, "clockrate", "8000");
00438
00439 iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p");
00440
00441 iks_insert_attrib(iq, "type", "set");
00442 iks_insert_attrib(iq, "to", to);
00443 iks_insert_attrib(iq, "from", from);
00444 iks_insert_attrib(iq, "id", client->connection->mid);
00445 ast_aji_increment_mid(client->connection->mid);
00446
00447 iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session");
00448 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00449 iks_insert_attrib(gtalk, "initiator", initiator ? from : to);
00450 iks_insert_attrib(gtalk, "id", sid);
00451 iks_insert_node(iq, gtalk);
00452 iks_insert_node(gtalk, dcodecs);
00453 iks_insert_node(gtalk, transport);
00454 iks_insert_node(dcodecs, payload_telephone);
00455
00456 iks_send(client->connection->p, iq);
00457 iks_delete(payload_telephone);
00458 iks_delete(transport);
00459 iks_delete(dcodecs);
00460 iks_delete(gtalk);
00461 iks_delete(iq);
00462 return 1;
00463 }
00464
00465 static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator)
00466 {
00467 iks *iq, *session, *transport;
00468 iq = iks_new("iq");
00469 session = iks_new("session");
00470 transport = iks_new("transport");
00471 if(!(iq && session && transport)) {
00472 if(iq)
00473 iks_delete(iq);
00474 if(session)
00475 iks_delete(session);
00476 if(transport)
00477 iks_delete(transport);
00478 ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
00479 return -1;
00480 }
00481 iks_insert_attrib(iq, "from", from);
00482 iks_insert_attrib(iq, "to", to);
00483 iks_insert_attrib(iq, "type", "set");
00484 iks_insert_attrib(iq, "id",p->parent->connection->mid);
00485 ast_aji_increment_mid(p->parent->connection->mid);
00486 iks_insert_attrib(session, "type", "transport-accept");
00487 iks_insert_attrib(session, "id", sid);
00488 iks_insert_attrib(session, "initiator", initiator ? from : to);
00489 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
00490 iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
00491 iks_insert_node(iq,session);
00492 iks_insert_node(session,transport);
00493 iks_send(p->parent->connection->p, iq);
00494 iks_delete(transport);
00495 iks_delete(session);
00496 iks_delete(iq);
00497 return 1;
00498
00499 }
00500
00501 static int gtalk_ringing_ack(void *data, ikspak *pak)
00502 {
00503 struct gtalk_pvt *p = data;
00504
00505 if (p->ringrule)
00506 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00507 p->ringrule = NULL;
00508 if (p->owner)
00509 ast_queue_control(p->owner, AST_CONTROL_RINGING);
00510 return IKS_FILTER_EAT;
00511 }
00512
00513 static int gtalk_answer(struct ast_channel *ast)
00514 {
00515 struct gtalk_pvt *p = ast->tech_pvt;
00516 int res = 0;
00517
00518 if (option_debug)
00519 ast_log(LOG_DEBUG, "Answer!\n");
00520 ast_mutex_lock(&p->lock);
00521 gtalk_invite(p, p->them, p->us,p->sid, 0);
00522 ast_mutex_unlock(&p->lock);
00523 return res;
00524 }
00525
00526 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
00527 {
00528 struct gtalk_pvt *p = chan->tech_pvt;
00529 enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
00530
00531 if (!p)
00532 return res;
00533
00534 ast_mutex_lock(&p->lock);
00535 if (p->rtp){
00536 *rtp = p->rtp;
00537 res = AST_RTP_TRY_PARTIAL;
00538 }
00539 ast_mutex_unlock(&p->lock);
00540
00541 return res;
00542 }
00543
00544 static int gtalk_get_codec(struct ast_channel *chan)
00545 {
00546 struct gtalk_pvt *p = chan->tech_pvt;
00547 return p->peercapability;
00548 }
00549
00550 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
00551 {
00552 struct gtalk_pvt *p;
00553
00554 p = chan->tech_pvt;
00555 if (!p)
00556 return -1;
00557 ast_mutex_lock(&p->lock);
00558
00559
00560
00561
00562
00563
00564
00565
00566 ast_mutex_unlock(&p->lock);
00567 return 0;
00568 }
00569
00570 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
00571 {
00572 iks *response = NULL, *error = NULL, *reason = NULL;
00573 int res = -1;
00574
00575 response = iks_new("iq");
00576 if (response) {
00577 iks_insert_attrib(response, "type", "result");
00578 iks_insert_attrib(response, "from", from);
00579 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00580 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00581 if (reasonstr) {
00582 error = iks_new("error");
00583 if (error) {
00584 iks_insert_attrib(error, "type", "cancel");
00585 reason = iks_new(reasonstr);
00586 if (reason)
00587 iks_insert_node(error, reason);
00588 iks_insert_node(response, error);
00589 }
00590 }
00591 iks_send(client->connection->p, response);
00592 if (reason)
00593 iks_delete(reason);
00594 if (error)
00595 iks_delete(error);
00596 iks_delete(response);
00597 res = 0;
00598 }
00599 return res;
00600 }
00601
00602 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
00603 {
00604 struct gtalk_pvt *tmp;
00605 char *from;
00606 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00607
00608 for (tmp = client->p; tmp; tmp = tmp->next) {
00609 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00610 break;
00611 }
00612
00613 from = iks_find_attrib(pak->x, "to");
00614 if(!from)
00615 from = client->connection->jid->full;
00616
00617 if (tmp) {
00618 if (tmp->owner)
00619 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00620 } else
00621 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00622 gtalk_response(client, from, pak, NULL, NULL);
00623 return 1;
00624 }
00625
00626 static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
00627 {
00628 struct gtalk_pvt *tmp;
00629 char *from;
00630
00631 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00632
00633 for (tmp = client->p; tmp; tmp = tmp->next) {
00634 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00635 break;
00636 }
00637
00638 from = iks_find_attrib(pak->x, "to");
00639 if(!from)
00640 from = client->connection->jid->full;
00641
00642 if (!tmp)
00643 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00644
00645
00646 gtalk_response(client, from, pak, NULL, NULL);
00647 return 1;
00648 }
00649
00650 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
00651 {
00652 struct gtalk_pvt *tmp;
00653 iks *dtmfnode = NULL, *dtmfchild = NULL;
00654 char *dtmf;
00655 char *from;
00656
00657 for (tmp = client->p; tmp; tmp = tmp->next) {
00658 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00659 break;
00660 }
00661 from = iks_find_attrib(pak->x, "to");
00662 if(!from)
00663 from = client->connection->jid->full;
00664
00665
00666 if (tmp) {
00667 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00668 gtalk_response(client, from, pak,
00669 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00670 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00671 return -1;
00672 }
00673 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00674 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00675 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00676 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00677 f.subclass = dtmf[0];
00678 ast_queue_frame(tmp->owner, &f);
00679 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00680 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00681 struct ast_frame f = {AST_FRAME_DTMF_END, };
00682 f.subclass = dtmf[0];
00683 ast_queue_frame(tmp->owner, &f);
00684 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00685 } else if(iks_find_attrib(pak->x, "dtmf")) {
00686 struct ast_frame f = {AST_FRAME_DTMF, };
00687 f.subclass = dtmf[0];
00688 ast_queue_frame(tmp->owner, &f);
00689 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00690 }
00691 }
00692 } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00693 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00694 if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00695 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00696 struct ast_frame f = {AST_FRAME_DTMF_END, };
00697 f.subclass = dtmf[0];
00698 ast_queue_frame(tmp->owner, &f);
00699 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00700 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00701 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00702 f.subclass = dtmf[0];
00703 ast_queue_frame(tmp->owner, &f);
00704 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00705 }
00706 }
00707 }
00708 }
00709 gtalk_response(client, from, pak, NULL, NULL);
00710 return 1;
00711 } else
00712 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00713
00714 gtalk_response(client, from, pak, NULL, NULL);
00715 return 1;
00716 }
00717
00718 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
00719 {
00720 struct gtalk_pvt *tmp;
00721 char *from;
00722
00723 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00724
00725 for (tmp = client->p; tmp; tmp = tmp->next) {
00726 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00727 break;
00728 }
00729 from = iks_find_attrib(pak->x, "to");
00730 if(!from)
00731 from = client->connection->jid->full;
00732
00733 if (tmp) {
00734 tmp->alreadygone = 1;
00735 if (tmp->owner)
00736 ast_queue_hangup(tmp->owner);
00737 } else
00738 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00739 gtalk_response(client, from, pak, NULL, NULL);
00740 return 1;
00741 }
00742
00743 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
00744 {
00745 struct gtalk_candidate *tmp;
00746 struct aji_client *c = client->connection;
00747 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00748 struct sockaddr_in sin;
00749 struct sockaddr_in dest;
00750 struct in_addr us;
00751 iks *iq, *gtalk, *candidate, *transport;
00752 char user[17], pass[17], preference[5], port[7];
00753
00754
00755 iq = iks_new("iq");
00756 gtalk = iks_new("session");
00757 candidate = iks_new("candidate");
00758 transport = iks_new("transport");
00759 if (!iq || !gtalk || !candidate || !transport) {
00760 ast_log(LOG_ERROR, "Memory allocation error\n");
00761 goto safeout;
00762 }
00763 ours1 = ast_calloc(1, sizeof(*ours1));
00764 ours2 = ast_calloc(1, sizeof(*ours2));
00765 if (!ours1 || !ours2)
00766 goto safeout;
00767
00768 iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
00769 iks_insert_node(iq, gtalk);
00770 iks_insert_node(gtalk,transport);
00771 iks_insert_node(transport, candidate);
00772
00773 for (; p; p = p->next) {
00774 if (!strcasecmp(p->sid, sid))
00775 break;
00776 }
00777
00778 if (!p) {
00779 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00780 goto safeout;
00781 }
00782
00783 ast_rtp_get_us(p->rtp, &sin);
00784 ast_find_ourip(&us, bindaddr);
00785
00786
00787 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00788 ours1->port = ntohs(sin.sin_port);
00789 ours1->preference = 1;
00790 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00791 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00792 ast_copy_string(ours1->username, user, sizeof(ours1->username));
00793 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00794 ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
00795 ours1->protocol = AJI_PROTOCOL_UDP;
00796 ours1->type = AJI_CONNECT_LOCAL;
00797 ours1->generation = 0;
00798 p->ourcandidates = ours1;
00799
00800 if (!ast_strlen_zero(externip)) {
00801
00802 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00803 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00804 ast_copy_string(ours2->username, user, sizeof(ours2->username));
00805 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00806 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00807 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00808 ours2->port = ntohs(sin.sin_port);
00809 ours2->preference = 0.9;
00810 ours2->protocol = AJI_PROTOCOL_UDP;
00811 ours2->type = AJI_CONNECT_STUN;
00812 ours2->generation = 0;
00813 ours1->next = ours2;
00814 ours2 = NULL;
00815 }
00816 ours1 = NULL;
00817 dest.sin_addr = __ourip;
00818 dest.sin_port = sin.sin_port;
00819
00820
00821 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00822 snprintf(port, sizeof(port), "%d", tmp->port);
00823 snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00824 iks_insert_attrib(iq, "from", to);
00825 iks_insert_attrib(iq, "to", from);
00826 iks_insert_attrib(iq, "type", "set");
00827 iks_insert_attrib(iq, "id", c->mid);
00828 ast_aji_increment_mid(c->mid);
00829 iks_insert_attrib(gtalk, "type", "transport-info");
00830 iks_insert_attrib(gtalk, "id", sid);
00831 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from);
00832 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00833 iks_insert_attrib(candidate, "name", tmp->name);
00834 iks_insert_attrib(candidate, "address", tmp->ip);
00835 iks_insert_attrib(candidate, "port", port);
00836 iks_insert_attrib(candidate, "username", tmp->username);
00837 iks_insert_attrib(candidate, "password", tmp->password);
00838 iks_insert_attrib(candidate, "preference", preference);
00839 if (tmp->protocol == AJI_PROTOCOL_UDP)
00840 iks_insert_attrib(candidate, "protocol", "udp");
00841 if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00842 iks_insert_attrib(candidate, "protocol", "ssltcp");
00843 if (tmp->type == AJI_CONNECT_STUN)
00844 iks_insert_attrib(candidate, "type", "stun");
00845 if (tmp->type == AJI_CONNECT_LOCAL)
00846 iks_insert_attrib(candidate, "type", "local");
00847 if (tmp->type == AJI_CONNECT_RELAY)
00848 iks_insert_attrib(candidate, "type", "relay");
00849 iks_insert_attrib(candidate, "network", "0");
00850 iks_insert_attrib(candidate, "generation", "0");
00851 iks_send(c->p, iq);
00852 }
00853 p->laststun = 0;
00854
00855 safeout:
00856 if (ours1)
00857 free(ours1);
00858 if (ours2)
00859 free(ours2);
00860 if (iq)
00861 iks_delete(iq);
00862 if (gtalk)
00863 iks_delete(gtalk);
00864 if (candidate)
00865 iks_delete(candidate);
00866 if(transport)
00867 iks_delete(transport);
00868 return 1;
00869 }
00870
00871 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
00872 {
00873 struct gtalk_pvt *tmp = NULL;
00874 struct aji_resource *resources = NULL;
00875 struct aji_buddy *buddy;
00876 char idroster[200];
00877 char *data, *exten = NULL;
00878
00879 if (option_debug)
00880 ast_log(LOG_DEBUG, "The client is %s for alloc\n", client->name);
00881 if (!sid && !strchr(them, '/')) {
00882 if (!strcasecmp(client->name, "guest")) {
00883 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00884 if (buddy)
00885 resources = buddy->resources;
00886 } else if (client->buddy)
00887 resources = client->buddy->resources;
00888 while (resources) {
00889 if (resources->cap->jingle) {
00890 break;
00891 }
00892 resources = resources->next;
00893 }
00894 if (resources)
00895 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
00896 else {
00897 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
00898 return NULL;
00899 }
00900 }
00901 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00902 return NULL;
00903 }
00904 if (sid) {
00905 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
00906 ast_copy_string(tmp->them, them, sizeof(tmp->them));
00907 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00908 } else {
00909 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
00910 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
00911 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00912 tmp->initiator = 1;
00913 }
00914 tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
00915 tmp->parent = client;
00916 if (!tmp->rtp) {
00917 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
00918 free(tmp);
00919 return NULL;
00920 }
00921
00922 if(strchr(tmp->us, '/')) {
00923 data = ast_strdupa(tmp->us);
00924 exten = strsep(&data, "/");
00925 } else
00926 exten = tmp->us;
00927 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
00928 ast_mutex_init(&tmp->lock);
00929 ast_mutex_lock(>alklock);
00930 tmp->next = client->p;
00931 client->p = tmp;
00932 ast_mutex_unlock(>alklock);
00933 return tmp;
00934 }
00935
00936
00937 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title)
00938 {
00939 struct ast_channel *tmp;
00940 int fmt;
00941 int what;
00942 const char *n2;
00943 char *data = NULL, *cid = NULL;
00944
00945 if (title)
00946 n2 = title;
00947 else
00948 n2 = i->us;
00949 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
00950 if (!tmp) {
00951 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
00952 return NULL;
00953 }
00954 tmp->tech = >alk_tech;
00955
00956
00957
00958
00959 if (i->jointcapability)
00960 what = i->jointcapability;
00961 else if (i->capability)
00962 what = i->capability;
00963 else
00964 what = global_capability;
00965 tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
00966 fmt = ast_best_codec(tmp->nativeformats);
00967
00968 if (i->rtp) {
00969 ast_rtp_setstun(i->rtp, 1);
00970 tmp->fds[0] = ast_rtp_fd(i->rtp);
00971 tmp->fds[1] = ast_rtcp_fd(i->rtp);
00972 }
00973 if (i->vrtp) {
00974 ast_rtp_setstun(i->rtp, 1);
00975 tmp->fds[2] = ast_rtp_fd(i->vrtp);
00976 tmp->fds[3] = ast_rtcp_fd(i->vrtp);
00977 }
00978 if (state == AST_STATE_RING)
00979 tmp->rings = 1;
00980 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
00981 tmp->writeformat = fmt;
00982 tmp->rawwriteformat = fmt;
00983 tmp->readformat = fmt;
00984 tmp->rawreadformat = fmt;
00985 tmp->tech_pvt = i;
00986
00987 tmp->callgroup = client->callgroup;
00988 tmp->pickupgroup = client->pickupgroup;
00989 tmp->cid.cid_pres = client->callingpres;
00990 if (!ast_strlen_zero(client->accountcode))
00991 ast_string_field_set(tmp, accountcode, client->accountcode);
00992 if (client->amaflags)
00993 tmp->amaflags = client->amaflags;
00994 if (!ast_strlen_zero(client->language))
00995 ast_string_field_set(tmp, language, client->language);
00996 if (!ast_strlen_zero(client->musicclass))
00997 ast_string_field_set(tmp, musicclass, client->musicclass);
00998 i->owner = tmp;
00999 ast_module_ref(ast_module_info->self);
01000 ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01001 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01002
01003
01004 if (!strcasecmp(client->name, "guest")) {
01005 data = ast_strdupa(i->them);
01006 if (strchr(data, '/')) {
01007 cid = strsep(&data, "/");
01008 } else
01009 cid = data;
01010 } else {
01011 data = ast_strdupa(client->user);
01012 cid = data;
01013 }
01014 cid = strsep(&cid, "@");
01015 tmp->cid.cid_ani = ast_strdup(cid);
01016 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
01017 tmp->cid.cid_dnid = ast_strdup(i->exten);
01018 tmp->priority = 1;
01019 if (i->rtp)
01020 ast_jb_configure(tmp, &global_jbconf);
01021 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01022 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01023 tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01024 ast_hangup(tmp);
01025 tmp = NULL;
01026 }
01027
01028 return tmp;
01029 }
01030
01031 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
01032 {
01033 iks *request, *session = NULL;
01034 int res = -1;
01035
01036 request = iks_new("iq");
01037 if (request) {
01038 iks_insert_attrib(request, "type", "set");
01039 iks_insert_attrib(request, "from", p->us);
01040 iks_insert_attrib(request, "to", p->them);
01041 iks_insert_attrib(request, "id", client->connection->mid);
01042 ast_aji_increment_mid(client->connection->mid);
01043 session = iks_new("session");
01044 if (session) {
01045 iks_insert_attrib(session, "type", action);
01046 iks_insert_attrib(session, "id", p->sid);
01047 iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them);
01048 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
01049 iks_insert_node(request, session);
01050 iks_send(client->connection->p, request);
01051 iks_delete(session);
01052 res = 0;
01053 }
01054 iks_delete(request);
01055 }
01056 return res;
01057 }
01058
01059 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
01060 {
01061 struct gtalk_candidate *last;
01062 while (candidate) {
01063 last = candidate;
01064 candidate = candidate->next;
01065 free(last);
01066 }
01067 }
01068
01069 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
01070 {
01071 struct gtalk_pvt *cur, *prev = NULL;
01072 cur = client->p;
01073 while (cur) {
01074 if (cur == p) {
01075 if (prev)
01076 prev->next = p->next;
01077 else
01078 client->p = p->next;
01079 break;
01080 }
01081 prev = cur;
01082 cur = cur->next;
01083 }
01084 if (p->ringrule)
01085 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01086 if (p->owner)
01087 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01088 if (p->rtp)
01089 ast_rtp_destroy(p->rtp);
01090 if (p->vrtp)
01091 ast_rtp_destroy(p->vrtp);
01092 gtalk_free_candidates(p->theircandidates);
01093 free(p);
01094 }
01095
01096
01097 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
01098 {
01099 struct gtalk_pvt *p, *tmp = client->p;
01100 struct ast_channel *chan;
01101 int res;
01102 iks *codec;
01103 char *from = NULL;
01104
01105 from = iks_find_attrib(pak->x,"to");
01106 if(!from)
01107 from = client->connection->jid->full;
01108
01109 while (tmp) {
01110 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01111 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01112 gtalk_response(client, from, pak, "out-of-order", NULL);
01113 return -1;
01114 }
01115 tmp = tmp->next;
01116 }
01117
01118 p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
01119 if (!p) {
01120 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01121 return -1;
01122 }
01123 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
01124 if (chan) {
01125 ast_mutex_lock(&p->lock);
01126 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01127 if (iks_find_attrib(pak->query, "id")) {
01128 ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
01129 sizeof(p->sid));
01130 }
01131
01132 codec = iks_child(iks_child(iks_child(pak->x)));
01133 while (codec) {
01134 ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
01135 ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio",
01136 iks_find_attrib(codec, "name"), 0);
01137 codec = iks_next(codec);
01138 }
01139
01140 ast_mutex_unlock(&p->lock);
01141 ast_setstate(chan, AST_STATE_RING);
01142 res = ast_pbx_start(chan);
01143
01144 switch (res) {
01145 case AST_PBX_FAILED:
01146 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01147 gtalk_response(client, from, pak, "service-unavailable", NULL);
01148 break;
01149 case AST_PBX_CALL_LIMIT:
01150 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01151 gtalk_response(client, from, pak, "service-unavailable", NULL);
01152 break;
01153 case AST_PBX_SUCCESS:
01154 gtalk_response(client, from, pak, NULL, NULL);
01155 gtalk_invite_response(p, p->them, p->us,p->sid, 0);
01156 gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01157
01158 break;
01159 }
01160 } else {
01161 gtalk_free_pvt(client, p);
01162 }
01163 return 1;
01164 }
01165
01166 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
01167 {
01168 struct gtalk_candidate *tmp;
01169 struct hostent *hp;
01170 struct ast_hostent ahp;
01171 struct sockaddr_in sin;
01172 struct sockaddr_in aux;
01173
01174 if (time(NULL) == p->laststun)
01175 return 0;
01176
01177 tmp = p->theircandidates;
01178 p->laststun = time(NULL);
01179 while (tmp) {
01180 char username[256];
01181
01182
01183 hp = ast_gethostbyname(tmp->ip, &ahp);
01184 sin.sin_family = AF_INET;
01185 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01186 sin.sin_port = htons(tmp->port);
01187 snprintf(username, sizeof(username), "%s%s", tmp->username,
01188 p->ourcandidates->username);
01189
01190
01191 ast_rtp_get_peer(p->rtp, &aux);
01192
01193
01194
01195
01196 if (aux.sin_addr.s_addr &&
01197 aux.sin_addr.s_addr != sin.sin_addr.s_addr)
01198 ast_rtp_stun_request(p->rtp, &aux, username);
01199 else
01200 ast_rtp_stun_request(p->rtp, &sin, username);
01201
01202 if (aux.sin_addr.s_addr && option_debug > 3) {
01203 ast_log(LOG_DEBUG, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01204 ast_log(LOG_DEBUG, "Sending STUN request to %s\n", tmp->ip);
01205 }
01206
01207 tmp = tmp->next;
01208 }
01209 return 1;
01210 }
01211
01212 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
01213 {
01214 struct gtalk_pvt *p = NULL, *tmp = NULL;
01215 struct aji_client *c = client->connection;
01216 struct gtalk_candidate *newcandidate = NULL;
01217 iks *traversenodes = NULL, *receipt = NULL;
01218 char *from;
01219
01220 from = iks_find_attrib(pak->x,"to");
01221 if(!from)
01222 from = c->jid->full;
01223
01224 for (tmp = client->p; tmp; tmp = tmp->next) {
01225 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01226 p = tmp;
01227 break;
01228 }
01229 }
01230
01231 if (!p)
01232 return -1;
01233
01234 traversenodes = pak->query;
01235 while(traversenodes) {
01236 if(!strcasecmp(iks_name(traversenodes), "session")) {
01237 traversenodes = iks_child(traversenodes);
01238 continue;
01239 }
01240 if(!strcasecmp(iks_name(traversenodes), "transport")) {
01241 traversenodes = iks_child(traversenodes);
01242 continue;
01243 }
01244 if(!strcasecmp(iks_name(traversenodes), "candidate")) {
01245 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01246 if (!newcandidate)
01247 return 0;
01248 ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
01249 sizeof(newcandidate->name));
01250 ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
01251 sizeof(newcandidate->ip));
01252 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01253 ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
01254 sizeof(newcandidate->username));
01255 ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
01256 sizeof(newcandidate->password));
01257 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01258 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
01259 newcandidate->protocol = AJI_PROTOCOL_UDP;
01260 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
01261 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01262
01263 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
01264 newcandidate->type = AJI_CONNECT_STUN;
01265 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
01266 newcandidate->type = AJI_CONNECT_LOCAL;
01267 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
01268 newcandidate->type = AJI_CONNECT_RELAY;
01269 ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
01270 sizeof(newcandidate->network));
01271 newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
01272 newcandidate->next = NULL;
01273
01274 newcandidate->next = p->theircandidates;
01275 p->theircandidates = newcandidate;
01276 p->laststun = 0;
01277 gtalk_update_stun(p->parent, p);
01278 newcandidate = NULL;
01279 }
01280 traversenodes = iks_next(traversenodes);
01281 }
01282
01283 receipt = iks_new("iq");
01284 iks_insert_attrib(receipt, "type", "result");
01285 iks_insert_attrib(receipt, "from", from);
01286 iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
01287 iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
01288 iks_send(c->p, receipt);
01289 iks_delete(receipt);
01290
01291 return 1;
01292 }
01293
01294 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
01295 {
01296 struct ast_frame *f;
01297
01298 if (!p->rtp)
01299 return &ast_null_frame;
01300 f = ast_rtp_read(p->rtp);
01301 gtalk_update_stun(p->parent, p);
01302 if (p->owner) {
01303
01304 if (f->frametype == AST_FRAME_VOICE) {
01305 if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01306 if (option_debug)
01307 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
01308 p->owner->nativeformats =
01309 (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
01310 ast_set_read_format(p->owner, p->owner->readformat);
01311 ast_set_write_format(p->owner, p->owner->writeformat);
01312 }
01313
01314
01315
01316
01317
01318 }
01319 }
01320 return f;
01321 }
01322
01323 static struct ast_frame *gtalk_read(struct ast_channel *ast)
01324 {
01325 struct ast_frame *fr;
01326 struct gtalk_pvt *p = ast->tech_pvt;
01327
01328 ast_mutex_lock(&p->lock);
01329 fr = gtalk_rtp_read(ast, p);
01330 ast_mutex_unlock(&p->lock);
01331 return fr;
01332 }
01333
01334
01335 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
01336 {
01337 struct gtalk_pvt *p = ast->tech_pvt;
01338 int res = 0;
01339
01340 switch (frame->frametype) {
01341 case AST_FRAME_VOICE:
01342 if (!(frame->subclass & ast->nativeformats)) {
01343 ast_log(LOG_WARNING,
01344 "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01345 frame->subclass, ast->nativeformats, ast->readformat,
01346 ast->writeformat);
01347 return 0;
01348 }
01349 if (p) {
01350 ast_mutex_lock(&p->lock);
01351 if (p->rtp) {
01352 res = ast_rtp_write(p->rtp, frame);
01353 }
01354 ast_mutex_unlock(&p->lock);
01355 }
01356 break;
01357 case AST_FRAME_VIDEO:
01358 if (p) {
01359 ast_mutex_lock(&p->lock);
01360 if (p->vrtp) {
01361 res = ast_rtp_write(p->vrtp, frame);
01362 }
01363 ast_mutex_unlock(&p->lock);
01364 }
01365 break;
01366 case AST_FRAME_IMAGE:
01367 return 0;
01368 break;
01369 default:
01370 ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01371 frame->frametype);
01372 return 0;
01373 }
01374
01375 return res;
01376 }
01377
01378 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01379 {
01380 struct gtalk_pvt *p = newchan->tech_pvt;
01381 ast_mutex_lock(&p->lock);
01382
01383 if ((p->owner != oldchan)) {
01384 ast_mutex_unlock(&p->lock);
01385 return -1;
01386 }
01387 if (p->owner == oldchan)
01388 p->owner = newchan;
01389 ast_mutex_unlock(&p->lock);
01390 return 0;
01391 }
01392
01393 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01394 {
01395 int res = 0;
01396
01397 switch (condition) {
01398 case AST_CONTROL_HOLD:
01399 ast_moh_start(ast, data, NULL);
01400 break;
01401 case AST_CONTROL_UNHOLD:
01402 ast_moh_stop(ast);
01403 break;
01404 default:
01405 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01406 res = -1;
01407 }
01408
01409 return res;
01410 }
01411
01412 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
01413 {
01414 return gtalk_digit(chan, digit, 0);
01415 }
01416
01417 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01418 {
01419 return gtalk_digit(chan, digit, duration);
01420 }
01421
01422 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
01423 {
01424 struct gtalk_pvt *p = ast->tech_pvt;
01425 struct gtalk *client = p->parent;
01426 iks *iq, *gtalk, *dtmf;
01427 char buffer[2] = {digit, '\0'};
01428 iq = iks_new("iq");
01429 gtalk = iks_new("gtalk");
01430 dtmf = iks_new("dtmf");
01431 if(!iq || !gtalk || !dtmf) {
01432 if(iq)
01433 iks_delete(iq);
01434 if(gtalk)
01435 iks_delete(gtalk);
01436 if(dtmf)
01437 iks_delete(dtmf);
01438 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01439 return -1;
01440 }
01441
01442 iks_insert_attrib(iq, "type", "set");
01443 iks_insert_attrib(iq, "to", p->them);
01444 iks_insert_attrib(iq, "from", p->us);
01445 iks_insert_attrib(iq, "id", client->connection->mid);
01446 ast_aji_increment_mid(client->connection->mid);
01447 iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01448 iks_insert_attrib(gtalk, "action", "session-info");
01449 iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them);
01450 iks_insert_attrib(gtalk, "sid", p->sid);
01451 iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01452 iks_insert_attrib(dtmf, "code", buffer);
01453 iks_insert_node(iq, gtalk);
01454 iks_insert_node(gtalk, dtmf);
01455
01456 ast_mutex_lock(&p->lock);
01457 if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01458 iks_insert_attrib(dtmf, "action", "button-down");
01459 } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01460 iks_insert_attrib(dtmf, "action", "button-up");
01461 }
01462 iks_send(client->connection->p, iq);
01463 iks_delete(iq);
01464 iks_delete(gtalk);
01465 iks_delete(dtmf);
01466 ast_mutex_unlock(&p->lock);
01467 return 0;
01468 }
01469
01470 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
01471 {
01472 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01473
01474 return -1;
01475 }
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
01498 {
01499 struct gtalk_pvt *p = ast->tech_pvt;
01500
01501 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01502 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01503 return -1;
01504 }
01505
01506 ast_setstate(ast, AST_STATE_RING);
01507 p->jointcapability = p->capability;
01508 if (!p->ringrule) {
01509 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01510 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01511 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01512 } else
01513 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01514
01515 gtalk_invite(p, p->them, p->us, p->sid, 1);
01516 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
01517
01518 return 0;
01519 }
01520
01521
01522 static int gtalk_hangup(struct ast_channel *ast)
01523 {
01524 struct gtalk_pvt *p = ast->tech_pvt;
01525 struct gtalk *client;
01526
01527 ast_mutex_lock(&p->lock);
01528 client = p->parent;
01529 p->owner = NULL;
01530 ast->tech_pvt = NULL;
01531 if (!p->alreadygone)
01532 gtalk_action(client, p, "terminate");
01533 ast_mutex_unlock(&p->lock);
01534
01535 gtalk_free_pvt(client, p);
01536 ast_module_unref(ast_module_info->self);
01537
01538 return 0;
01539 }
01540
01541
01542 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause)
01543 {
01544 struct gtalk_pvt *p = NULL;
01545 struct gtalk *client = NULL;
01546 char *sender = NULL, *to = NULL, *s = NULL;
01547 struct ast_channel *chan = NULL;
01548
01549 if (data) {
01550 s = ast_strdupa(data);
01551 if (s) {
01552 sender = strsep(&s, "/");
01553 if (sender && (sender[0] != '\0'))
01554 to = strsep(&s, "/");
01555 if (!to) {
01556 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01557 return NULL;
01558 }
01559 }
01560 }
01561 client = find_gtalk(to, sender);
01562 if (!client) {
01563 ast_log(LOG_WARNING, "Could not find recipient.\n");
01564 return NULL;
01565 }
01566 ASTOBJ_WRLOCK(client);
01567 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01568 if (p)
01569 chan = gtalk_new(client, p, AST_STATE_DOWN, to);
01570
01571 ASTOBJ_UNLOCK(client);
01572 return chan;
01573 }
01574
01575
01576 static int gtalk_show_channels(int fd, int argc, char **argv)
01577 {
01578 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
01579 struct gtalk_pvt *p;
01580 struct ast_channel *chan;
01581 int numchans = 0;
01582 char them[AJI_MAX_JIDLEN];
01583 char *jid = NULL;
01584 char *resource = NULL;
01585
01586 if (argc != 3)
01587 return RESULT_SHOWUSAGE;
01588
01589 ast_mutex_lock(>alklock);
01590 ast_cli(fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01591 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01592 ASTOBJ_WRLOCK(iterator);
01593 p = iterator->p;
01594 while(p) {
01595 chan = p->owner;
01596 ast_copy_string(them, p->them, sizeof(them));
01597 jid = them;
01598 resource = strchr(them, '/');
01599 if (!resource)
01600 resource = "None";
01601 else {
01602 *resource = '\0';
01603 resource ++;
01604 }
01605 if (chan)
01606 ast_cli(fd, FORMAT,
01607 chan->name,
01608 jid,
01609 resource,
01610 ast_getformatname(chan->readformat),
01611 ast_getformatname(chan->writeformat)
01612 );
01613 else
01614 ast_log(LOG_WARNING, "No available channel\n");
01615 numchans ++;
01616 p = p->next;
01617 }
01618 ASTOBJ_UNLOCK(iterator);
01619 });
01620
01621 ast_mutex_unlock(>alklock);
01622
01623 ast_cli(fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01624 return RESULT_SUCCESS;
01625 #undef FORMAT
01626 }
01627
01628
01629 static int gtalk_do_reload(int fd, int argc, char **argv)
01630 {
01631 ast_verbose("IT DOES WORK!\n");
01632 return RESULT_SUCCESS;
01633 }
01634
01635 static int gtalk_parser(void *data, ikspak *pak)
01636 {
01637 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01638
01639 if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
01640
01641 gtalk_newcall(client, pak);
01642 } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
01643 if (option_debug > 2)
01644 ast_log(LOG_DEBUG, "About to add candidate!\n");
01645 gtalk_add_candidate(client, pak);
01646 if (option_debug > 2)
01647 ast_log(LOG_DEBUG, "Candidate Added!\n");
01648 } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
01649 gtalk_is_answered(client, pak);
01650 } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
01651 gtalk_is_accepted(client, pak);
01652 } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
01653 gtalk_handle_dtmf(client, pak);
01654 } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
01655 gtalk_hangup_farend(client, pak);
01656 } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
01657 gtalk_hangup_farend(client, pak);
01658 }
01659 ASTOBJ_UNREF(client, gtalk_member_destroy);
01660 return IKS_FILTER_EAT;
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
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
01712 struct ast_codec_pref prefs, char *context,
01713 struct gtalk *member)
01714 {
01715 struct aji_client *client;
01716
01717 if (!member)
01718 ast_log(LOG_WARNING, "Out of memory.\n");
01719
01720 ast_copy_string(member->name, label, sizeof(member->name));
01721 ast_copy_string(member->user, label, sizeof(member->user));
01722 ast_copy_string(member->context, context, sizeof(member->context));
01723 member->allowguest = allowguest;
01724 member->prefs = prefs;
01725 while (var) {
01726 #if 0
01727 struct gtalk_candidate *candidate = NULL;
01728 #endif
01729 if (!strcasecmp(var->name, "username"))
01730 ast_copy_string(member->user, var->value, sizeof(member->user));
01731 else if (!strcasecmp(var->name, "disallow"))
01732 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
01733 else if (!strcasecmp(var->name, "allow"))
01734 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
01735 else if (!strcasecmp(var->name, "context"))
01736 ast_copy_string(member->context, var->value, sizeof(member->context));
01737 #if 0
01738 else if (!strcasecmp(var->name, "candidate")) {
01739 candidate = gtalk_create_candidate(var->value);
01740 if (candidate) {
01741 candidate->next = member->ourcandidates;
01742 member->ourcandidates = candidate;
01743 }
01744 }
01745 #endif
01746 else if (!strcasecmp(var->name, "connection")) {
01747 if ((client = ast_aji_get_client(var->value))) {
01748 member->connection = client;
01749 iks_filter_add_rule(client->f, gtalk_parser, member,
01750 IKS_RULE_TYPE, IKS_PAK_IQ,
01751 IKS_RULE_FROM_PARTIAL, member->user,
01752 IKS_RULE_NS, "http://www.google.com/session",
01753 IKS_RULE_DONE);
01754
01755 } else {
01756 ast_log(LOG_ERROR, "connection referenced not found!\n");
01757 return 0;
01758 }
01759 }
01760 var = var->next;
01761 }
01762 if (member->connection && member->user)
01763 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
01764 else {
01765 ast_log(LOG_ERROR, "No Connection or Username!\n");
01766 }
01767 return 1;
01768 }
01769
01770 static int gtalk_load_config(void)
01771 {
01772 char *cat = NULL;
01773 struct ast_config *cfg = NULL;
01774 char context[AST_MAX_CONTEXT];
01775 int allowguest = 1;
01776 struct ast_variable *var;
01777 struct gtalk *member;
01778 struct ast_codec_pref prefs;
01779 struct aji_client_container *clients;
01780 struct gtalk_candidate *global_candidates = NULL;
01781 struct hostent *hp;
01782 struct ast_hostent ahp;
01783
01784 cfg = ast_config_load(GOOGLE_CONFIG);
01785 if (!cfg)
01786 return 0;
01787
01788
01789 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01790
01791 cat = ast_category_browse(cfg, NULL);
01792 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
01793
01794 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
01795 continue;
01796
01797 if (!strcasecmp(var->name, "allowguest"))
01798 allowguest =
01799 (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
01800 else if (!strcasecmp(var->name, "disallow"))
01801 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
01802 else if (!strcasecmp(var->name, "allow"))
01803 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
01804 else if (!strcasecmp(var->name, "context"))
01805 ast_copy_string(context, var->value, sizeof(context));
01806 else if (!strcasecmp(var->name, "bindaddr")) {
01807 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
01808 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
01809 } else {
01810 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
01811 }
01812 }
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823 }
01824 while (cat) {
01825 if (strcasecmp(cat, "general")) {
01826 var = ast_variable_browse(cfg, cat);
01827 member = (struct gtalk *) malloc(sizeof(struct gtalk));
01828 memset(member, 0, sizeof(struct gtalk));
01829 ASTOBJ_INIT(member);
01830 ASTOBJ_WRLOCK(member);
01831 if (!strcasecmp(cat, "guest")) {
01832 ast_copy_string(member->name, "guest", sizeof(member->name));
01833 ast_copy_string(member->user, "guest", sizeof(member->user));
01834 ast_copy_string(member->context, context, sizeof(member->context));
01835 member->allowguest = allowguest;
01836 member->prefs = prefs;
01837 while (var) {
01838 if (!strcasecmp(var->name, "disallow"))
01839 ast_parse_allow_disallow(&member->prefs, &member->capability,
01840 var->value, 0);
01841 else if (!strcasecmp(var->name, "allow"))
01842 ast_parse_allow_disallow(&member->prefs, &member->capability,
01843 var->value, 1);
01844 else if (!strcasecmp(var->name, "context"))
01845 ast_copy_string(member->context, var->value,
01846 sizeof(member->context));
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857 var = var->next;
01858 }
01859 ASTOBJ_UNLOCK(member);
01860 clients = ast_aji_get_clients();
01861 if (clients) {
01862 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
01863 ASTOBJ_WRLOCK(iterator);
01864 ASTOBJ_WRLOCK(member);
01865 member->connection = iterator;
01866 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://www.google.com/session", IKS_RULE_DONE);
01867 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);
01868 ASTOBJ_UNLOCK(member);
01869 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01870 ASTOBJ_UNLOCK(iterator);
01871 });
01872 } else {
01873 ASTOBJ_UNLOCK(member);
01874 ASTOBJ_UNREF(member, gtalk_member_destroy);
01875 }
01876 } else {
01877 ASTOBJ_UNLOCK(member);
01878 if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
01879 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01880 ASTOBJ_UNREF(member, gtalk_member_destroy);
01881 }
01882 }
01883 cat = ast_category_browse(cfg, cat);
01884 }
01885 gtalk_free_candidates(global_candidates);
01886 return 1;
01887 }
01888
01889
01890 static int load_module(void)
01891 {
01892 #ifdef HAVE_GNUTLS
01893 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
01894 #endif
01895
01896 ASTOBJ_CONTAINER_INIT(>alk_list);
01897 if (!gtalk_load_config()) {
01898 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
01899 return 0;
01900 }
01901
01902 sched = sched_context_create();
01903 if (!sched)
01904 ast_log(LOG_WARNING, "Unable to create schedule context\n");
01905
01906 io = io_context_create();
01907 if (!io)
01908 ast_log(LOG_WARNING, "Unable to create I/O context\n");
01909
01910 if (ast_find_ourip(&__ourip, bindaddr)) {
01911 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
01912 return 0;
01913 }
01914
01915 ast_rtp_proto_register(>alk_rtp);
01916 ast_cli_register_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01917
01918
01919 if (ast_channel_register(>alk_tech)) {
01920 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
01921 return -1;
01922 }
01923 return 0;
01924 }
01925
01926
01927 static int reload(void)
01928 {
01929 return 0;
01930 }
01931
01932
01933 static int unload_module(void)
01934 {
01935 struct gtalk_pvt *privates = NULL;
01936 ast_cli_unregister_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01937
01938 ast_channel_unregister(>alk_tech);
01939 ast_rtp_proto_unregister(>alk_rtp);
01940
01941 if (!ast_mutex_lock(>alklock)) {
01942
01943 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01944 ASTOBJ_WRLOCK(iterator);
01945 privates = iterator->p;
01946 while(privates) {
01947 if (privates->owner)
01948 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
01949 privates = privates->next;
01950 }
01951 iterator->p = NULL;
01952 ASTOBJ_UNLOCK(iterator);
01953 });
01954 ast_mutex_unlock(>alklock);
01955 } else {
01956 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01957 return -1;
01958 }
01959 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
01960 ASTOBJ_CONTAINER_DESTROY(>alk_list);
01961 return 0;
01962 }
01963
01964 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Gtalk Channel Driver",
01965 .load = load_module,
01966 .unload = unload_module,
01967 .reload = reload,
01968 );