ivrdemo_读取xml

ivrdemo.c


/*

 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 1999 - 2005, Digium, Inc.
 *
 * Mark Spencer <markster@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */


/*! \file
 *
 * \brief IVR Demo application
 *
 * \author Mark Spencer <markster@digium.com>
 * 
 * \ingroup applications
 */


/*** MODULEINFO
<defaultenabled>no</defaultenabled>
 ***/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>


#include <mxml.h>


#define XML_FILE_PATH "./menu.xml"




//define for menu attr
#define TITLE   "title"
#define FLAGS   "flags"
//define for option attr
#define OPTION   "option"
#define ACTION          "action"




typedef enum {False = 0, True = 1} BOOL;




typedef enum {
AST_ACTION_UPONE,       /*!< adata is unused */
AST_ACTION_EXIT,        /*!< adata is the return value for ast_ivr_menu_run if channel was not hungup */
AST_ACTION_CALLBACK,    /*!< adata is an ast_ivr_callback */
AST_ACTION_PLAYBACK,    /*!< adata is file to play */
AST_ACTION_BACKGROUND,  /*!< adata is file to play */
AST_ACTION_PLAYLIST,    /*!< adata is list of files, separated by ; to play */
AST_ACTION_MENU,        /*!< adata is a pointer to an ast_ivr_menu */
AST_ACTION_REPEAT,      /*!< adata is max # of repeats, cast to a pointer */
AST_ACTION_RESTART,     /*!< adata is like repeat, but resets repeats to 0 */
AST_ACTION_TRANSFER,    /*!< adata is a string with exten\verbatim[@context]\endverbatim */
AST_ACTION_WAITOPTION,  /*!< adata is a timeout, or 0 for defaults */
AST_ACTION_NOOP,        /*!< adata is unused */
AST_ACTION_BACKLIST,    /*!< adata is list of files separated by ; allows interruption */
} ast_ivr_action;  




//define for the last option attr flag 
typedef enum {
STR_ATTR,
SUBMENU_ATTR,
ULONG_ATTR,
FUN_ATTR
} option_last_attr_flag;




struct ast_ivr_option {
        char *option;
        ast_ivr_action action;
        void *adata;
};


typedef struct ast_ivr_option ast_ivr_option_t ;


 struct ast_ivr_menu {
       char *title;            /*!< Title of menu */
       unsigned int flags;     /*!< Flags */                                                          
       struct ast_ivr_option *options; /*!< All options */                                            
};  


typedef struct ast_ivr_menu ast_ivr_menu_t ;


/*************************************************************************************************
* use to parse : <mainmenu falgs=0 options="mainmenu" title="IVR Demo Main Menu">
*                <submenu1 falgs=0 options="submenu1" title="IVR Demo Sub Menu1">
*/
typedef struct ivr_menu_des_s {
const char *title_str ; // title str 
const char *flags_str ;        // flag str 
//const char *options_str ;     // options str   unused 
} ivr_menu_des_t ;




typedef struct _value_string {
        int  value;
        const char   *string;
} value_string;




typedef int (*ivr_demo_func)(const char *chan, void *data);




typedef struct _string_2_fun {
        const char   *string;
ivr_demo_func fun;
} string_2_fun;


typedef struct _string_2_menu {
const char   *string;
ast_ivr_menu_t * menu_ptr;
} string_2_menu;






//static BOOL load_xml_file(const char *filename);
static inline int strlen_zero(const char *s);
static BOOL load_xml_file(const char *filename,const char *menuname,ast_ivr_menu_t *ivr_menu) ;
static BOOL parse_menu_attrs(mxml_node_t *node,ivr_menu_des_t *menu_des);
static BOOL parse_option_attrs(mxml_node_t *node,int num_attrs,ast_ivr_option_t *option);
static ast_ivr_action str_2_action(const char *str);
static int ivr_demo_function(const char *chan, void *data);
static ivr_demo_func string_2_fun_pointer( const char * str);
static ast_ivr_menu_t* string_2_menu_pointer(const char * str);
static BOOL parse_last_option_attr(mxml_node_t *node,ast_ivr_option_t *option);
static ast_ivr_option_t *init_ivr_option(int *argc);
static ast_ivr_option_t *add_ivr_option(ast_ivr_option_t *option_ptr,int *argc,ast_ivr_option_t option);


//this table use to change string to  ast_ivr_action
static const value_string option_vals[] = {
{ AST_ACTION_UPONE,                    "AST_ACTION_UPONE" },
{ AST_ACTION_EXIT,                     "AST_ACTION_EXIT" },
{ AST_ACTION_CALLBACK,                 "AST_ACTION_CALLBACK" },
{ AST_ACTION_PLAYBACK,                 "AST_ACTION_PLAYBACK" },
{ AST_ACTION_BACKGROUND,               "AST_ACTION_BACKGROUND" },
{ AST_ACTION_PLAYLIST,                 "AST_ACTION_PLAYLIST" },
{ AST_ACTION_MENU,                     "AST_ACTION_MENU" },
{ AST_ACTION_REPEAT,                   "AST_ACTION_REPEAT" },
{ AST_ACTION_RESTART,                  "AST_ACTION_RESTART" },
{ AST_ACTION_TRANSFER,                 "AST_ACTION_TRANSFER" },
{ AST_ACTION_WAITOPTION,               "AST_ACTION_WAITOPTION" },
{ AST_ACTION_NOOP,                     "AST_ACTION_NOOP" },
{ AST_ACTION_BACKLIST,                 "AST_ACTION_BACKLIST" }
};




static value_string option_last_attr_vals[] = {
{ STR_ATTR,                     "str" },
{ SUBMENU_ATTR,                         "submenu" },
{ ULONG_ATTR,                     "ulong" },
{ FUN_ATTR,                 "fun" }
};






//the ivr_menu 
static ast_ivr_menu_t ivr_menu ; 
static ast_ivr_menu_t ivr_submenu ;


//this table use to change string to function pointer 
static string_2_fun string_fun_vals[] = {
{ "ivr_demo_func",                     ivr_demo_function }
};


//this table use to change string to menu pointer
static string_2_menu string_menu_vals[] = {
{ "ivr_submenu", &ivr_submenu}
};






static int ivr_demo_function(const char *chan, void *data)
{
fprintf(stderr, "Open the file %s error!\n",(char *)data);
return 1;
}




/*! \brief returns non-zero if the string is not defined, or has zero length */                              
static inline int strlen_zero(const char *s)
{
        return (!s || (*s == '\0'));                                                                         
}




/***********************************************************************************************
filename : the xml file name (including path)
menuname : such as :
<mainmenu flags=0 title="IVR Demo Main Menu">   --------->   the menuname is  mainmenu 
.......
</mainmenu>
<submenu1 flags=0 title="IVR Demo Sub Menu1">   --------->   the menuname is  submenu1
.......
</submenu1>
ivr_menu_ptr: the pointer of the ast_ivr_menu_t 
*/
static BOOL load_xml_file(const char *filename,const char *menuname,ast_ivr_menu_t *ivr_menu_ptr)
{
FILE *fp = NULL;
mxml_node_t *tree;
mxml_node_t *menu;
mxml_node_t *mainmenu;
mxml_node_t *option;

ivr_menu_des_t menu_des ;

int option_num ;
ast_ivr_option_t *ivr_option ;


fp = fopen(filename, "r");
if( fp == NULL )
{
fprintf(stderr, "Open the file %s error!\n",filename);
return False;
}
fprintf(stderr, "##########Here load_xml_file!############\n");
tree = mxmlLoadFile(NULL, fp, MXML_TEXT_CALLBACK);
if( tree != False )
{
    if ((menu = mxmlFindElement(tree, tree, "menu", NULL, NULL,
                                MXML_DESCEND)) == NULL)
{
fprintf(stderr, "Unable to find first <menu> element in XML tree!\n");
return False;
}
if ((mainmenu = mxmlFindElement(menu, menu, menuname, NULL, NULL,
                                MXML_DESCEND)) == NULL)
{
fprintf(stderr, "Unable to find first <%s> element in XML tree!\n",menuname);
return False;
}

if( !parse_menu_attrs(mainmenu,&menu_des) )
{
fprintf(stderr,"Parse menu attrs error !\n");
return False;
}

//fprintf(stderr,"The menu_des.title_str is %s  \n",menu_des.title_str);
//fprintf(stderr,"The menu_des.flags_str is %s  \n",menu_des.flags_str);

ivr_option = init_ivr_option(&option_num);
if( !ivr_option )
{
fprintf(stderr,"init_ivr_option error!\n");
return False;
}


for(option=mxmlFindElement(mainmenu, mainmenu, "option", NULL, NULL,MXML_DESCEND_FIRST);
option;
option=mxmlFindElement(option, mainmenu, "option", NULL, NULL,MXML_NO_DESCEND))
{
ast_ivr_option_t ast_option ;
ast_option.option = NULL ;    //init 
ast_option.action = -1 ;
ast_option.adata = NULL ;
int num_attrs = option->value.element.num_attrs ;
//fprintf(stderr,"The num_attrs is %d\n",num_attrs);
if( !parse_option_attrs(option,num_attrs,&ast_option) )
{
fprintf(stderr,"parse_option_attrs error!\n");
return False ;
}
//option_num += 1 ;
ivr_option = add_ivr_option(ivr_option,&option_num,ast_option);
if( !ivr_option )
{
fprintf(stderr,"add_ivr_option error!\n");
return False;
}


}
ivr_menu_ptr->title = (char *)menu_des.title_str;
ivr_menu_ptr->flags = atoi( menu_des.flags_str );
ivr_menu_ptr->options = ivr_option ;

}



fclose(fp);
return True;
}




/**********************************************************************
such as : 
<mainmenu flags=0 title="IVR Demo Main Menu">   
.......
</mainmenu>
to parse the "flags=0 " and "title="IVR Demo Main Menu""
*/
static BOOL parse_menu_attrs(mxml_node_t *node,ivr_menu_des_t *menu_des)
{
assert( node != NULL );
const char *tmp = NULL ;


tmp = mxmlElementGetAttr(node,TITLE) ;
if( strlen_zero(tmp) )
{
return False;

}
menu_des->title_str = tmp ;
tmp = mxmlElementGetAttr(node,FLAGS) ;
if( strlen_zero(tmp) )
{
return False;
}
menu_des->flags_str = tmp ;
return True;
}


/**************************************************************************************
such as :
<option option="s" action=AST_ACTION_BACKGROUND str="demo-abouttotry"></option>
<option option="s" action=AST_ACTION_WAITOPTION></option>
to parse all the attrs 
*/
static BOOL parse_option_attrs(mxml_node_t *node,int num_attrs,ast_ivr_option_t *option)
{
//fprintf(stderr,"The num_attrs is %d \n",num_attrs);
const char *tmp = NULL;
ast_ivr_action flags ;
tmp = mxmlElementGetAttr(node,OPTION) ;
if( strlen_zero(tmp) )
{
return False;
}
option->option = (char *)tmp ;
tmp = mxmlElementGetAttr(node,ACTION) ;
if( strlen_zero(tmp) )
{
return False;
}
flags = str_2_action(tmp);
//fprintf(stderr,"The flags is %d\n",flags);
if( flags == -1 )
{
return False;
}
option->action = flags;

if( num_attrs == 3 )   //some options have 3 attrs 
{
if( !parse_last_option_attr(node,option) )
{
fprintf(stderr,"parse_last_option_attr error!\n");
return False;
}
}
return True;
}


//parse the last option attr 
static BOOL parse_last_option_attr(mxml_node_t *node,ast_ivr_option_t *option)
{
const char *tmp = NULL;
BOOL found = False ;
int i ;
int num = sizeof(option_last_attr_vals) / sizeof(option_last_attr_vals[0]);
//fprintf(stderr,"The num is %d\n",num);
for(i=0;i<num;i++)
{
tmp = mxmlElementGetAttr(node,option_last_attr_vals[i].string) ;
if( !strlen_zero(tmp) )
{
//fprintf(stderr,"The tmp is %s \n",tmp);
//fprintf(stderr,"The (option_last_attr_flag)i is %d \n",i);
switch((option_last_attr_flag)i)
{

case STR_ATTR:
option->adata = (void *)tmp ;
found = True;
break;
case SUBMENU_ATTR:
{
ast_ivr_menu_t* menu = string_2_menu_pointer(tmp);
if( !menu )
{
found = False ;
}
option->adata = (void *)menu;
found = True;
}
break;
case ULONG_ATTR:
option->adata = (void *)atoi(tmp);
found = True;
break;
case FUN_ATTR:
{
ivr_demo_func fun = string_2_fun_pointer(tmp);
if( !fun )
{
found = False ;
}
option->adata = (void *)fun;
found = True;
}
break;
default:
found = False ;
break;
}
if( found )
{
return True ;
}
}
}
return False;
}


// change string to function pointer 
static ivr_demo_func string_2_fun_pointer( const char * str)
{
int i ;
int num = sizeof(string_fun_vals) / sizeof(string_fun_vals[0]);
//fprintf(stderr,"The num is %d\n",num);
for(i=0;i<num;i++)
{
if( !strcmp(str,string_fun_vals[i].string) )
{
return string_fun_vals[i].fun ;
}
}
return (ivr_demo_func)NULL;
}


//change string to menu pointer
static ast_ivr_menu_t* string_2_menu_pointer(const char * str)
{
int i ;
int num = sizeof(string_menu_vals) / sizeof(string_menu_vals[0]);
//fprintf(stderr,"The num is %d\n",num);
for(i=0;i<num;i++)
{
if( !strcmp(str,string_menu_vals[i].string) )
{
return string_menu_vals[i].menu_ptr ;
}
}
return (ast_ivr_menu_t*)NULL;
}




//change string to  ast_ivr_action
static ast_ivr_action str_2_action(const char *str)
{
int i ;
int action_num = sizeof(option_vals) / sizeof(option_vals[0]);
//fprintf(stderr,"The action_num is %d\n",action_num);
for(i=0;i<action_num;i++)
{
//fprintf(stderr,"The str is %s\n",str);
//fprintf(stderr,"The option_vals[i].string is %s\n",option_vals[i].string);
if( !strcmp(str,option_vals[i].string) )
{
return (ast_ivr_action)i;
}
}
return -1;
}


static ast_ivr_option_t *init_ivr_option(int *argc)
{
ast_ivr_option_t *ivr_option = NULL ;
*argc = 0 ;
ivr_option = calloc(1,sizeof(ast_ivr_option_t));
if( !ivr_option )
{
fprintf(stderr,"No Merrory!\n");
return (ast_ivr_option_t *)NULL ;
}
return ivr_option ;
}


static ast_ivr_option_t *add_ivr_option(ast_ivr_option_t *option_ptr,int *argc,ast_ivr_option_t option)
{
/* 
Grow the array; "*argc" currently contains the number of string
pointers, *not* counting the NULL pointer at the end, so we have
to add 1 in order to get the new size of the array, including the
new pointer and the terminating NULL pointer. 
*/
option_ptr = realloc( option_ptr , ((*argc)+1) * sizeof(ast_ivr_option_t ) );
if( !option_ptr )
{
fprintf(stderr,"No Merrory!\n");
return (ast_ivr_option_t *)NULL ;
}
option_ptr[*argc] = option ;
(*argc)++ ;    //increase the num 
return option_ptr;
}




int main( void )
{
if( load_xml_file(XML_FILE_PATH,"mainmenu",&ivr_menu) )
{
int i ;
//ivr_menu_ptr->title = (char *)menu_des.title_str;
//ivr_menu_ptr->flags = atoi( menu_des.flags_str );
fprintf(stderr,"The ivr_menu.title is %s\n",ivr_menu.title);
fprintf(stderr,"The ivr_menu.flags is %d\n",ivr_menu.flags);

for(i=0;i<10;i++)
{
//fprintf(stderr,"The ivr_menu.options[%d]  is %s\n",i,ivr_menu.options[i]);
fprintf(stderr,"The ivr_menu.options[%d] :\n",i);
fprintf(stderr,"\tThe  option %s \n",(char *)ivr_menu.options[i].option);
fprintf(stderr,"\tThe  action %d \n",(ast_ivr_action)ivr_menu.options[i].action);
//fprintf(stderr,"\tThe  adata %s \n",(char *)ivr_menu.options[i].adata);
}

}

if( load_xml_file(XML_FILE_PATH,"submenu1",&ivr_submenu) )
{
int i ;
//ivr_menu_ptr->title = (char *)menu_des.title_str;
//ivr_menu_ptr->flags = atoi( menu_des.flags_str );
fprintf(stderr,"The ivr_menu.title is %s\n",ivr_submenu.title);
fprintf(stderr,"The ivr_menu.flags is %d\n",ivr_submenu.flags);

for(i=0;i<8;i++)
{
//fprintf(stderr,"The ivr_menu.options[%d]  is %s\n",i,ivr_menu.options[i]);
fprintf(stderr,"The ivr_menu.options[%d] :\n",i);
fprintf(stderr,"\tThe  option %s \n",(char *)ivr_submenu.options[i].option);
fprintf(stderr,"\tThe  action %d \n",(ast_ivr_action)ivr_submenu.options[i].action);
//fprintf(stderr,"\tThe  adata %s \n",(char *)ivr_menu.options[i].adata);
}

}

return 0 ;
}


***********************************************************

Makefile


CC = gcc -Wall -O2
LIBS =-L/usr/local/lib -lmxml -lpthread
INCLUDE = -I /usr/local/include
TARGET = ivrdemo
all:$(TARGET)
ivrdemo: ivrdemo.o
$(CC) -o ivrdemo ivrdemo.o $(LIBS)
.c.o:
$(CC) -c $(INCLUDE) $< $(LIBS)


clean:
@rm *.o
@rm ivrdemo



***********************************************************************'

menu.xml


<?xml version="1.0"?>
<menu>
<mainmenu flags=0 title="IVR Demo Main Menu">
<option option="s" action=AST_ACTION_BACKGROUND str="demo-congrats"></option>
<option option="g" action=AST_ACTION_BACKGROUND str="demo-instruct"></option>
<option option="g" action=AST_ACTION_WAITOPTION></option>
<option option="1" action=AST_ACTION_PLAYBACK str="digits/1"></option>
<option option="1" action=AST_ACTION_RESTART></option>
<option option="2" action=AST_ACTION_MENU submenu="ivr_submenu"></option>
<option option="2" action=AST_ACTION_RESTART></option>
<option option="i" action=AST_ACTION_PLAYBACK str="invalid"></option>
<option option="i" action=AST_ACTION_REPEAT ulong=2></option>
<option option="#" action=AST_ACTION_EXIT></option>
</mainmenu>
<submenu1 flags=0 title="IVR Demo Sub Menu1">
<option option="s" action=AST_ACTION_BACKGROUND str="demo-abouttotry"></option>
<option option="s" action=AST_ACTION_WAITOPTION></option>
<option option="1" action=AST_ACTION_PLAYBACK str="digits/1"></option>
<option option="1" action=AST_ACTION_RESTART></option>
<option option="2" action=AST_ACTION_PLAYLIST str="digits/2;digits/3"></option>
<option option="3" action=AST_ACTION_CALLBACK fun="ivr_demo_func"></option>
<option option="*" action=AST_ACTION_REPEAT></option>
<option option="#" action=AST_ACTION_UPONE></option>
</submenu1>
</menu>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值