Merged revisions 290479 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r290479 | dvossel | 2010-10-05 17:00:43 -0500 (Tue, 05 Oct 2010) | 6 lines
  
  Fixes chan_gtalk to work with gmail client
  
  This patch was written by Philippe Sultan (phsultan). Thanks
  for keeping this up to date!
........


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@290480 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
David Vossel 15 years ago
parent 096d16f3bb
commit 268ae2e8d5

@ -67,12 +67,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj.h" #include "asterisk/astobj.h"
#include "asterisk/abstract_jb.h" #include "asterisk/abstract_jb.h"
#include "asterisk/jabber.h" #include "asterisk/jabber.h"
#include "asterisk/jingle.h"
#define GOOGLE_CONFIG "gtalk.conf" #define GOOGLE_CONFIG "gtalk.conf"
#define GOOGLE_NS "http://www.google.com/session"
/*! Global jitterbuffer configuration - by default, jb is disabled */ /*! Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf = static struct ast_jb_conf default_jbconf =
{ {
@ -95,6 +93,12 @@ enum gtalk_connect_type {
AJI_CONNECT_RELAY = 3, AJI_CONNECT_RELAY = 3,
}; };
enum gtalk_client_type {
AJI_CLIENT_UNKNOWN,
AJI_CLIENT_GTALK, /*!< Remote client type is GoogleTalk */
AJI_CLIENT_GMAIL, /*!< Remote client type is Gmail */
};
struct gtalk_pvt { struct gtalk_pvt {
ast_mutex_t lock; /*!< Channel private lock */ ast_mutex_t lock; /*!< Channel private lock */
time_t laststun; time_t laststun;
@ -105,6 +109,7 @@ struct gtalk_pvt {
char ring[10]; /*!< Message ID of ring */ char ring[10]; /*!< Message ID of ring */
iksrule *ringrule; /*!< Rule for matching RING request */ iksrule *ringrule; /*!< Rule for matching RING request */
int initiator; /*!< If we're the initiator */ int initiator; /*!< If we're the initiator */
enum gtalk_client_type ctype;
int alreadygone; int alreadygone;
int capability; int capability;
struct ast_codec_pref prefs; struct ast_codec_pref prefs;
@ -391,7 +396,7 @@ static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, in
ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n"); ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
return 0; return 0;
} }
iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone"); iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
iks_insert_attrib(dcodecs, "xml:lang", "en"); iks_insert_attrib(dcodecs, "xml:lang", "en");
for (x = 0; x < 64; x++) { for (x = 0; x < 64; x++) {
@ -411,7 +416,7 @@ static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, in
iks_insert_attrib(payload_telephone, "name", "telephone-event"); iks_insert_attrib(payload_telephone, "name", "telephone-event");
iks_insert_attrib(payload_telephone, "clockrate", "8000"); iks_insert_attrib(payload_telephone, "clockrate", "8000");
} }
iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p"); iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
iks_insert_attrib(iq, "type", "set"); iks_insert_attrib(iq, "type", "set");
iks_insert_attrib(iq, "to", to); iks_insert_attrib(iq, "to", to);
@ -419,7 +424,7 @@ static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, in
iks_insert_attrib(iq, "id", client->connection->mid); iks_insert_attrib(iq, "id", client->connection->mid);
ast_aji_increment_mid(client->connection->mid); ast_aji_increment_mid(client->connection->mid);
iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session"); iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept"); iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
/* put the initiator attribute to lower case if we receive the call /* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */ * otherwise GoogleTalk won't establish the session */
@ -475,8 +480,8 @@ static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, cha
while (((c = *t) != '/') && (*t++ = tolower(c))); while (((c = *t) != '/') && (*t++ = tolower(c)));
} }
iks_insert_attrib(session, "initiator", initiator ? from : lowerto); iks_insert_attrib(session, "initiator", initiator ? from : lowerto);
iks_insert_attrib(session, "xmlns", "http://www.google.com/session"); iks_insert_attrib(session, "xmlns", GOOGLE_NS);
iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p"); iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
iks_insert_node(iq,session); iks_insert_node(iq,session);
iks_insert_node(session,transport); iks_insert_node(session,transport);
ast_aji_send(p->parent->connection, iq); ast_aji_send(p->parent->connection, iq);
@ -600,18 +605,27 @@ static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const c
static int gtalk_is_answered(struct gtalk *client, ikspak *pak) static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
{ {
struct gtalk_pvt *tmp; struct gtalk_pvt *tmp = NULL;
char *from; char *from;
iks *codec; iks *codec;
char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
int peernoncodeccapability; int peernoncodeccapability;
ast_log(LOG_DEBUG, "The client is %s\n", client->name); ast_log(LOG_DEBUG, "The client is %s\n", client->name);
/* Make sure our new call doesn't exist yet */
/* Make sure our new call does exist */
for (tmp = client->p; tmp; tmp = tmp->next) { for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
break;
} else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
break; break;
} }
}
if (tmp == 0) {
ast_log(LOG_WARNING, "Could not find session in iq\n");
return -1;
}
/* codec points to the first <payload-type/> tag */ /* codec points to the first <payload-type/> tag */
codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x))); codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
@ -751,7 +765,7 @@ static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
ast_debug(1, "The client is %s\n", client->name); ast_debug(1, "The client is %s\n", client->name);
/* Make sure our new call doesn't exist yet */ /* Make sure our new call doesn't exist yet */
for (tmp = client->p; tmp; tmp = tmp->next) { for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))
break; break;
} }
from = iks_find_attrib(pak->x, "to"); from = iks_find_attrib(pak->x, "to");
@ -796,11 +810,14 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch
if (!ours1 || !ours2) if (!ours1 || !ours2)
goto safeout; goto safeout;
iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p"); iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
iks_insert_node(iq, gtalk); iks_insert_node(iq, gtalk);
if (p->ctype == AJI_CLIENT_GMAIL) {
iks_insert_node(gtalk,candidate);
} else {
iks_insert_node(gtalk,transport); iks_insert_node(gtalk,transport);
iks_insert_node(transport, candidate); iks_insert_node(transport, candidate);
}
for (; p; p = p->next) { for (; p; p = p->next) {
if (!strcasecmp(p->sid, sid)) if (!strcasecmp(p->sid, sid))
break; break;
@ -863,7 +880,18 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch
iks_insert_attrib(iq, "type", "set"); iks_insert_attrib(iq, "type", "set");
iks_insert_attrib(iq, "id", c->mid); iks_insert_attrib(iq, "id", c->mid);
ast_aji_increment_mid(c->mid); ast_aji_increment_mid(c->mid);
switch (p->ctype) {
case AJI_CLIENT_GTALK:
iks_insert_attrib(gtalk, "type", "transport-info"); iks_insert_attrib(gtalk, "type", "transport-info");
break;
case AJI_CLIENT_GMAIL:
iks_insert_attrib(gtalk, "type", "candidates");
break;
default:
ast_log(LOG_WARNING, "Client type is unknown\n");
iks_insert_attrib(gtalk, "type", "candidates");
break;
}
iks_insert_attrib(gtalk, "id", sid); iks_insert_attrib(gtalk, "id", sid);
/* put the initiator attribute to lower case if we receive the call /* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */ * otherwise GoogleTalk won't establish the session */
@ -922,19 +950,22 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const
if (!sid && !strchr(them, '/')) { /* I started call! */ if (!sid && !strchr(them, '/')) { /* I started call! */
if (!strcasecmp(client->name, "guest")) { if (!strcasecmp(client->name, "guest")) {
buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them); buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
if (buddy) if (buddy) {
resources = buddy->resources; resources = buddy->resources;
} else if (client->buddy) }
} else if (client->buddy) {
resources = client->buddy->resources; resources = client->buddy->resources;
}
while (resources) { while (resources) {
if (resources->cap->jingle) { if (resources->cap->jingle) {
break; break;
} }
resources = resources->next; resources = resources->next;
} }
if (resources) if (resources) {
snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource); snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
else { } else {
ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n"); ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
return NULL; return NULL;
} }
@ -942,6 +973,8 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const
if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
return NULL; return NULL;
} }
/* set client type to unknown until we have more info */
tmp->ctype = AJI_CLIENT_UNKNOWN;
memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref)); memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
@ -956,6 +989,7 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const
tmp->initiator = 1; tmp->initiator = 1;
} }
/* clear codecs */ /* clear codecs */
bindaddr.sin_family = AF_INET;
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) { if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n"); ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
@ -1112,7 +1146,7 @@ static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *a
while (((c = *t) != '/') && (*t++ = tolower(c))); while (((c = *t) != '/') && (*t++ = tolower(c)));
} }
iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem); iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
iks_insert_attrib(session, "xmlns", "http://www.google.com/session"); iks_insert_attrib(session, "xmlns", GOOGLE_NS);
iks_insert_node(request, session); iks_insert_node(request, session);
ast_aji_send(client->connection, request); ast_aji_send(client->connection, request);
res = 0; res = 0;
@ -1179,7 +1213,7 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak)
from = client->connection->jid->full; from = client->connection->jid->full;
while (tmp) { while (tmp) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid)) {
ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid); ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
gtalk_response(client, from, pak, "out-of-order", NULL); gtalk_response(client, from, pak, "out-of-order", NULL);
return -1; return -1;
@ -1203,6 +1237,14 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak)
return -1; return -1;
} }
/* if the node name of the query contains a semicolon, the remote peer
* is a gmail type client. If not, treat it as a regular GoogleTalk
* client */
if (strchr(iks_name(pak->query), ':')) {
p->ctype = AJI_CLIENT_GMAIL;
} else {
p->ctype = AJI_CLIENT_GTALK;
}
chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL); chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
if (!chan) { if (!chan) {
gtalk_free_pvt(client, p); gtalk_free_pvt(client, p);
@ -1220,8 +1262,13 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak)
codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x))); codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
while (codec) { while (codec) {
if (!strcmp(iks_name(codec), "vid:payload-type") && p->vrtp) {
ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->vrtp), p->vrtp, atoi(iks_find_attrib(codec, "id")));
ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->vrtp), p->vrtp, atoi(iks_find_attrib(codec, "id")), "video", iks_find_attrib(codec, "name"), 0);
} else {
ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id"))); ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0); ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
}
codec = iks_next_tag(codec); codec = iks_next_tag(codec);
} }
@ -1256,7 +1303,9 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak)
break; break;
case AST_PBX_SUCCESS: case AST_PBX_SUCCESS:
gtalk_response(client, from, pak, NULL, NULL); gtalk_response(client, from, pak, NULL, NULL);
if (p->ctype == AJI_CLIENT_GTALK) {
gtalk_invite_response(p, p->them, p->us,p->sid, 0); gtalk_invite_response(p, p->them, p->us,p->sid, 0);
}
gtalk_create_candidates(client, p, p->sid, p->them, p->us); gtalk_create_candidates(client, p, p->sid, p->them, p->us);
/* nothing to do */ /* nothing to do */
break; break;
@ -1288,8 +1337,7 @@ static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(tmp->port); sin.sin_port = htons(tmp->port);
snprintf(username, sizeof(username), "%s%s", tmp->username, snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
p->ourcandidates->username);
/* Find out the result of the STUN */ /* Find out the result of the STUN */
ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp); ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
@ -1298,12 +1346,12 @@ static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
/* If the STUN result is different from the IP of the hostname, /* If the STUN result is different from the IP of the hostname,
lock on the stun IP of the hostname advertised by the lock on the stun IP of the hostname advertised by the
remote client */ remote client */
if (aux.sin_addr.s_addr && if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
aux.sin_addr.s_addr != sin.sin_addr.s_addr)
ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username); ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
else } else {
ast_sockaddr_from_sin(&sin_tmp, &sin);
ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
}
if (aux.sin_addr.s_addr) { if (aux.sin_addr.s_addr) {
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); 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);
ast_debug(4, "Sending STUN request to %s\n", tmp->ip); ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
@ -1327,26 +1375,30 @@ static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
from = c->jid->full; from = c->jid->full;
for (tmp = client->p; tmp; tmp = tmp->next) { for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid)) {
p = tmp; p = tmp;
break; break;
} }
} }
if (!p) if (!p) {
return -1; return -1;
}
traversenodes = pak->query; traversenodes = pak->query;
while(traversenodes) { while(traversenodes) {
if(!strcasecmp(iks_name(traversenodes), "session")) { if(!strcasecmp(iks_name(traversenodes), "session")) {
traversenodes = iks_first_tag(traversenodes); traversenodes = iks_first_tag(traversenodes);
continue; continue;
} }
if(!strcasecmp(iks_name(traversenodes), "ses:session")) {
traversenodes = iks_child(traversenodes);
continue;
}
if(!strcasecmp(iks_name(traversenodes), "transport")) { if(!strcasecmp(iks_name(traversenodes), "transport")) {
traversenodes = iks_first_tag(traversenodes); traversenodes = iks_first_tag(traversenodes);
continue; continue;
} }
if(!strcasecmp(iks_name(traversenodes), "candidate")) { if(!strcasecmp(iks_name(traversenodes), "candidate") || !strcasecmp(iks_name(traversenodes), "ses:candidate")) {
newcandidate = ast_calloc(1, sizeof(*newcandidate)); newcandidate = ast_calloc(1, sizeof(*newcandidate));
if (!newcandidate) if (!newcandidate)
return 0; return 0;
@ -1801,26 +1853,30 @@ static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
static int gtalk_parser(void *data, ikspak *pak) static int gtalk_parser(void *data, ikspak *pak)
{ {
struct gtalk *client = ASTOBJ_REF((struct gtalk *) data); struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
int res;
if (iks_find_attrib(pak->x, "type") && !strcmp(iks_find_attrib (pak->x, "type"),"error")) { if (iks_find_attrib(pak->x, "type") && !strcmp(iks_find_attrib (pak->x, "type"),"error")) {
ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n"); ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
} } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
else if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
/* New call */ /* New call */
gtalk_newcall(client, pak); gtalk_newcall(client, pak);
} else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) { } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
ast_debug(3, "About to add candidate!\n"); ast_debug(3, "About to add candidate!\n");
gtalk_add_candidate(client, pak); res = gtalk_add_candidate(client, pak);
if (!res) {
ast_log(LOG_WARNING, "Could not add any candidate\n");
} else {
ast_debug(3, "Candidate Added!\n"); ast_debug(3, "Candidate Added!\n");
} else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) { }
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
gtalk_is_answered(client, pak); gtalk_is_answered(client, pak);
} else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) { } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
gtalk_is_accepted(client, pak); gtalk_is_accepted(client, pak);
} else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) { } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
gtalk_handle_dtmf(client, pak); gtalk_handle_dtmf(client, pak);
} else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) { } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
gtalk_hangup_farend(client, pak); gtalk_hangup_farend(client, pak);
} else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) { } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
gtalk_hangup_farend(client, pak); gtalk_hangup_farend(client, pak);
} }
ASTOBJ_UNREF(client, gtalk_member_destroy); ASTOBJ_UNREF(client, gtalk_member_destroy);
@ -1917,7 +1973,7 @@ static int gtalk_create_member(char *label, struct ast_variable *var, int allowg
iks_filter_add_rule(client->f, gtalk_parser, member, iks_filter_add_rule(client->f, gtalk_parser, member,
IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_TYPE, IKS_PAK_IQ,
IKS_RULE_FROM_PARTIAL, member->user, IKS_RULE_FROM_PARTIAL, member->user,
IKS_RULE_NS, "http://www.google.com/session", IKS_RULE_NS, GOOGLE_NS,
IKS_RULE_DONE); IKS_RULE_DONE);
} else { } else {
@ -2042,7 +2098,7 @@ static int gtalk_load_config(void)
ASTOBJ_WRLOCK(iterator); ASTOBJ_WRLOCK(iterator);
ASTOBJ_WRLOCK(member); ASTOBJ_WRLOCK(member);
member->connection = NULL; member->connection = NULL;
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); iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
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); 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);
ASTOBJ_UNLOCK(member); ASTOBJ_UNLOCK(member);
ASTOBJ_UNLOCK(iterator); ASTOBJ_UNLOCK(iterator);

@ -72,6 +72,7 @@
*/ */
#define AJI_MAX_JIDLEN 3071 #define AJI_MAX_JIDLEN 3071
#define AJI_MAX_RESJIDLEN 1023 #define AJI_MAX_RESJIDLEN 1023
#define AJI_MAX_ATTRLEN 256
#define MUC_NS "http://jabber.org/protocol/muc" #define MUC_NS "http://jabber.org/protocol/muc"

@ -44,6 +44,9 @@
#define JINGLE_DTMF_NS "urn:xmpp:tmp:jingle:dtmf" #define JINGLE_DTMF_NS "urn:xmpp:tmp:jingle:dtmf"
#define GOOGLE_NS "http://www.google.com/session" #define GOOGLE_NS "http://www.google.com/session"
#define GOOGLE_AUDIO_NS "http://www.google.com/session/phone"
#define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
#define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
#define JINGLE_SID "sid" #define JINGLE_SID "sid"
#define GOOGLE_SID "id" #define GOOGLE_SID "id"

@ -569,8 +569,16 @@ static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *nam
static int gtalk_yuck(iks *node) static int gtalk_yuck(iks *node)
{ {
if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) { if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
ast_debug(1, "Found resource with Googletalk voice capabilities\n");
return 1;
} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
return 1;
} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
return 1; return 1;
} }
return 0; return 0;
} }
@ -1577,6 +1585,23 @@ static int aji_act_hook(void *data, int type, iks *node)
pak = iks_packet(node); pak = iks_packet(node);
/* work around iksemel's impossibility to recognize node names
* containing a semicolon. Set the namespace of the corresponding
* node accordingly. */
if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
char *node_ns = NULL;
char attr[AJI_MAX_ATTRLEN];
char *node_name = iks_name(iks_child(node));
char *aux = strchr(node_name, ':') + 1;
snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
node_ns = iks_find_attrib(iks_child(node), attr);
if (node_ns) {
pak->ns = node_ns;
pak->query = iks_child(node);
}
}
if (!client->component) { /*client */ if (!client->component) { /*client */
switch (type) { switch (type) {
case IKS_NODE_START: case IKS_NODE_START:
@ -2405,7 +2430,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
if (gtalk_yuck(pak->x)) { /* gtalk should do discover */ if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
found->cap->jingle = 1; found->cap->jingle = 1;
} }
if (found->cap->jingle && option_debug > 4) { if (found->cap->jingle) {
ast_debug(1, "Special case for google till they support discover.\n"); ast_debug(1, "Special case for google till they support discover.\n");
} else { } else {
iks *iq, *query; iks *iq, *query;

Loading…
Cancel
Save