Asterisk的Callback功能

转自: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

 

你可能感兴趣的:(Asterisk的Callback功能)