转自:http://blog.sakuras.cn/2008/06/asteriskcallbac.html
Asterisk本身其实不带Callback的功能,但因其强大的扩展性,因为想在上面实现Callback功能也不复杂
首先要在Asterisk的extensions.conf里面加入如下内容(以下代码来源于http://www.geocities.com/callbackagi/)
[office]
exten => s,1,Answer
exten => s,2,wait(1)
exten => s,3,Background(welcome)
exten => s,4,Background(enter-ext-of-person)
exten => s,5,Background(for-sales)
exten => s,6,Background(press-1)
exten => s,7,Background(for-tech-support)
exten => s,8,Background(press-2)
exten => s,9,Background(for)
exten => s,10,Background(customer-service)
exten => s,11,Background(press-3)
exten => s,12,Background(to-reach-operator)
exten => s,13,Background(press-0)
exten => s,14,Read(DTMF)
exten => s,15,GotoIf($["${DTMF}" = "1"]?17:35)
exten => s,16,Background(pbx-onemoment)
exten => s,17,Goto(400,2)
exten => s,18,GotoIf($["${DTMF}" = "2"]?20:22)
exten => s,19,Background(pbx-onemoment)
exten => s,20,Goto(303,2)
exten => s,21,GotoIf($["${DTMF}" = "3"]?23:25)
exten => s,22,Background(pbx-onemoment)
exten => s,23,Goto(200,1)
exten => s,24,GotoIf($["${DTMF}" = "400"]?26:28)
exten => s,25,Background(pbx-onemoment)
exten => s,26,Goto(400,2)
exten => s,27,GotoIf($["${DTMF}" = "401"]?29:31)
exten => s,28,Background(pbx-onemoment)
exten => s,29,Goto(401,2)
exten => s,30,GotoIf($["${DTMF}" = "210"]?32:34)
exten => s,31,Background(pbx-onemoment)
exten => s,32,Goto(210,2)
exten => s,33,GotoIf($["${DTMF}" = "0"]?35:37)
exten => s,34,Background(pbx-onemoment)
exten => s,35,Goto(200,1)
;exten => s,37,Background(invalid)
exten => s,36,Goto(s,4)
exten => s,37,Background(pls-wait-connect-call)
exten => s,38,Background(to-reach-operator)
exten => s,39,Goto(200,1)
exten => s,40,Hangup
………………..
………………..
………………..
exten => _200,1,Playback(pbx-callconect)
exten => _200,2,Dial(SIP/200,30,rtT)
exten => _200,3,Voicemail(u200)
exten => _210,1,Playback(pbx-callconect)
exten => _210,2,Dial(SIP/210,30,rtT)
exten => _210,3,Goto(callback_agi,s,1)
exten => _211,1,Playback(pbx-callconect)
exten => _211,2,Dial(SIP/211,10,rtT)
exten => _211,3,Goto(callback_agi,s,1)
exten => _400,1,Playback(pbx-callconect)
exten => _400,2,Dial(SIP/400,30,rtT)
exten => _400,3,Voicemail(u400)
exten => _302,1,Playback(pbx-callconect)
exten => _302,2,Dial(SIP/302,30,rtT)
exten => _302,3,Voicemail(u302)
exten => _303,1,Playback(pbx-callconect)
exten => _303,2,Dial(SIP/303,30,rtT)
exten => _303,3,Voicemail(u303)
exten => _401,1,Dial(SIP/401,30,rtT)
exten => _401,2,Playback(number-not-answering)
exten => _401,3,Playback(goodbye)
exten => _401,4,Hangup
exten => *98,1,VoicemailMain
exten => *98,2,Hangup
…………..
……………
………..
[callback_agi]
exten => s,1,Playback(please-try-again)
exten => s,2,Playback(vm-goodbye)
exten => s,3,AGI(callback.agi)
exten => s,4,Hangup
exten => t,1,Goto(s,4)
……………
………….
剩下就是要做个AGI了
这里使用的是C写的,命名为callback.c
//////////////////////////////////////////////////////////////////
// FileName : callback.c
// Author : Gobinda Paul <[email protected]>
// initial date : 10/14/2006
// initial version : 1.0.1b
//////////////////////////////////////////////////////////////////
#include <inttypes.h>
#include <stdarg.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/cdefs.h>
#define LOGPATHFILENAME "/var/log/callback.log" // View callback log
#define TMPCALLPATH "/var/spool/asterisk/tmp/" // We need temporary path for make call
#define ASTPOOLDIR "/var/spool/asterisk/outgoing/" // Asterisk spool dir
#define PRIORITY 2 // Indicates debug level
#define EXTENSION "s" // Where to start
#define CONTEXT "office" // Wrote your own context here
#define MAXRETRY 1 // Number of max retry
#define RETRYTIME 10 // Interval Time
#define CALLBACKTIME 10 // It’s indicates that after 10 sec, it will try to call you back
struct call
{
float enhanced;
char channel[100];
char language[10];
char type[10];
char uniqueid[30];
char callerid[100];
int dnid;
char rdnis[30];
char context[100];
char extension[20];
int priority;
int maxretries;
int retryTime;
};
long filesize(FILE *stream)
{
long curpos, length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
fseek(stream, curpos, SEEK_SET);
return length;
}
int RenameLogFile(void)
{
FILE *stream,*stream2;
char rename_file[100]="";
char curtime[100]="";
struct tm t;
time_t tm;
time(&tm);
localtime_r(&tm, &t);
strftime(curtime, sizeof(curtime), "%y-%m-%d %H:%M:%S", &t);
stream2 = fopen(LOGPATHFILENAME, "a+");
if(stream2== NULL)
{
fclose(stream2);
return -1;
}
fclose(stream2);
stream = fopen(LOGPATHFILENAME, "r+");
if(stream== NULL)
{
fclose(stream);
return -1;
}
sprintf(rename_file,"%s_",LOGPATHFILENAME);
strcat(rename_file,curtime);
if(filesize(stream)>10485760)
{
rename(LOGPATHFILENAME,rename_file);
}
fclose(stream);
return 0;
}
void CallBack_log(int priority, char *fmt, ...)
{
FILE *fp;
RenameLogFile();
if(PRIORITY >=priority)
{
va_list arg_ptr;
va_start(arg_ptr, fmt);
fp=fopen(LOGPATHFILENAME,"a+");
if(fp == NULL)
{
return;
}
vfprintf(fp, fmt, arg_ptr);
va_end(arg_ptr);
fclose(fp);
}
}
void Create_Call(struct call *callback)
{
FILE *fp;
char CallFile[256]="";
char tmp[256]="";
struct tm t;
int i=0;
time_t tm;
strcpy(CallFile,"mkdir -p ");
strcat(CallFile,TMPCALLPATH);
system(CallFile);
strcpy(CallFile,"");
time(&tm);
localtime_r(&tm, &t);
strftime(CallFile, sizeof(CallFile), "call%Y%m%d_%H%M%S", &t);
strcpy(tmp,TMPCALLPATH);
strcat(tmp,CallFile);
CallBack_log(3, "/n===================================/n");
CallBack_log(3, "Create New Call File: '%s'", tmp);
CallBack_log(3, "/n===================================/n");
fp=fopen(tmp,"w");
if(fp == NULL)
{
CallBack_log(3, "Can't Create New File [%s]",tmp);
return;
}
for(i=0;callback->channel[i]!=0;i++ )
{
if(callback->channel[i]=='-')
break;
else
callback->extension[i]=callback->channel[i];
}
fprintf(fp,"Channel: %s/n",callback->extension);
fprintf(fp,"Callerid: %s/n",callback->callerid);
fprintf(fp,"Context: %s/n",callback->context);
fprintf(fp,"Extension: %s/n", EXTENSION);
fprintf(fp,"MaxRetries: %d/n",callback->maxretries);
fprintf(fp,"RetryTime: %d/n",callback->retryTime);
fclose(fp);
strcpy(CallFile,"mv ");
strcat(CallFile,tmp);
strcat(CallFile," ");
strcat(CallFile,ASTPOOLDIR);
sleep(CALLBACKTIME);
system(CallFile);
CallBack_log(3, "/n===================================/n");
CallBack_log(3, "Executeing: '%s'", CallFile);
CallBack_log(3, "/n===================================/n");
strcpy(CallFile,"rm -rf ");
strcat(CallFile,tmp);
system(CallFile);
CallBack_log(3, "/n===================================/n");
CallBack_log(3, "Deleting Tmp File: '%s'", CallFile);
CallBack_log(3, "/n===================================/n");
}
static int read_environment(void)
{
char buf[256];
char *val;
for(;;) {
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '/0';
if (!strlen(buf))
return 0;
val = strchr(buf, ':');
if (!val) {
CallBack_log(2, "Invalid environment: '%s'/n", buf);
return -1;
}
*val = '/0';
val++;
val++;
setenv(buf, val, 1);
}
return 0;
}
int main(int argc, char *argv[])
{
char *tmp;
struct call *callback;
callback=(struct call *)malloc(sizeof(struct call));
int ver = 0;
int subver = 0;
setlinebuf(stdin);
setlinebuf(stdout);
if (read_environment())
{
CallBack_log(2, "Failed to read environment: %s/n", strerror(errno));
free(callback);
exit(1);
}
CallBack_log(2, "/n===================================/n");
CallBack_log(2, "CallBack AGI Get Following Environment:/n");
CallBack_log(2, "===================================/n");
tmp = getenv("agi_enhanced");
if (tmp)
{
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
CallBack_log(2, "agi_enhanced : %s/n", tmp);
if(tmp!=NULL)
callback->enhanced=atof(tmp);
tmp = getenv("agi_channel");
CallBack_log(2, "agi_channel : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->channel,tmp);
tmp = getenv("agi_language");
CallBack_log(2, "agi_language : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->language,tmp);
tmp = getenv("agi_type");
CallBack_log(2, "agi_type : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->type,tmp);
tmp = getenv("agi_uniqueid");
CallBack_log(2, "agi_uniqueid : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->uniqueid,tmp);
tmp = getenv("agi_callerid");
CallBack_log(2, "agi_callerid : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->callerid,tmp);
tmp = getenv("agi_dnid");
CallBack_log(2, "agi_dnid : %s/n", tmp);
if(tmp!=NULL)
callback->dnid=atoi(tmp);
tmp = getenv("aagi_rdnis");
CallBack_log(2, "agi_rdnis : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->rdnis,tmp);
tmp = getenv("agi_context");
CallBack_log(2, "agi_context : %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->context,CONTEXT);
tmp = getenv("agi_extension");
CallBack_log(2, "agi_extension: %s/n", tmp);
if(tmp!=NULL)
strcpy(callback->extension,tmp);
else
strcpy(callback->extension,EXTENSION);
tmp = getenv("agi_priority");
CallBack_log(2, "agi_priority : %s/n", tmp);
if(tmp!=NULL)
callback->priority=atoi(tmp);
else
callback->priority=PRIORITY;
CallBack_log(2, "===================================/n");
callback->maxretries=MAXRETRY;
callback->retryTime=RETRYTIME;
Create_Call(callback);
free(callback);
return 1;
}
拷贝 callback.c 到 /var/lib/asterisk/agi-bin/目录下
然后对其进行编译:gcc callback.c –o callback.agi
测试方法:Dial 400/401/302/303/200 to 211 / 210
查看日志: tail –f /var/log/callback.log