您的位置:首页 > 其它

ivrdemo_读取xml

2015-11-17 10:35 246 查看
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: