[asterisk-commits] brushtyler: branch brushtyler/voicemail_menu_branch r199855 - in /team/brusht...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jun 10 09:51:14 CDT 2009
Author: brushtyler
Date: Wed Jun 10 09:51:11 2009
New Revision: 199855
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=199855
Log:
Added some code and vmmenu example
Added:
team/brushtyler/voicemail_menu_branch/apps/app_myvm.c (with props)
team/brushtyler/voicemail_menu_branch/apps/myvm/
team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt (with props)
team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample (with props)
team/brushtyler/voicemail_menu_branch/apps/newvoicemail.c (with props)
Added: team/brushtyler/voicemail_menu_branch/apps/app_myvm.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/brushtyler/voicemail_menu_branch/apps/app_myvm.c?view=auto&rev=199855
==============================================================================
--- team/brushtyler/voicemail_menu_branch/apps/app_myvm.c (added)
+++ team/brushtyler/voicemail_menu_branch/apps/app_myvm.c Wed Jun 10 09:51:11 2009
@@ -1,0 +1,2 @@
+#define MYVM_STANDALONE
+#include "newvoicemail.c"
Propchange: team/brushtyler/voicemail_menu_branch/apps/app_myvm.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/brushtyler/voicemail_menu_branch/apps/app_myvm.c
------------------------------------------------------------------------------
svn:keywords = brushtyler 2009-06-10
Propchange: team/brushtyler/voicemail_menu_branch/apps/app_myvm.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt
URL: http://svn.asterisk.org/svn-view/asterisk/team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt?view=auto&rev=199855
==============================================================================
--- team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt (added)
+++ team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt Wed Jun 10 09:51:11 2009
@@ -1,0 +1,145 @@
+=== VOICEMAIL_MENU.CONF FILE ===
+
+A few notes on the proposed architecture for the new voicemail application.
+
+The idea is that the entire behaviour of the voicemail is configurable
+through a config file. The file contains multiple sections,representing
+individual submenus that can be linked together using special commands.
+Within each section, users can bind individual keypresses (or sequences),
+or timeouts, to specific actions, including playback or recording of
+messages, manipulation of list of messages, jumps or "gosub" to a different
+section, dialplan functions.
+All bindings can use variables so they are highly configurable.
+
+The starting point of each individual voicemail can be set explicitly, so
+it is extremely easy to use existing templates or implement brand-new
+behaviours on a per-user base.
+
+An example of the configuration file is given below.
+
+Users can use voicemail_menu.conf file to set the voicemail behavior.
+This file is divided into sections, each of these is a menu. There are
+also a global section that contains the general working params.
+
+=== Global Section ===
+The global section is special and contain global variables and other
+directives used by the voicemail system.
+
+ [general]
+ start = menu_name
+ ; specifies the name of the voicemail start menu. A 'menu_name'
+ ; section must exist in the voicemail_menu.conf
+ authentication_required = yes|no
+ ; set this flag to 'no' if you want skip the autentication, 'yes'
+ ; otherwise
+ max_retries = n
+ ; number of maximum failed authentication before Asterisk closes
+ ; the communication channel
+ forward_key = #
+ ; set the key to forward the playing message
+ reverse_key = *
+ ; set the key to reverse the playing message
+ pause_key = 0
+ ; set the key to pause the playing message
+ stop_key = 2
+ ; set the key to stop the playing message
+ restart_key = 1
+ ; set the key to restart the playing message
+
+=== Menu Sections ===
+In general each menu section contains a number of '<pattern> = <actions>'
+lines, where <pattern> matches a sequence of keypresses.
+
+Some <pattern>'s are special and used to indicate options that
+are valid within the menu itself and not preserved across
+calls or jumps to different menus.
+
+The general menu section structure is the following:
+ [menu_name]
+ ; 'init' and 'default' are the only two special pattern names
+ init = actions
+ ; init actions are executed when enter in this menu
+ default = actions
+ ; default actions are executed when the user input doesn't
+ ; matches with any patterns
+
+ ; other patterns are used to match keypresses.
+ ; the match is done using the same mechanism used in the
+ ; dialplan, so refer to that to know about special characters,
+ ; wildcards, and how overlapping patterns are matched.
+ ; Is used a interdigit timer and the pattern are evaluted just
+ ; when the timer expires
+ <pattern> = <actions>
+
+
+=== Actions ===
+Each pattern can be associated to multiple actions, which are
+executed in sequence.
+Links between menus are implemented with 'jump actions'.
+Other actions are normally executing user commands, setting variables,
+and so on.
+
+An action list can be preceded by a conditional statement.
+ <pattern> = [IF(conditions),] action1[, action2, ...]
+If the conditions are not verified, the system behaves as if
+the pattern did not match.
+
+Actions
+There are 2 action types: jump actions and function actions. The jump actions
+is used to navigate throught menus, the function actions are the real actions
+will be made by voicemail application.
+
+Jump Actions
+ call(menu_name)
+ ; make a jump from a menu to another keeping trace of the caller menu.
+ ; The arg is the menu name to call. This function keep the history of
+ ; visited menus so you can return to a previous menu.
+
+ return(n)
+ ; return to a previous visited menu. The arg is the number of menus you
+ ; want come back, is optional and if omitted is implicitly 1.
+
+ jump(menu_name)
+ ; likewise call, make a jump from a menu to another but don't keep any
+ ; trace of previous menu.
+
+Function Actions
+ play_msg(current|previous|next)
+ ; start the playing of a voice message. The arg is the message we want
+ ; to playing and is optional (if omitted will play the current message).
+
+ change_to(folder_name)
+ ; with this function user can change the actual selected folder. The
+ ; arg is the folder name in which go
+
+ play(file)
+ ; this function playing an audio file and is used to play the menus
+ ; instructions. The arg is the file name.
+
+ delete()
+ undelete()
+ ; The first function mark for deletion the selected message, the second
+ ; function instead unmark previous marked messages. The real deletion
+ ; of marked messages occurs when voicemail are correctly terminated.
+
+ dialout()
+ ; permit users to make an external call using as phone number the typed
+ ; pattern. Before calling, Asterisk will terminate the voicemail
+ ; application.
+
+ callback()
+ ; make a call to the selected message sender phone number. The
+ ; voicemail application remain active and after calling user can return
+ ; to interact with the voicemail.
+
+ envelope()
+ ; playing the additional message informations (date and time of
+ ; receipt, sender information).
+
+ leave_mess()
+ ; user can record a message in own mailbox.
+
+ save_msg(folder)
+ ; store the selected message in a different folder. The arg is the
+ ; folder name into store the message.
+
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt
------------------------------------------------------------------------------
svn:keywords = brushtyler 2009-06-10
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/brief.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample
URL: http://svn.asterisk.org/svn-view/asterisk/team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample?view=auto&rev=199855
==============================================================================
--- team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample (added)
+++ team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample Wed Jun 10 09:51:11 2009
@@ -1,0 +1,162 @@
+; Voice Mail Menu' configuration file
+;
+; In this configuration the menu is considered as organized
+; in more parts named "menu_name" the behaviour of the menu
+; is set by tha association 'digit = actions', where 'digits'
+; is a pattern present in the dialplan by the user, and
+; 'actions' is a list of "function(arguments)" separated by
+; 'comma. Comments are precedeed by ';'.
+;
+;------------------- global settings -----------------------;
+
+[general]
+ start = vm_menu ; starting menu name
+ authentication_required = yes ; login required
+ max_retries = 3 ; max number of login fails
+ forward_key = # ; playing command
+ reverse_key = *
+ pause_key = 0
+ stop_key = 2
+ restart_key = 1
+
+;--------------------- menu section ------------------------;
+;
+; Main Menu
+; In the init action is used the VMCOUNT dialplan function
+; to get the number of messages stored in a mailbox folder;
+; if there are new messages, new messages folder is stored
+; into the FOLD channel var, otherwise old messages folder
+; is stored. This permit to set a quick key to access these
+; messages. The 'play(vm_intro)' action play an audio file
+; containing menu instructions.
+;
+; note that some of the actions associated to digits are conditional,
+; so that they are enabled or disabled depending on the status
+; of the voice mailbox
+
+[vm_menu]
+ init = SET(FOLD=${IF(${VMCOUNT(id at mb,INBOX)}?NEW_FOLDER:OLD_FOLDER)}),play(vm_intro)
+ ; set in FOLD var the working folder
+ default = play(vm_intro)
+ ; play instructions
+
+ 1 = change_to(${FOLD})
+ ; if there are new messages, go to the new messages folder,
+ ; else open the old messages folder
+ 2 = call(change_folder_menu)
+ ; go to Change Folder Menu
+ 3 = call(adv_menu)
+ ; go to Advanced Menu Options
+ 4 = IF(${NOT_FIRST_MSG}),play_msg(previous)
+ ; play previous message
+ 5 = IF(${MSG_SELECTED}),play_msg()
+ ; play current message
+ 6 = IF(${NOT_LAST_MSG}),play_msg(next)
+ ; play next message
+ 7 = IF(${MSG_SELECTED && VMU_NOT_DELETED}),delete()
+ ; mark selected message for deletion
+ 7 = IF(${MSG_SELECTED && VMU_DELETED}),undelete()
+ ; unmark a previous marked message for deletion
+ 8 = IF(${MSG_SELECTED}),forward_message()
+ ; forward a message
+ 9 = IF(${MSG_SELECTED}),call(save_to_folder_menu)
+ ; go to Save To Folder Menu
+ 0 = call(opts_menu)
+ ; go to Voicemail Menu Options
+ * = play(vm_intro)
+ ; play instructions
+ # = exit()
+ ; exit from voicemail application
+
+;-----------------------------------------------------------;
+;
+; Advanced Menu Options
+; Contains the message advanced operations o user operation
+; related to a message
+
+[adv_menu]
+ init = play(vm_adv_intro)
+ default = play(vm_adv_intro)
+ 1 = IF(${MSG_SELECTED}),reply() ; reply to sender
+ 2 = IF(${VMU_CALLBACK}),callback() ; call the sender
+ 3 = IF(${MSG_SELECTED}),envelope() ; play additional
+ ; message information
+ 4 = IF(${VMU_DIALOUT}),call(dialout_menu) ; make an external call
+ 5 = IF(${VMU_LEAVEMESS}),leave_mess() ; leave a message
+ * = return(1) ; return to Main Menu
+
+;-----------------------------------------------------------;
+;
+; Dialout Menu
+; In this menu, the user input pattern is used as phone
+; number to call.
+
+[dialout_menu]
+ init = play(vm_dialout_intro)
+ default = return(1) ; when timer elapsed without
+ ; pressing of any digit,
+ ; return to Main Menu
+
+ _X. = dialout() ; make a call
+ * = return(1) ; return to Main Menu
+
+;-----------------------------------------------------------;
+;
+; Save To Folder Menu
+; By this menu user can store a message in another folder:
+; the played audio file explain to users the folder related
+; to each pattern. After changing or typing '*', user can
+; return to Main Menu.
+
+[save_to_folder_menu]
+ init = play(vm_save_to_folder_intro)
+ default = play(vm_save_to_folder_intro)
+ 1 = save_msg(work), return(1)
+ 2 = save_msg(family), return(1)
+ 3 = save_msg(friends), return(1)
+ 4 = save_msg(cust1), return(1)
+ 5 = save_msg(cust2), return(1)
+ 6 = save_msg(cust2), return(1)
+ 7 = save_msg(cust3), return(1)
+ 8 = save_msg(cust4), return(1)
+ 9 = save_msg(cust5), return(1)
+ * = return(1) ; return Main Menu
+
+;-----------------------------------------------------------;
+;
+; Change Folder Menu
+; By this menu user can change his actual working folder:
+; the played audio file explain to users the folder related
+; to each pattern. After changing or typing '*', user can
+; return to Main Menu.
+
+[change_folder_menu]
+ init = play(vm_change_folder_intro)
+ default = play(vm_change_folder_intro)
+ 1 = change_to(work), return(1)
+ 2 = change_to(family), return(1)
+ 3 = change_to(friends), return(1)
+ 4 = change_to(cust1), return(1)
+ 5 = change_to(cust2), return(1)
+ 6 = change_to(cust2), return(1)
+ 7 = change_to(cust3), return(1)
+ 8 = change_to(cust4), return(1)
+ 9 = change_to(cust5), return(1)
+ * = return(1) ; return Main Menu
+
+;-----------------------------------------------------------;
+;
+; Voicemail Menu Options
+; In this menu there are the voicemail manage operations as
+; recording a welcome message or changing the password.
+
+
+[opts_menu]
+ init = play(vm_opts_intro)
+ default = play(vm_opts_intro)
+ 1 = record(unavailable) ; record a unavailable message
+ 2 = record(busy) ; record a busy message
+ 3 = record(name) ; record a welcome message
+ 4 = changepassword() ; change the user password
+ * = return(1) ; return Main Menu
+
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample
------------------------------------------------------------------------------
svn:keywords = brushtyler 2009-06-10
Propchange: team/brushtyler/voicemail_menu_branch/apps/myvm/voicemail_menu.conf.sample
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/brushtyler/voicemail_menu_branch/apps/newvoicemail.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/brushtyler/voicemail_menu_branch/apps/newvoicemail.c?view=auto&rev=199855
==============================================================================
--- team/brushtyler/voicemail_menu_branch/apps/newvoicemail.c (added)
+++ team/brushtyler/voicemail_menu_branch/apps/newvoicemail.c Wed Jun 10 09:51:11 2009
@@ -1,0 +1,2700 @@
+/*
+ * A new voicemail application where all policies are configurable
+ * through a configuration file and not hardwired in the code.
+ * At the moment the file is made of three parts:
+ * header (the first 1200 lines), main body, footer. The main body can be included in the
+ * original app_voicemail.c to replace some of its functions,
+ * while header and footer are the glue to let the file compile by itself.
+ */
+
+#ifdef MYVM_STANDALONE
+/*!-------------------------------------------------------------*/
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 86820 $")
+
+#include "asterisk/paths.h"
+#include <dirent.h>
+
+
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/options.h"
+#include "asterisk/config.h"
+#include "asterisk/say.h"
+#include "asterisk/module.h"
+#include "asterisk/app.h"
+#include "asterisk/manager.h"
+#include "asterisk/localtime.h"
+#include "asterisk/cli.h"
+#include "asterisk/utils.h"
+#include "asterisk/smdi.h"
+#include "asterisk/event.h"
+
+#ifdef ODBC_STORAGE
+#include "asterisk/res_odbc.h"
+#endif
+
+/*
+ * Various constants used mostly in the old code.
+ */
+#define VOICEMAIL_CONFIG "voicemail.conf"
+#define VM_REVIEW (1 << 0)
+#define VM_OPERATOR (1 << 1)
+#define VM_SAYCID (1 << 2)
+#define VM_SVMAIL (1 << 3)
+#define VM_ENVELOPE (1 << 4)
+#define VM_SAYDURATION (1 << 5)
+#define VM_SKIPAFTERCMD (1 << 6)
+#define VM_FORCENAME (1 << 7) /*!< Have new users record their name */
+#define VM_FORCEGREET (1 << 8) /*!< Have new users record their greetings */
+#define VM_PBXSKIP (1 << 9)
+#define VM_DIRECFORWARD (1 << 10) /*!< directory_forward */
+#define VM_ATTACH (1 << 11)
+#define VM_DELETE (1 << 12)
+#define VM_ALLOCED (1 << 13)
+#define VM_SEARCH (1 << 14)
+#define VM_TEMPGREETWARN (1 << 15) /*!< Remind user tempgreeting is set */
+#define VM_MOVEHEARD (1 << 16) /*!< Move a "heard" message to Old after listening to it */
+#define RETRIEVE(a,b,c,d)
+#define DISPOSE(a,b)
+#define STORE(a,b,c,d,e,f,g,h,i)
+#define MAX_NUM_CID_CONTEXTS 10
+#define ERROR_LOCK_PATH -100
+#define MAXMSG 100
+#define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
+#define VOICEMAIL_FILE_MODE 0666
+#define VOICEMAIL_DIR_MODE 0777
+#define VM_MOVEHEARD (1 << 16) /*!< Move a "heard" message to Old after listening to it */
+#define MAXMSGLIMIT 9999
+#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
+#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
+#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
+#define DELETE(a,b,c) (vm_delete(c))
+#define SENDMAIL "/usr/sbin/sendmail -t"
+#define PWDCHANGE_INTERNAL (1 << 1)
+#define PWDCHANGE_EXTERNAL (1 << 2)
+#define ASTERISK_USERNAME "asterisk"
+#define VALID_DTMF "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
+/*! --- */
+
+/*
+ * Config arguments, buffers and so on
+ */
+static char ext_pass_cmd[128]; /* [general] externpass = ... */
+static char userscontext[AST_MAX_EXTENSION] = "default"; /* [general] userscontext = ... */
+static char dialcontext[AST_MAX_CONTEXT] = ""; /* [general] dialout = ... */
+static char callcontext[AST_MAX_CONTEXT] = ""; /* [general] callback = ... */
+static char exitcontext[AST_MAX_CONTEXT] = "";
+static int saydurationminfo;
+static char mailcmd[160]; /* Configurable mail cmd */
+static char vmfmts[80];
+static char vm_spool_dir[PATH_MAX];
+static struct ast_flags globalflags = {0};
+static struct ast_smdi_interface *smdi_iface = NULL;
+static AST_LIST_HEAD_STATIC(zones, vm_zone);
+static AST_LIST_HEAD_STATIC(users, ast_vm_user);
+static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
+static int skipms;
+static int vmmaxsecs;
+static double volgain;
+static int maxmsg;
+static int vmminsecs;
+static int maxgreet;
+static int silencethreshold = 128;
+static char serveremail[80];
+static int maxlogins;
+static int maxsilence;
+static char externnotify[160];
+static char emaildateformat[32] = "%A, %B %d, %Y at %r";
+static int pwdchange = PWDCHANGE_INTERNAL;
+/* custom audio control prompts for voicemail playback */
+static char listen_control_forward_key[12];
+static char listen_control_reverse_key[12];
+static char listen_control_pause_key[12];
+static char listen_control_restart_key[12];
+static char listen_control_stop_key[12];
+
+/* Check mail, control, etc */
+static char *app2 = "VoiceMailMain2";
+/*static char *synopsis_vmain = "Check Voicemail messages";
+static char *descrip_vmain =
+ " VoiceMailMain([mailbox][@context][,options]): This application allows the\n"
+ "calling party to check voicemail messages. A specific mailbox, and optional\n"
+ "corresponding context, may be specified. If a mailbox is not provided, the\n"
+ "calling party will be prompted to enter one. If a context is not specified,\n"
+ "the 'default' context will be used.\n\n"
+ " Options:\n"
+ " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
+ " is entered by the caller.\n"
+ " g(#) - Use the specified amount of gain when recording a voicemail\n"
+ " message. The units are whole-number decibels (dB).\n"
+ " s - Skip checking the passcode for the mailbox.\n"
+ " a(#) - Skip folder prompt and go directly to folder specified.\n"
+ " Defaults to INBOX\n";
+*/
+
+/*! Poll mailboxes for changes since there is something external to
+ * app_voicemail that may change them. */
+static unsigned int poll_mailboxes;
+
+/*! Polling frequency */
+static unsigned int poll_freq;
+/*! By default, poll every 30 seconds */
+#define DEFAULT_POLL_FREQ 30
+
+static char *emailbody = NULL;
+static char *emailsubject = NULL;
+static char *pagerbody = NULL;
+static char *pagersubject = NULL;
+static char fromstring[100];
+static char pagerfromstring[100];
+static char emailtitle[100];
+static char charset[32] = "ISO-8859-1";
+
+static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
+static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
+static int adsiver = 1;
+/*! --- */
+
+/*! STRUCTS */
+
+enum {
+ OPT_SILENT = (1 << 0),
+ OPT_BUSY_GREETING = (1 << 1),
+ OPT_UNAVAIL_GREETING = (1 << 2),
+ OPT_RECORDGAIN = (1 << 3),
+ OPT_PREPEND_MAILBOX = (1 << 4),
+ OPT_AUTOPLAY = (1 << 6),
+} vm_option_flags;
+
+enum {
+ OPT_ARG_RECORDGAIN = 0,
+ OPT_ARG_PLAYFOLDER = 1,
+ /* This *must* be the last value in this enum! */
+ OPT_ARG_ARRAY_SIZE = 2,
+} vm_option_args;
+
+AST_APP_OPTIONS(vm_app_options, {
+ AST_APP_OPTION('s', OPT_SILENT),
+ AST_APP_OPTION('b', OPT_BUSY_GREETING),
+ AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
+ AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
+ AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
+ AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
+});
+
+/*this structure contains value of some variables defined in this function
+ * and needed to call voicemail function by the do_menu*/
+
+struct leave_vm_options {
+ unsigned int flags;
+ signed char record_gain;
+};
+
+/*! Voicemail time zones */
+struct vm_zone {
+ AST_LIST_ENTRY(vm_zone) list;
+ char name[80];
+ char timezone[80];
+ char msg_format[512];
+};
+
+/* There is apparently support for a fixed number of folders */
+static int map_folder(const char *mbox_name)
+{
+ return 0; /* XXX must be fixed */
+}
+
+static const char *mbox(int id)
+{
+ static const char *msgs[] = {
+ "INBOX",
+ "Old",
+ "Work",
+ "Family",
+ "Friends",
+ "Cust1",
+ "Cust2",
+ "Cust3",
+ "Cust4",
+ "Cust5",
+ };
+ return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown";
+}
+
+struct vmstate {
+ struct vm_state *vms;
+ AST_LIST_ENTRY(vmstate) list;
+};
+
+struct ast_vm_user {
+ char context[AST_MAX_CONTEXT]; /*!< Voicemail context */
+ char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
+ char password[80]; /*!< Secret pin code, numbers only */
+ char fullname[80]; /*!< Full name, for directory app */
+ char email[80]; /*!< E-mail address */
+ char pager[80]; /*!< E-mail address to pager (no attachment) */
+ char serveremail[80]; /*!< From: Mail address */
+ char mailcmd[160]; /*!< Configurable mail command */
+ char language[MAX_LANGUAGE]; /*!< Config: Language setting */
+ char zonetag[80]; /*!< Time zone */
+ char callback[80];
+ char dialout[80];
+ char uniqueid[20]; /*!< Unique integer identifier */
+ char exit[80];
+ char attachfmt[20]; /*!< Attachment format */
+ unsigned int flags; /*!< VM_ flags */
+ int saydurationm;
+ int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */
+ int maxsecs; /*!< Maximum number of seconds per message for this mailbox */
+#ifdef IMAP_STORAGE
+ char imapuser[80]; /*!< IMAP server login */
+ char imappassword[80]; /*!< IMAP server password if authpassword not defined */
+#endif
+ double volgain; /*!< Volume gain for voicemails sent via email */
+ AST_LIST_ENTRY(ast_vm_user) list;
+};
+
+/*! Voicemail mailbox state */
+struct vm_state {
+ char str_dig[80]; /*!< Buffer representing pattern digited by user >*/
+ char curbox[80];
+ char username[80];
+ char curdir[PATH_MAX];
+ char vmbox[PATH_MAX];
+ char fn[PATH_MAX];
+ char fn2[PATH_MAX];
+ int *deleted;
+ int *heard;
+ int curmsg;
+ int lastmsg;
+ int newmessages;
+ int oldmessages;
+ int starting;
+ int repeats;
+#ifdef IMAP_STORAGE
+ int updated; /*!< decremented on each mail check until 1 -allows delay */
+ long msgArray[256];
+ MAILSTREAM *mailstream;
+ int vmArrayIndex;
+ char imapuser[80]; /*!< IMAP server login */
+ int interactive;
+ unsigned int quota_limit;
+ unsigned int quota_usage;
+ struct vm_state *persist_vms;
+#endif
+};
+
+enum vm_folder {
+ NEW_FOLDER,
+ OLD_FOLDER,
+ WORK_FOLDER,
+ FAMILY_FOLDER,
+ FRIENDS_FOLDER,
+ GREETINGS_FOLDER
+};
+
+/*!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/*!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/*!++++++++++++++++++++++++++HERE START CODE EXPORTED++++++++++++++++++++++++++++++++*/
+/*!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/*!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/*forward declarations*/
+
+/* functions now in app_voicemail.c used from here */
+static int load_config(int);
+#if 0
+static int vmu_debug(struct ast_vm_user* vmu);
+static int vms_debug(struct vm_state* vms);
+#endif
+
+static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms);
+static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms);
+/*static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms,
+ struct ast_vm_user *sender, char *fmt, int flag,signed char record_gain);*/
+/*static void adsi_folders(struct ast_channel *chan, int start, char *label);
+static int get_folder2(struct ast_channel *chan, char *fn, int start);
+static void adsi_delete(struct ast_channel *chan, struct vm_state *vms);
+static void adsi_status2(struct ast_channel *chan, struct vm_state *vms);*/
+static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu);
+static void apply_options(struct ast_vm_user *vmu, const char *options);
+static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, const char *box);
+#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
+static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
+#endif
+static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+static void populate_defaults(struct ast_vm_user *vmu)
+{
+ ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
+ if (saydurationminfo)
+ vmu->saydurationm = saydurationminfo;
+ ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
+ ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
+ ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
+ if (vmmaxsecs)
+ vmu->maxsecs = vmmaxsecs;
+ if (maxmsg)
+ vmu->maxmsg = maxmsg;
+ vmu->volgain = volgain;
+}
+
+static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
+{
+ int x;
+ if (!strcasecmp(var, "attach")) {
+ ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
+ } else if (!strcasecmp(var, "attachfmt")) {
+ ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
+ } else if (!strcasecmp(var, "serveremail")) {
+ ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
+ } else if (!strcasecmp(var, "language")) {
+ ast_copy_string(vmu->language, value, sizeof(vmu->language));
+ } else if (!strcasecmp(var, "tz")) {
+ ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
+#ifdef IMAP_STORAGE
+ } else if (!strcasecmp(var, "imapuser")) {
+ ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
+ } else if (!strcasecmp(var, "imappassword")) {
+ ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
+#endif
+ } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
+ ast_set2_flag(vmu, ast_true(value), VM_DELETE);
+ } else if (!strcasecmp(var, "saycid")){
+ ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
+ } else if (!strcasecmp(var,"sendvoicemail")){
+ ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
+ } else if (!strcasecmp(var, "review")){
+ ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
+ } else if (!strcasecmp(var, "tempgreetwarn")){
+ ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
+ } else if (!strcasecmp(var, "operator")){
+ ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
+ } else if (!strcasecmp(var, "envelope")){
+ ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
+ } else if (!strcasecmp(var, "moveheard")){
+ ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
+ } else if (!strcasecmp(var, "sayduration")){
+ ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
+ } else if (!strcasecmp(var, "saydurationm")){
+ if (sscanf(value, "%d", &x) == 1) {
+ vmu->saydurationm = x;
+ } else {
+ ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
+ }
+ } else if (!strcasecmp(var, "forcename")){
+ ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
+ } else if (!strcasecmp(var, "forcegreetings")){
+ ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
+ } else if (!strcasecmp(var, "callback")) {
+ ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
+ } else if (!strcasecmp(var, "dialout")) {
+ ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
+ } else if (!strcasecmp(var, "exitcontext")) {
+ ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
+ } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
+ if (vmu->maxsecs <= 0) {
+ ast_log(LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
+ vmu->maxsecs = vmmaxsecs;
+ } else {
+ vmu->maxsecs = atoi(value);
+ }
+ if (!strcasecmp(var, "maxmessage"))
+ ast_log(LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
+ } else if (!strcasecmp(var, "maxmsg")) {
+ vmu->maxmsg = atoi(value);
+ if (vmu->maxmsg <= 0) {
+ ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
+ vmu->maxmsg = MAXMSG;
+ } else if (vmu->maxmsg > MAXMSGLIMIT) {
+ ast_log(LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
+ vmu->maxmsg = MAXMSGLIMIT;
+ }
+ } else if (!strcasecmp(var, "volgain")) {
+ sscanf(value, "%lf", &vmu->volgain);
+ } else if (!strcasecmp(var, "options")) {
+ apply_options(vmu, value);
+ }
+}
+
+static void apply_options(struct ast_vm_user *vmu, const char *options)
+{ /* Destructively Parse options and apply */
+ char *stringp;
+ char *s;
+ char *var, *value;
+ stringp = ast_strdupa(options);
+ while ((s = strsep(&stringp, "|"))) {
+ value = s;
+ if ((var = strsep(&value, "=")) && value) {
+ apply_option(vmu, var, value);
+ }
+ }
+}
+
+static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
+{
+ struct ast_variable *tmp;
+ for (tmp = var; tmp; tmp = tmp->next) {
+ if (!strcasecmp(tmp->name, "vmsecret")) {
+ ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
+ } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) { /* don't overwrite vmsecret if it exists */
+ if (ast_strlen_zero(retval->password))
+ ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
+ } else if (!strcasecmp(tmp->name, "uniqueid")) {
+ ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
+ } else if (!strcasecmp(tmp->name, "pager")) {
+ ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
+ } else if (!strcasecmp(tmp->name, "email")) {
+ ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
+ } else if (!strcasecmp(tmp->name, "fullname")) {
+ ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
+ } else if (!strcasecmp(tmp->name, "context")) {
+ ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
+#ifdef IMAP_STORAGE
+ } else if (!strcasecmp(tmp->name, "imapuser")) {
+ ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
+ } else if (!strcasecmp(tmp->name, "imappassword")) {
+ ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
+#endif
+ } else
+ apply_option(retval, tmp->name, tmp->value);
+ }
+}
+
+#if 0 /* unused */
+static int is_valid_dtmf(const char *key)
+{
+ int i;
+ char *local_key = ast_strdupa(key);
+
+ for(i = 0; i < strlen(key); ++i) {
+ if(!strchr(VALID_DTMF, *local_key)) {
+ ast_log(LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
+ return 0;
+ }
+ local_key++;
+ }
+ return 1;
+}
+#endif
+
+
+static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
+{
+ struct ast_variable *var;
+ struct ast_vm_user *retval;
+
+ if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
+ if (!ivm)
+ ast_set_flag(retval, VM_ALLOCED);
+ else
+ memset(retval, 0, sizeof(*retval));
+ if (mailbox)
+ ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
+ populate_defaults(retval);
+ if (!context && ast_test_flag((&globalflags), VM_SEARCH))
+ var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
+ else
+ var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
+ if (var) {
+ apply_options_full(retval, var);
+ ast_variables_destroy(var);
+ } else {
+ if (!ivm)
+ ast_free(retval);
+ retval = NULL;
+ }
+ }
+ if (retval == NULL)
+ fprintf(stderr, "Utente NON TROVATO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ return retval;
+}
+
+
+static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
+{
+ /* This function could be made to generate one from a database, too */
+ struct ast_vm_user *vmu=NULL, *cur;
+ if( (AST_LIST_LOCK(&users)) != 0) /*0 on success*/
+ fprintf(stderr, "Error Locking User List\n");
+ if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
+ context = "default";
+
+ AST_LIST_TRAVERSE(&users, cur, list) {
+ if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
+ break;
+ if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
+ break;
+ }
+ if (cur) {
+ /* Make a copy, so that on a reload, we have no race */
+ if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
+ memcpy(vmu, cur, sizeof(*vmu));
+ ast_set2_flag(vmu, !ivm, VM_ALLOCED);
+ AST_LIST_NEXT(vmu, list) = NULL;
+ }
+ } else
+ vmu = find_user_realtime(ivm, context, mailbox);
+ AST_LIST_UNLOCK(&users);
+ return vmu;
+}
+
+static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
+{
+ return snprintf(dest, len, "%s%s/%s/%s", vm_spool_dir, context, ext, folder);
+}
+
+static int make_file(char *dest, int len, char *dir, int num)
+{
+ return snprintf(dest, len, "%s/msg%04d", dir, num);
+}
+
+/*! \brief basically mkdir -p $dest/$context/$ext/$folder
+ * \param dest String. base directory.
+ * \param len Length of dest.
+ * \param context String. Ignored if is null or empty string.
+ * \param ext String. Ignored if is null or empty string.
+ * \param folder String. Ignored if is null or empty string.
+ * \return -1 on failure, 0 on success.
+ */
+static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
+{
+ mode_t mode = VOICEMAIL_DIR_MODE;
+ int res;
+ make_dir(dest, len, context, ext, folder);
+ if ((res = ast_mkdir(dest, mode))) {
+ ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
+ return -1;
+ }
+ return 0;
+}
+
+/*! \brief Lock file path
+ only return failure if ast_lock_path returns 'timeout',
+ not if the path does not exist or any other reason
+ */
+static int vm_lock_path(const char *path)
+{
+ switch (ast_lock_path(path)) {
+ case AST_LOCK_TIMEOUT:
+ return -1;
+ default:
+ return 0;
+ }
+}
+
+static int count_messages(struct ast_vm_user *vmu, char *dir)
+{
+ /* Find all .txt files - even if they are not in sequence from 0000 */
+
+ int vmcount = 0;
+ DIR *vmdir = NULL;
+ struct dirent *vment = NULL;
+
+ if (vm_lock_path(dir))
+ return ERROR_LOCK_PATH;
+
+ if ((vmdir = opendir(dir))) {
+ while ((vment = readdir(vmdir))) {
+ if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
+ vmcount++;
+ }
+ closedir(vmdir);
+ }
+ ast_unlock_path(dir);
+
+ return vmcount;
+}
+
+static void rename_file(char *sfn, char *dfn)
+{
+ char stxt[PATH_MAX];
+ char dtxt[PATH_MAX];
+ ast_filerename(sfn,dfn,NULL);
+ snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
+ snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
+ if (ast_check_realtime("voicemail_data")) {
+ ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, NULL);
+ }
+ rename(stxt, dtxt);
+}
+
+static int copy(char *infile, char *outfile)
+{
+ int ifd;
+ int ofd;
+ int res;
+ int len;
+ char buf[4096];
+
+#ifdef HARDLINK_WHEN_POSSIBLE
+ /* Hard link if possible; saves disk space & is faster */
+ if (link(infile, outfile)) {
+#endif
+ if ((ifd = open(infile, O_RDONLY)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
+ return -1;
+ }
+ if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
+ close(ifd);
+ return -1;
+ }
+ do {
+ len = read(ifd, buf, sizeof(buf));
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
+ close(ifd);
+ close(ofd);
+ unlink(outfile);
+ }
+ if (len) {
+ res = write(ofd, buf, len);
+ if (errno == ENOMEM || errno == ENOSPC || res != len) {
[... 2058 lines stripped ...]
More information about the asterisk-commits
mailing list