[svn-commits] brushtyler: branch brushtyler/voicemail_menu_branch r199855 - in /team/brusht...

SVN commits to the Digium repositories svn-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 svn-commits mailing list