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