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