[asterisk-commits] phsultan: branch phsultan/jabberreceive r121558 - in /team/phsultan/jabberrec...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jun 10 10:07:44 CDT 2008


Author: phsultan
Date: Tue Jun 10 10:07:44 2008
New Revision: 121558

URL: http://svn.digium.com/view/asterisk?view=rev&rev=121558
Log:
Added JabberReceive as an application, give examples of how to use the
res_jabber related functions/applications in (configs/jabber.txt).

Make SendText available for chan_gtalk.
 

Modified:
    team/phsultan/jabberreceive/channels/chan_gtalk.c
    team/phsultan/jabberreceive/doc/jabber.txt
    team/phsultan/jabberreceive/res/res_jabber.c

Modified: team/phsultan/jabberreceive/channels/chan_gtalk.c
URL: http://svn.digium.com/view/asterisk/team/phsultan/jabberreceive/channels/chan_gtalk.c?view=diff&rev=121558&r1=121557&r2=121558
==============================================================================
--- team/phsultan/jabberreceive/channels/chan_gtalk.c (original)
+++ team/phsultan/jabberreceive/channels/chan_gtalk.c Tue Jun 10 10:07:44 2008
@@ -166,6 +166,7 @@
 /* Forward declarations */
 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
+static int gtalk_sendtext(struct ast_channel *ast, const char *text);
 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
@@ -194,6 +195,7 @@
 	.description = "Gtalk Channel Driver",
 	.capabilities = AST_FORMAT_AUDIO_MASK,
 	.requester = gtalk_request,
+	.send_text = gtalk_sendtext,
 	.send_digit_begin = gtalk_digit_begin,
 	.send_digit_end = gtalk_digit_end,
 	.bridge = ast_rtp_bridge,
@@ -1459,6 +1461,25 @@
 	}
 
 	return res;
+}
+
+static int gtalk_sendtext(struct ast_channel *chan, const char *text)
+{
+	struct aji_client *client = NULL;
+	struct gtalk_pvt *p = chan->tech_pvt;
+	
+
+	if (!p->parent) {
+		ast_log(LOG_ERROR, "Parent channel not found\n");
+		return -1;
+	}
+	if (!p->parent->connection) {
+		ast_log(LOG_ERROR, "XMPP client not found\n");
+		return -1;
+	}
+	client = p->parent->connection;
+	ast_aji_send_chat(client, p->them, text);
+	return 0;
 }
 
 static int gtalk_digit_begin(struct ast_channel *chan, char digit)

Modified: team/phsultan/jabberreceive/doc/jabber.txt
URL: http://svn.digium.com/view/asterisk/team/phsultan/jabberreceive/doc/jabber.txt?view=diff&rev=121558&r1=121557&r2=121558
==============================================================================
--- team/phsultan/jabberreceive/doc/jabber.txt (original)
+++ team/phsultan/jabberreceive/doc/jabber.txt Tue Jun 10 10:07:44 2008
@@ -1,15 +1,91 @@
-(res_jabber is very experimental!)
-
-Jabber(xmpp) is an xml based protocol primarily for presence and messaging.
+XMPP (Jabber) is an xml based protocol primarily for presence and messaging.
 It is an open standard and there are several open server implementations,
 ejabberd, jabberd(2), wildfire, and many others, as well as several open source
-clients, Psi, gajim, gaim etc.  Jabber differs from other IM applications as it
+clients, Psi, gajim, gaim etc. XMPP differs from other IM applications as it
 is immensly extendable.  This allows us to easily integrate Asterisk with 
-jabber.  The Asterisk Jabber Interface is provided by res_jabber.so.  res_jabber 
-allows for Asterisk to connect to any jabber server via the standard client
-protocol or also as a simple client.  Several simple functions are exposed to
-the dial plan, jabberstatus, jabbersend, and soon jabberrecv.  res_jabber is also used
-to provide the connection interface for chan_jingle.
+XMPP. The Asterisk XMPP Interface is provided by res_jabber.so.
 
-The maintainer of res_jabber is Matthew O'Gorman <mogorman at digium.com> or
-mog_work on irc or (preferred) mogorman at astjab.org over jabber.
+res_jabber allows for Asterisk to connect to any jabber server via the 
+standard client protocol or also as a simple client. 
+
+res_jabber is also used to provide the connection interface for chan_jingle.
+
+A function (JABBER_STATUS) and two applications (JabberSend and
+JabberReceive) are exposed to the dialplan.
+
+You'll find examples of how to use these function/applications
+hereafter. We assume that 'asterisk-xmpp' is properly configured in
+jabber.conf.
+
+**** JABBER_STATUS ****
+
+Note : as of version 1.6, the corresponding application JabberStatus is still
+available.
+
+JABBER_STATUS stores the status of a buddy in a dialplan variable for
+further use. Here is an AEL example of how to use it :
+
+1234 => {
+         JabberStatus(asterisk-xmpp,buddy at gmail.com,STATUS);
+         if (${STATUS}=1) {
+                   NoOp(User is online and active, ring his Gtalk client.);
+                   Dial(Gtalk/asterisk-xmpp/buddy at gmail.com);
+         } else {
+                   NoOp(Prefer the SIP phone);
+                   Dial(SIP/1234);
+         }
+}
+
+**** JabberSend ****
+
+JabberSend sends an XMPP message to a buddy. Ex. (call notification) :
+
+context default {
+	_XXXX => {
+	      JabberSend(asterisk-xmpp,buddy at gmail.com,${CALLERID(name)} is calling ${EXTEN});
+	      
+	      Dial(SIP/${EXTEN}, 30);
+	      Hangup();
+	}
+}
+
+**** JabberReceive ****
+
+JabberReceive waits for an XMPP message from an XMPP buddy and passes
+it to dialplan variable. It makes a Jingle to
+SIP/H323/MGCP/PSTN/... gateway out of Asterisk. In this example, a
+user initiates a Gtalk voice call to Asterisk through his/her
+GoogleTalk client. Asterisk establishes the call and starts a
+chat conversation with the user to ask for a number to dial :
+
+context gtalk-in {
+	s => {
+	  NoOp(Caller id : ${CALLERID(all)});
+	  Answer();
+	  JabberSend(asterisk-xmpp,${CALLERID(name),Please enter the number you wish to call);
+	  JabberReceive(${CALLERID(name)},NEWEXTEN);
+	  JabberSend(asterisk-xmpp,$(CALLERID(name),(Calling ${NEWEXTEN} ...);
+	  Dial(SIP/${NEWEXTEN);
+	  Hangup(); 
+	}
+}
+
+A shorter version for this snippet, that takes advantage of the
+SendText application (available for chan_gtalk) :
+
+context gtalk-in {
+	s => {
+	  NoOp(Caller id : ${CALLERID(all)});
+	  Answer();
+	  SendText(Please enter the number you wish to call);
+	  JabberReceive(${CALLERID(name)},NEWEXTEN);
+	  SendText(Calling ${NEWEXTEN} ...);
+	  Dial(SIP/${NEWEXTEN);
+	  Hangup(); 
+	}
+}
+
+The maintainers of res_jabber are Matthew O'Gorman
+<mogorman at digium.com> (mog_work on irc or mogorman at astjab.org over
+XMPP) and Philippe Sultan <philippe.sultan at inria.fr> (address
+reachable over email, SIP and XMPP).

Modified: team/phsultan/jabberreceive/res/res_jabber.c
URL: http://svn.digium.com/view/asterisk/team/phsultan/jabberreceive/res/res_jabber.c?view=diff&rev=121558&r1=121557&r2=121558
==============================================================================
--- team/phsultan/jabberreceive/res/res_jabber.c (original)
+++ team/phsultan/jabberreceive/res/res_jabber.c Tue Jun 10 10:07:44 2008
@@ -70,6 +70,7 @@
 static void aji_client_destroy(struct aji_client *obj);
 static int aji_send_exec(struct ast_channel *chan, void *data);
 static int aji_status_exec(struct ast_channel *chan, void *data);
+static int aji_recv_exec(struct ast_channel *chan, void *data);
 static int aji_is_secure(struct aji_client *client);
 static int aji_start_tls(struct aji_client *client);
 static int aji_tls_handshake(struct aji_client *client);
@@ -129,22 +130,32 @@
 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
 
 static char *ajisend_descrip =
-"JabberSend(Jabber,ScreenName,Message)\n"
-"  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
-"  ScreenName - User Name to message.\n" 
+"JabberSend(Jabber,JID,Message)\n"
+"  Jabber  - Client or transport Asterisk uses to connect to Jabber\n" 
+"  JID     - Jabber ID of the buddy to send message to\n" 
 "  Message - Message to be sent to the buddy\n";
 
 static char *app_ajistatus = "JabberStatus";
 
-static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
+static char *ajistatus_synopsis = "JabberStatus(Jabber,JID,Variable)";
 
 static char *ajistatus_descrip =
-"JabberStatus(Jabber,ScreenName,Variable)\n"
-"  Jabber - Client or transport Asterisk uses to connect to Jabber\n"
-"  ScreenName - User Name to retrieve status from.\n"
+"JabberStatus(Jabber,JID,Variable)\n"
+"  Jabber   - Client or transport Asterisk uses to connect to Jabber\n"
+"  JID      - Jabber ID of the buddy to retrieve status from\n"
 "  Variable - Variable to store presence in will be 1-6.\n" 
 "             In order, Online, Chatty, Away, XAway, DND, Offline\n" 
 "             If not in roster variable will = 7\n";
+
+static char *app_ajirecv = "JabberReceive";
+
+static char *ajirecv_synopsis = "JabberReceive(Variable)";
+
+static char *ajirecv_descrip =
+"JabberReceive(JID,Variable[,timeout])\n"
+"  JID      - Jabber ID of the buddy to receive message from\n" 
+"  Variable - Variable to store message in\n"
+"  timeout  - Defaults to 20s\n" ;
 
 struct aji_client_container clients;
 struct aji_capabilities *capabilities = NULL;
@@ -758,6 +769,59 @@
 		return ret;	
 
 	return IKS_OK;
+}
+
+ /*!
+ * \brief Dial plan function to receive a message.
+ * \param channel, and data, data is sender, variable.
+ * \return received text or NULL.
+ */
+static int aji_recv_exec(struct ast_channel *chan, void *data)
+{
+	char message[AST_MAX_EXTENSION];
+	char *buf, *parse, *variable = NULL;
+	int to; /* timeout */
+	
+	AST_DECLARE_APP_ARGS(args,
+			     AST_APP_ARG(sender);
+			     AST_APP_ARG(variable);
+			     AST_APP_ARG(timeout);
+			     );
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "%s requires arguments (sender,variable[,timeout])\n", app_ajirecv);
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (args.argc < 2 || args.argc > 3) {
+		ast_log(LOG_WARNING, "%s requires arguments (sender,variable[,timeout])\n", app_ajirecv);
+		return -1;
+	}
+
+	if (ast_strlen_zero(args.timeout)) {
+		to = 20000;
+	} else {
+		to = atoi(args.timeout);
+		if (to > 0) {
+			to *= 1000;
+		} else {
+			ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
+		}
+	}
+
+	ast_log(LOG_NOTICE, "Waiting for an XMPP message from %s\n", args.sender);
+	buf = ast_recvtext(chan, to);
+	/* return if we timed out */
+	if (!buf)
+		return -1;
+	ast_copy_string(message, buf, sizeof(message));
+	variable = ast_skip_blanks(args.variable);
+	ast_trim_blanks(variable);
+	pbx_builtin_setvar_helper(chan, variable, message);
+	return 0;
 }
 
 /*!
@@ -1466,17 +1530,63 @@
 static void aji_handle_message(struct aji_client *client, ikspak *pak)
 {
 	struct aji_message *insert, *tmp;
+	struct ast_channel *chan = NULL;
+	char *parse = NULL;
+	struct ast_frame f = { AST_FRAME_TEXT, };
 	int flag = 0;
+	AST_DECLARE_APP_ARGS(args,
+			     AST_APP_ARG(sender);
+			     AST_APP_ARG(variable);
+			     );
+
+	ast_debug(3, "client %s received a message\n", client->name);
 	
 	if (!(insert = ast_calloc(1, sizeof(*insert))))
 		return;
 	time(&insert->arrived);
-	if (iks_find_cdata(pak->x, "body"))
+	if (iks_find_cdata(pak->x, "body")) {
 		insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
-	if (pak->id)
-		ast_copy_string(insert->id, pak->id, sizeof(insert->message));
-	if (pak->from)
-		insert->from = ast_strdup(pak->from->full);
+	}
+	if (pak->id) {
+		ast_copy_string(insert->id, pak->id, sizeof(insert->id));
+	}
+	if (pak->from){
+		/* insert will furtherly be added to message list */
+ 		insert->from = ast_strdup(pak->from->full);
+	}
+	/* if we receive a message from a buddy, try to pass it to 
+	   a channel waiting for JabberReceive to return */
+	if (pak->from && iks_find_cdata(pak->x, "body")) {
+		ast_debug(3, "message comes from %s\n", insert->from);
+		
+		/* build the text frame from received message */
+		if (insert->message) {
+			f.datalen = strlen(insert->message);
+			f.data.ptr = (void *) insert->message;
+		}
+
+		while ((chan = ast_channel_walk_locked(chan))) {
+			if (!chan->data) {
+				continue;
+			}
+			parse = ast_strdupa(chan->data);
+			AST_STANDARD_APP_ARGS(args, parse);
+		
+			/* now queue the text frame only if the channel is 
+			   under control of the JabberReceive app *and* the 
+			   XMPP message comes from the configured JID */
+			if (!strcasecmp(chan->appl, "JabberReceive") && !strncmp(args.sender, pak->from->partial, strlen(pak->from->partial))) {
+				ast_debug(3, "Queuing text frame to %s\n", chan->name);				
+				ast_queue_frame(chan, &f);
+			}
+			ast_channel_unlock(chan);
+			ast_debug(3, "chan was %s \n", chan ? "FOUND" : "NOT FOUND");
+			if (chan) {
+				break;
+			}
+		}
+	}
+
 	AST_LIST_LOCK(&client->messages);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
 		if (flag) {
@@ -3002,6 +3112,7 @@
 	ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
 	ast_unregister_application(app_ajisend);
 	ast_unregister_application(app_ajistatus);
+	ast_unregister_application(app_ajirecv);
 	ast_manager_unregister("JabberSend");
 	ast_custom_function_unregister(&jabberstatus_function);
 	
@@ -3029,6 +3140,7 @@
 			"Sends a message to a Jabber Client", mandescr_jabber_send);
 	ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
 	ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
+	ast_register_application(app_ajirecv, aji_recv_exec, ajirecv_synopsis, ajirecv_descrip);
 	ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
 	ast_custom_function_register(&jabberstatus_function);
 




More information about the asterisk-commits mailing list