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