Revision
15040
Author
gled
Date
2009-10-02 04:42:09 -0500 (Fri, 02 Oct 2009)

Log Message

stream_file OK, still waiting for FSCORE-455 to get return values

Modified Paths

Diff

Modified: freeswitch/trunk/contrib/gled/esl2agi/esl2agi.c (15039 => 15040)


--- freeswitch/trunk/contrib/gled/esl2agi/esl2agi.c	2009-10-01 22:56:33 UTC (rev 15039)
+++ freeswitch/trunk/contrib/gled/esl2agi/esl2agi.c	2009-10-02 09:42:09 UTC (rev 15040)
@@ -47,7 +47,7 @@
         esl_handle_t eslC = {{0}};
 
         char script_path[1024] = "\0";
-        const char *buf;
+        char *buf;
 	int pid;
 	int thread_running;
 
@@ -94,6 +94,7 @@
 		close(pipes.socket[1]);
 		close(pipes.script[0]);
 		close(esl_req.client_sock);
+		close(STDERR_FILENO);
 
 	        dup2(pipes.socket[0], STDIN_FILENO);
         	dup2(pipes.script[1], STDOUT_FILENO);
@@ -114,19 +115,16 @@
 
 		signal(SIGCHLD, SIG_IGN);
 		signal(SIGPIPE, SIG_IGN);
-
+		// fprintf(stderr,"New call, handling setup...\n");
 		handle_setup_env(pipes.socket[1],&eslC);
 
 		/* TODO: check status */
 		status = esl_send(&eslC,"myevents");
-		eslC.async_execute = 0;
+		eslC.async_execute = 1;
 		while ( eslC.connected && thread_running) {
 			int r , nfds = 0;
 			fd_set rd;
 
-			/* As we are in sync mode, we should NOT care about socket there, 
-			 * there is a binding of esl_execute to find command results
-			 */
 			FD_ZERO(&rd);
 			FD_SET(pipes.script[0], &rd);
 			nfds = MAX(nfds,pipes.script[0]);
@@ -135,13 +133,13 @@
 			if (r == -1 )
 				break;
 			else if (FD_ISSET(pipes.script[0],&rd) ) { /* AGI has something to say */
-				bzero(&sbuf,2047);
 				r = read(pipes.script[0],&sbuf,2047);
 				if (r<0)
 					goto end;
 				else {
 					/*TODO: correct ugly hack to remove final \n */
 					sbuf[r-1] = '\0';
+					// fprintf(stderr,"Treating: '%s'\n",sbuf);
 					if ( find_and_exec_command(&eslC,pipes.socket[1],(char *) &sbuf) < 0 )
 						goto end;
 				}
@@ -199,7 +197,7 @@
 	}
 
 	if (!(ip && port)) {
-		fprintf(stderr, "Usage %s -h <host> -p <port>\n", argv[0]);
+		// fprintf(stderr, "Usage %s -h <host> -p <port>\n", argv[0]);
 		return -1;
 	}
 
@@ -210,175 +208,134 @@
 	return 0;
 }
 
+static int safe_int_snprintf_buffer(char **buf,const char *format, int ret) {
+	int size;
+	size = 2 + strlen(format); // Max 2 digits in int
+	if (*buf != NULL)
+		*buf = realloc(*buf,size+1);
+	else
+		*buf = malloc(size +1);
+	memset(*buf,0,size+1);
+	size = snprintf(*buf,size+1,format,ret);
+	return size;
+}
+
+/*
+ * Return malloc'd buf containing header value specified with %format
+ */
+static int fill_buffer_from_header(esl_event_t *event,char **buf,char *header,const char *format) {
+	int size=0;
+	char *sbuf;
+	sbuf = esl_event_get_header(event, header);
+	if (sbuf) {
+		size = strlen(sbuf) + strlen(format);
+		if (*buf == NULL)
+			*buf = malloc(size+1);
+		else
+			*buf = realloc(*buf,size+1);
+		memset(*buf,0,size+1);
+		size = snprintf(*buf,size,format,sbuf);
+	}
+	return size;
+}
+
 /* Setup env 
- * TODO:	- correct parameters
- *		- add a generic routine instead of blindly repeating code
+ * TODO:	- check size, if no header found we should not block
  */
 static int handle_setup_env(int fd,esl_handle_t *eslC) {
-	char buf[1024];
-	char *sbuf;
+	char *sbuf=NULL;
+	int size;
 
 	/* Setup Env for AGI scripts */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "variable_ivr_path")) ) {
-		sprintf(buf,"agi_request: %s\n",sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"variable_ivr_path","agi_request: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
 	else
-		return -1;
+			return -1;
 
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "variable_channel_name")) ) {
-		sprintf(buf,"agi_channel: %s\n",sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"variable_channel_name","agi_channel: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
 	else
-		return -1;
+			return -1;
 
-	if ( write(fd, "agi_language: en\n",18) < 0 )
+	if ( write(fd, "agi_language: en\n",strlen("agi_language: en\n") ) < 0 )
 		return -1;
 
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Source")) ) {
-		sprintf(buf, "agi_type: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Source","agi_type: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
 	else
-		return -1;
+			return -1;
 
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Unique-ID")) ) {
-		sprintf(buf, "agi_uniqueid: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Unique-ID","agi_uniqueid: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
 	else
-		return -1;
+			return -1;
 
-	/* ANI/DNIS */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Caller-ID-Number")) ) {
-		sprintf(buf, "agi_callerid: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Caller-ID-Number","agi_callerid: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_callerid: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Caller-ID-Name")) ) {
-		sprintf(buf, "agi_calleridname: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Caller-ID-Name","agi_calleridname: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_calleridname: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
 
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Screen-Bit")) ) {
-		sprintf(buf, "agi_callingpres: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Screen-Bit","agi_callingpres: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_callingpres: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
-	/* TODO */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Caller-Caller-ID-Number")) ) {
-		sprintf(buf, "agi_callingani2: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	else {
-		sprintf(buf, "agi_callingani2: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	/* TODO */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Caller-Caller-ID-Number")) ) {
-		sprintf(buf, "agi_callington: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	else {
-		sprintf(buf, "agi_callington: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Caller-Destination-Number")) ) {
-		sprintf(buf, "agi_dnid: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	else {
-		sprintf(buf, "agi_dnid: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	/* TODO */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Caller-Destination-Number")) ) {
-		sprintf(buf, "agi_callingtns: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	else {
-		sprintf(buf, "agi_callingtns: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
 
-	/* TODO: correct info */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Caller-Destination-Number")) ) {
-		sprintf(buf, "agi_rdnis: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Caller-Destination-Number","agi_dnid: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_rdnis: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Context")) ) {
-		sprintf(buf, "agi_context: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
-	else {
-		sprintf(buf, "agi_context: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
-			return -1;
-	}
 
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-Destination-Number")) ) {
-		sprintf(buf, "agi_extension: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Context","agi_context: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_extension: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
 
-	/* TODO: correct info */
-	if ( (sbuf = esl_event_get_header(eslC->info_event, "Channel-State-Number")) ) {
-		sprintf(buf, "agi_priority: %s\n", sbuf);
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	if ( (size = fill_buffer_from_header(eslC->info_event,&sbuf,"Channel-Destination-Number","agi_extension: %s\n") ) > 0) {
+		if ( write(fd,sbuf,size) < 0)
 			return -1;
 	}
-	else {
-		sprintf(buf, "agi_priority: %s\n", "unknown");
-		if ( write(fd, buf,strlen(buf) ) < 0)
+	else
 			return -1;
-	}
 
-	if ( write(fd, "agi_enhanced: 0.0\n", 19) < 0 )
+	/* TODO 
+	 * agi_callingani2
+         * agi_callington
+	 * agi_callingtns
+         * agi_rdnis
+	 * agi_priority
+         */
+
+	if ( write(fd, "agi_enhanced: 0.0\n", strlen("agi_enhanced: 0.0\n") ) < 0 )
 		return -1;
-	if ( write(fd, "agi_accountcode: \n\n", 21) < 0 )
+	if ( write(fd, "agi_accountcode: \n", strlen("agi_accountcode: \n") ) < 0 )
 		return -1;
+
+	if ( write(fd, "\n\n", 2 ) < 0 )
+		return -1;
+
 	return 0;
 }
 
@@ -393,7 +350,7 @@
 	if ( esl_execute(eslC,cmd,args,uuid) != ESL_FAIL) {
 		while (!done && eslC->connected) {
 			if (esl_recv_event(eslC,1,NULL) == ESL_FAIL)
-				return -1;
+				return -1; // Maybe point of failure
 			else if (eslC->last_ievent) {
 				if (eslC->last_ievent->event_id == ESL_EVENT_CHANNEL_EXECUTE_COMPLETE ) {
 					if (! strcasecmp(cmd,esl_event_get_header(eslC->last_ievent,"Application") ) )
@@ -410,41 +367,51 @@
 }
 
 /*
- * Hangup AGI cmd
- * TODO:	- Add arg support to know which channel we want to hangup.
+ * Answer AGI cmd
+ * TODO: Why is there an A on the AGI side ?
  */
-static int handle_hangup(esl_handle_t *eslC,int fd,int *argc, char *argv[]) {
-	if (do_execute(eslC,"hangup",NULL,NULL,NULL) < 0 ) {
-		if ( write(fd,"200 result=-1\n\n",128) < 0 )
-			return -1;
-	}
-	else {
-		if ( write(fd,"200 result=0\n\n",128) < 0 )
-			return -1;
-	}
-	return 0;
+static int handle_answer(esl_handle_t *eslC,int fd,int *argc, char *argv[]) {
+	int res;
+	int size;
+	char *buf=NULL;
+	res = do_execute(eslC,"answer",NULL,NULL,NULL);
+
+	size = safe_int_snprintf_buffer(&buf,"200 result=%d\n\n",res);
+
+	res = write(fd,buf,size);
+	free(buf);
+	return res;
 }
 
+
 /*
- * Answer AGI cmd
+ * Hangup AGI cmd
+ * TODO:	- Add arg support to know which channel we want to hangup.
  */
-static int handle_answer(esl_handle_t *eslC,int fd,int *argc, char *argv[]) {
-	if (do_execute(eslC,"answer",NULL,NULL,NULL) < 0 ) {
-		if ( write(fd,"200 result=-1\n\n",128) < 0 )
-			return -1;
-	}
-	else {
-		if ( write(fd,"200 result=0\n\n",128) < 0 )
-			return -1;
-	}
-	return 0;
+static int handle_hangup(esl_handle_t *eslC,int fd,int *argc, char *argv[]) {
+	int res;
+	int size;
+	char *buf=NULL;
+
+	res = do_execute(eslC,"hangup",NULL,NULL,NULL);
+
+	size = safe_int_snprintf_buffer(&buf,"200 result=%d\n\n",res);
+
+	res = write(fd,buf,size);
+	free(buf);
+	return res;
 }
 
+/*
+ * STREAM FILE agi cmd
+ * TODO: rewrites with good string handling :)
+ */ 
 static int handle_streamfile(esl_handle_t *eslC,int fd,int *argc, char *argv[]) {
-	char buf[1024];
-	char *sbuf;
+	char *buf;
 	int offset=0;
-	int dtmf=0;
+	char dtmf[2]={"0"};
+	int res;
+
 	esl_event_t *reply=NULL;
 
 	if (*argc < 3 || *argc > 5)
@@ -452,49 +419,75 @@
 
 	if (argv[3]) {
 		/* We should set playback_terminators var there */
-		sprintf(buf,"playback_terminators=%s",argv[3]);
+		buf = malloc(strlen(argv[3])+22);
+		memset(buf,0,strlen(argv[3])+22);
+		snprintf(buf,22,"playback_terminators=%s",argv[3]);
 		do_execute(eslC,"set",buf,NULL,NULL);
+		free(buf);
 	}
-	bzero(&buf,1023);
 
 	if (argv[4]) {
 		offset = atoi(argv[4]);
 	}
 
-	if (offset > 0)
-		sprintf(buf,"%s@@%d",argv[2],offset);
+	buf = malloc(strlen(argv[2]) + 1);
+	memset(buf,0,strlen(argv[2])+1);
+
+	if (offset > 0) {
+		buf = realloc(buf,strlen(argv[2]) + strlen(argv[4]) + 3);
+		snprintf(buf,strlen(argv[2]) + strlen(argv[4]) + 3,"%s@@%d",argv[2],offset);
+
+	}
 	else
-		sprintf(buf,"%s",argv[2]);
+		snprintf(buf,strlen(argv[2]) + 1,"%s",argv[2]);
+
 	offset = 0;
-	if ( do_execute(eslC,"playback",buf,NULL,&reply) < 0 ) /* We should write about NON success there instead of returning stock */
-		return -1;
+	if ( do_execute(eslC,"playback",buf,NULL,&reply) < 0 ) { /* We should write about NON success there instead of returning stock */
+		offset = -1;
+		fprintf(stderr,"do_execute stream file failed\n");
+	}
 	else {
-		bzero(&buf,1023);
-		/* We should check playback_samples var to return offset, sent in the CHANNEL_EXECUTE_COMPLETE and 
-		variable_playback_terminator_used to get the DTMF we had */
+		free(buf);
+		buf=NULL;
 		if (reply) {
-			if (! (sbuf = esl_event_get_header(reply, "variable_playback_samples")) )
-					offset = -1;
-			else {
-				offset = atoi(sbuf);
-			}
-			if (! (sbuf = esl_event_get_header(reply, "variable_playback_terminator_used")) )
-					dtmf = 0;
-			else {
-				dtmf = atoi(sbuf);
-			}
+			res = fill_buffer_from_header(eslC->info_event,&buf,"variable_playback_samples","%d");
+			if ( res <= 0 )
+				offset = 0;
+			else 
+				offset = atoi(buf);
+
+			fprintf(stderr,"Offset is %d, res is %d, buf is %s\n",offset,res,buf);
+
+			res = fill_buffer_from_header(reply,&buf,"variable_playback_terminator_used","%s");
+			// sbuf = esl_event_get_header(reply, "variable_playback_terminator_used");
+			if (res > 0)
+				snprintf((char *)&dtmf,1,"%s",buf);
 		}
+		else {
+			fprintf(stderr,"No event reply in stream file\n");
+			offset=-1;
+		}
 	}
+	if (buf != NULL)
+		free(buf);
+	fprintf(stderr,"End stream file %d %s\n",offset,dtmf);
 	if (offset < 0) {
-		if ( write(fd,"200 result=-1 endpos=0\n\n",128) < 0 )
+		if ( write(fd,"200 result=-1 endpos=0\n\n",128) < 0 ) {
+			fprintf(stderr,"Write failed\n");
 			return -1;
+		}
 	}
 	else {
-		sprintf(buf,"200 result=%d endpos=%d\n\n",dtmf,offset);
-		if ( write(fd,buf,128) < 0 )
+		buf=malloc(65);
+		memset(buf,0,65);
+		snprintf(buf,64,"200 result=%s endpos=%d\n\n",dtmf,offset);
+		if ( write(fd,buf,64) < 0 ) {
+			free(buf);
+			fprintf(stderr,"Write failed\n");
 			return -1;
+		}
+		free(buf);
 	}
-
 	return 0;
 }
 
@@ -594,4 +587,3 @@
 	}
 	return r;
 }
-

Modified: freeswitch/trunk/contrib/gled/esl2agi/esl2agi.h (15039 => 15040)


--- freeswitch/trunk/contrib/gled/esl2agi/esl2agi.h	2009-10-01 22:56:33 UTC (rev 15039)
+++ freeswitch/trunk/contrib/gled/esl2agi/esl2agi.h	2009-10-02 09:42:09 UTC (rev 15040)
@@ -61,6 +61,7 @@
 #define ESL_A_TO_VOID(v)	((void*)(v))
 #define VOID_TO_ESL_A(p)	((esl_accept_t*)(p))
 #define MAX(x,y)		((x) > (y) ? (x) : (y))
+#define MIN(x,y)		((x) < (y) ? (x) : (y))
 
 /* 
  * Struct Section
@@ -88,49 +89,37 @@
 
 static void *esl2agi_thread(void *data);
 
-/*
- * - EXEC application OPTIONS
- * - GET DATA filetoplay timeout maxdigits
- * - GET VARIABLE variablename
- * - HANGUP 'channelname'
- * - RECORD FILE filename format escapedigits timeout offsetsamples BEEP s=silence
- * - SAY DIGITS
- * - set autohangup time
- * - set music  on|off class
- * - set variable
- * - stream file filename <escape digits> [sample offset]
- * - wait for digit timeout
- */
-
 static int handle_setup_env(int fd,esl_handle_t *eslC);
 
 static void parse_args(char *buf,int *argc,char *argv[_MAX_CMD_ARGS]);
 
 static command_binding_t *find_binding(char *cmd[]);
 
-static int handle_hangup(esl_handle_t *eslC,int fd,int *argc, char *argv[_MAX_CMD_ARGS]);
-
-static int handle_answer(esl_handle_t *eslC,int fd, int *argc, char *argv[_MAX_CMD_ARGS]);
-
 static int find_and_exec_command(esl_handle_t *eslC,int fd,char *buf);
 
+static int do_execute(esl_handle_t *eslC,char *cmd,char *args,char *uuid,esl_event_t **save_reply);
+
 /*
+ * ported agi commands
+ */
 
-static int handle_exec(esl_handle_t *eslC,int fd,char *args);
+static int handle_hangup(esl_handle_t *eslC,int fd,int *argc, char *argv[_MAX_CMD_ARGS]);
 
-static int handle_getdata(esl_handle_t *eslC,int fd,char *args);
+static int handle_answer(esl_handle_t *eslC,int fd, int *argc, char *argv[_MAX_CMD_ARGS]);
 
-static int handle_getvar(esl_handle_t *eslC,int fd,char *args);
+static int handle_streamfile(esl_handle_t *eslC,int fd,int *argc, char *argv[_MAX_CMD_ARGS]);
 
-static int handle_record(esl_handle_t *eslC,int fd,char *args);
 
-static int handle_say(esl_handle_t *eslC,int fd,char *args);
-
-static int handle_setvar(esl_handle_t *eslC,int fd,char *args);
-
-static int handle_set(esl_handle_t *eslC,int fd,char *args);
-
-static int handle_streamfile(esl_handle_t *eslC,int fd,char *args);
-
-static int handle_waitdigits(esl_handle_t *eslC,int fd,char *args);
-*/
+/* TODO
+ * - EXEC application OPTIONS
+ * - GET DATA filetoplay timeout maxdigits
+ * - GET VARIABLE variablename
+ * - HANGUP 'channelname'
+ * - RECORD FILE filename format escapedigits timeout offsetsamples BEEP s=silence
+ * - SAY DIGITS
+ * - set autohangup time
+ * - set music  on|off class
+ * - set variable
+ * - stream file filename <escape digits> [sample offset]
+ * - wait for digit timeout
+ */