⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cagi.c

📁 asterisk c-agi 提供c 语言接口的例子
💻 C
📖 第 1 页 / 共 3 页
字号:
// //   Written by: David Cornewell (david.cornewell@gmail.com)//         Date: 03-16-2005// //   Purpose: 	This is a C library for interfacing with Asterisks' AGI.  It is based on PHPAGI. //				Actually, it is almost completely copied from it. I just changed the code to C.//				The in depth documentation is the same.////   License:	LGPL. ////   MODS: //        $Id: cagi.c,v 1.14 2006/11/13 16:14:19 dcornewell Exp $//        $Log: cagi.c,v $//        Revision 1.14  2006/11/13 16:14:19  dcornewell//        Fixed bug in AGITool_sendcmd(); when parsing data from response it was getting//        the length of the string inside the (). it did -1. it should have.////        Revision 1.13  2006/10/06 20:39:45  dcornewell//        put checkes in Init for the return of fgets. Just in case the stdin pipe//        gets lost, but app is blocking SIGPIPE////        Revision 1.12  2006/10/04 18:49:17  dcornewell//        Changed AGITool_ListAddItem() to malloc field and value rather than use//        static buffers with them.  uses memory necessary and allows for more than 50//        bytes each.////        Revision 1.11  2006/03/10 19:20:32  dcornewell//        Fixed a bug when trying to get the status of a dead channel. if program handles//        the SIGHUP and tries to clean up, it was checking the status of a channel//        hoping to find out that it was down. would get SIGPIPE cause stdin/out/err are//        not gone and would try to parse a NULL from fgets(stdin). checking for that//        null now.////        also implemented some exec functions. basically wrappers that call exec with//        something.////        Revision 1.10  2006/02/21 19:20:53  dcornewell//        Checking value for null before doing anything with it.////        Revision 1.9  2005/10/04 16:36:27  dcornewell//        Updated AGITool_exec_dial prototype. added check to make sure res->data isn't//        over filled. would take 2048 bytes, but you never know////        Revision 1.8  2005/10/04 16:19:18  dcornewell//        Fixed bug with exec dial. needed a \n////        Revision 1.7  2005/10/03 13:50:39  dcornewell//        Added AGITool_get_variable2() that takes a dest variable. it will fill that//        field with the variable. More self explainatory.////        Revision 1.6  2005/10/03 13:36:46  dcornewell//        Fixed bug in send_cmd. I was parsing data from asterisk and I bombed a zero//        into my buffer rather than res->result. this stopped the parsing and I never//        filled res->data. Also added a raw field to the result structure that will//        contain the raw data from asterisk. This would have helped some in debugging.////        Revision 1.5  2005/09/29 20:02:49  dcornewell//        Added AGITool_exec_dial() will dial. Thanks to Raymond Chen for testing and//        working on this.////        Revision 1.4  2005/07/07 15:15:33  dcornewell//        Added a check for null in strim. Anything that stops core dumps. not likely,//        but good to check.////        Revision 1.3  2005/06/05 23:31:09  dcornewell//        Changed the command AUTOHANGUP to "SET AUTOHANGUP".  I am not sure if I messed//        this up, or if it just changed.  hope it works////        Revision 1.2  2005/04/14 00:13:29  dcornewell//        Changed License to LGPL.  Not sure why, people just like it better////        Revision 1.1.1.1  2005/03/22 15:45:15  dcornewell//        initial checkin of CAGI. Most needed features are implemented.//#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <ctype.h>#include "cagi.h"int FileExists(char *path){	struct stat file_stat;	if(stat(path, &file_stat))		return 0;	return 1;}int strim(char *src){	int i=0;	if (src) {		i=strlen(src)-1;		while (i>0 && isspace(src[i])) {			src[i]=0;			i--;		}	}	return i;}AGI_VAL_LIST *AGITool_ListAddItem(AGI_VAL_LIST *l, char *field, char *value){	AGI_VAL_LIST *newl;	newl = (AGI_VAL_LIST *)malloc(sizeof(AGI_VAL_LIST));	if (newl) {		memset(newl,0,sizeof(AGI_VAL_LIST));		if (field!=NULL) {			newl->field = (char*)malloc(strlen(field)+1);			strlcpy(newl->field,field,strlen(field)+1);		}		if (value!=NULL) {			newl->value = (char*)malloc(strlen(value)+1);			strlcpy(newl->value,value,strlen(value)+1);		}		newl->next=l;	}	return newl;}void AGITool_ListDestroy(AGI_VAL_LIST *l){	AGI_VAL_LIST *l2;	while (l) {		l2=l->next;		free(l->field);l->field=NULL;		free(l->value);l->value=NULL;		free(l);l=NULL;				l=l2;	}	return;}char *AGITool_ListGetVal(AGI_VAL_LIST *l, char *field){	while (l) {		if (!strcmp(l->field, field)) {			return l->value;		}		l=l->next;	}	return "";}int AGITool_Init(AGI_TOOLS *tool){	char buffer[1024], *field, *value;		// open stdin	tool->in = stdin;		// open stdout	tool->out = stdout;		/*    * Often contains any/all of the following:    *   agi_network - value is yes if this is a fastagi    *   agi_network_script - name of the script to execute    *   agi_request - name of agi script    *   agi_channel - current channel    *   agi_language - current language    *   agi_type - channel type (SIP, ZAP, IAX, ...)    *   agi_uniqueid - unique id based on unix time    *   agi_callerid - callerID string    *   agi_dnid - dialed number id    *   agi_rdnis - referring DNIS number    *   agi_context - current context    *   agi_extension - extension dialed    *   agi_priority - current priority    *   agi_enhanced - value is 1.0 if started as an EAGI script    *   agi_accountcode - set by SetAccount in the dialplan    */		// read the request	tool->agi_vars=tool->settings=NULL;		if ( fgets(buffer,sizeof(buffer),stdin) ) {		while(strcmp(buffer, "\n") != 0) {			field=buffer;			value=strchr(buffer,':');			if (value) {				value[0]=0;				value+=2;				strim(value);				tool->agi_vars = AGITool_ListAddItem(tool->agi_vars, field,value);			}				if ( !fgets(buffer,sizeof(buffer),stdin) ) {				// if failed, may have lost pipe, but sigpipe is blocked.				break;			}		}	}		// These could be configured in an ini...	tool->settings = AGITool_ListAddItem(tool->settings, "tmpdir","/tmp/");	tool->settings = AGITool_ListAddItem(tool->settings, "festival_text2wave","text2wave");	tool->settings = AGITool_ListAddItem(tool->settings, "cepstral_swift","swift");	return 0;}void AGITool_Destroy(AGI_TOOLS *tool){	AGITool_ListDestroy(tool->agi_vars);	AGITool_ListDestroy(tool->settings);}int AGITool_sendcmd(AGI_TOOLS *tool, AGI_CMD_RESULT *res, char *command, ...){    va_list ap;	char buffer[4096], *str, *ptr;	int count,ret;	res->code=500;	strlcpy(res->result,"-1",sizeof(res->result));	res->data[0]=0;	// write command    va_start(ap, command);    ret = vfprintf(tool->out, command, ap);	va_end(ap);	fflush(tool->out);	if (ret<0) {		return 0;	}	// Read result.  Occasionally, a command return a string followed by an extra new line.	// When this happens, our script will ignore the new line, but it will still be in the	// buffer.  So, if we get a blank line, it is probably the result of a previous	// command.  We read until we get a valid result or asterisk hangs up.  One offending	// command is SEND TEXT.	buffer[0]=0;	str=buffer;	for (count=0; str && !strlen(str) && count<5; count++) {		str = fgets(buffer,sizeof(buffer),tool->in);	}	if (!str) {		return atoi(res->result);	}	if(count >= 5) {		return 0;	}	//	// Let's save what asterisk sent in case caller needs raw data string. Good for debug too.	// This will only do us good with single line responses though.	//	strlcpy(res->raw,buffer,sizeof(res->raw));	strim(buffer);  // parse result	res->code = atoi(str);	str+=4;	if(str[0] == '-') // we have a multiline response!  Like Usage	{		char junkit[2048];		fgets(junkit,sizeof(junkit),tool->in);		while (atoi(junkit) != res->code) {			fgets(junkit,sizeof(junkit),tool->in);		}	}	if(res->code != AGIRES_OK) // some sort of error	{		strlcpy(res->data, str,sizeof(res->data));	} else {// normal AGIRES_OK response		ptr=strstr(str,"result=");		if (ptr) {			strlcpy(res->result, ptr+7, sizeof(res->result));			ptr=strchr(res->result,' ');			if (ptr) {				ptr[0]=0;			}//			res->result = atoi(strstr(str,"result=")+7);		}		if (strstr(str, "endpos=")) {			res->endpos = atoul(strstr(str,"endpos=")+7);		}		if (strchr(str, '(')) {			if (strchr(str, ')')) {				int dlen=strchr(str, ')')-strchr(str,'(');				if (dlen>sizeof(res->data)) dlen=sizeof(res->data);				strlcpy(res->data, strchr(str,'(')+1, dlen);			} else {				strlcpy(res->data, strchr(str,'(')+1, sizeof(res->data));			}		}	}	return atoi(res->result);}//****************************// Commands to be sent//****************************//// Answer channel if not already in answer state.//int AGITool_answer(AGI_TOOLS *tool, AGI_CMD_RESULT *res){	return AGITool_sendcmd(tool, res, "ANSWER\n");}//// Cause the channel to automatically hangup at $time seconds in the future.// If $time is 0 then the autohangup feature is disabled on this channel.//// If the channel is hungup prior to $time seconds, this setting has no effect.//// @param integer $time until automatic hangup// @return array, see evaluate for return information.//int AGITool_autohangup(AGI_TOOLS *tool, AGI_CMD_RESULT *res, int time){	return AGITool_sendcmd(tool, res, "SET AUTOHANGUP %d\n", time);}//// Get the status of the specified channel. If no channel name is specified, return the status of the current channel.//// @param string $channel//int AGITool_channel_status(AGI_TOOLS *tool, AGI_CMD_RESULT *res, char *channel){	int ret = AGITool_sendcmd(tool, res, "CHANNEL STATUS %s\n", channel);	switch(atoi(res->result))	{		case -1: snprintf(res->data, sizeof(res->data), "There is no channel that matches %s",channel); break;		case AST_STATE_DOWN: snprintf(res->data, sizeof(res->data), "Channel is down and available"); break;		case AST_STATE_RESERVED: snprintf(res->data, sizeof(res->data), "Channel is down, but reserved"); break;		case AST_STATE_OFFHOOK: snprintf(res->data, sizeof(res->data), "Channel is off hook"); break;		case AST_STATE_DIALING: snprintf(res->data, sizeof(res->data), "Digits (or equivalent) have been dialed"); break;		case AST_STATE_RING: snprintf(res->data, sizeof(res->data), "Line is ringing"); break;		case AST_STATE_RINGING: snprintf(res->data, sizeof(res->data), "Remote end is ringing"); break;		case AST_STATE_UP: snprintf(res->data, sizeof(res->data), "Line is up"); break;		case AST_STATE_BUSY: snprintf(res->data, sizeof(res->data), "Line is busy"); break;		case AST_STATE_DIALING_OFFHOOK: snprintf(res->data, sizeof(res->data), "Digits (or equivalent) have been dialed while offhook"); break;		case AST_STATE_PRERING: snprintf(res->data, sizeof(res->data), "Channel has detected an incoming call and is waiting for ring"); break;		default: snprintf(res->data, sizeof(res->data), "Unknown result: %s", res->result); break;	}	return ret;}//// Executes the specified Asterisk application with given options//// @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands//int AGITool_exec(AGI_TOOLS *tool, AGI_CMD_RESULT *res, char *application, char *options){	return AGITool_sendcmd(tool, res, "EXEC %s %s\n", application, options);}//// Plays the given file and receives DTMF data.//// This is similar to STREAM FILE, but this command can accept and return many DTMF digits,//  while STREAM FILE returns immediately after the first DTMF digit is detected.//// Asterisk looks for the file to play in /var/lib/asterisk/sounds //// If the user doesn't press any keys when the message plays, there is $timeout milliseconds// of silence then the command ends. //// The user has the opportunity to press a key at any time during the message or the// post-message silence. If the user presses a key while the message is playing, the// message stops playing. When the first key is pressed a timer starts counting for// $timeout milliseconds. Every time the user presses another key the timer is restarted.// The command ends when the counter goes to zero or the maximum number of digits is entered,// whichever happens first. //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -