Mon Mar 12 2012 21:23:54

Asterisk developer's documentation


app_minivm.c File Reference

MiniVoiceMail - A Minimal Voicemail System for Asterisk. More...

#include "asterisk.h"
#include <ctype.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <time.h>
#include <dirent.h>
#include <locale.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/dsp.h"
#include "asterisk/localtime.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/callerid.h"
#include "asterisk/event.h"
Include dependency graph for app_minivm.c:

Go to the source code of this file.

Data Structures

struct  b64_baseio
 Structure for base64 encoding. More...
struct  leave_vm_options
 Options for leaving voicemail with the voicemail() application. More...
struct  message_templates
 The list of e-mail templates. More...
struct  minivm_account
struct  minivm_accounts
struct  minivm_stats
 Structure for gathering statistics. More...
struct  minivm_template
struct  minivm_zone
 Voicemail time zones. More...
struct  minivm_zones
 The list of e-mail time zones. More...

Defines

#define ASTERISK_USERNAME   "asterisk"
#define B64_BASELINELEN   72
#define B64_BASEMAXINLINE   256
#define DEFAULT_CHARSET   "ISO-8859-1"
#define DEFAULT_DATEFORMAT   "%A, %B %d, %Y at %r"
#define EOL   "\r\n"
#define ERROR_LOCK_PATH   -100
#define FALSE   0
#define HMSU_OUTPUT_FORMAT   "%-23s %-15s %-15s %-10s %-10s %-50s\n"
#define HMSZ_OUTPUT_FORMAT   "%-15s %-20s %-45s\n"
#define HVLT_OUTPUT_FORMAT   "%-15s %-10s %-10s %-15.15s %-50s\n"
#define MAX_DATETIME_FORMAT   512
#define MAX_NUM_CID_CONTEXTS   10
#define MVM_ALLOCED   (1 << 13)
#define MVM_ENVELOPE   (1 << 4)
#define MVM_OPERATOR   (1 << 1)
#define MVM_PBXSKIP   (1 << 9)
#define MVM_REALTIME   (1 << 2)
#define MVM_REVIEW   (1 << 0)
#define MVM_SVMAIL   (1 << 3)
#define SENDMAIL   "/usr/sbin/sendmail -t"
 Default mail command to mail voicemail. Change it with the mailcmd= command in voicemail.conf.
#define SOUND_INTRO   "vm-intro"
#define TRUE   1
#define VOICEMAIL_CONFIG   "minivm.conf"
#define VOICEMAIL_DIR_MODE   0700

Enumerations

enum  minivm_option_args { OPT_ARG_RECORDGAIN = 0, OPT_ARG_ARRAY_SIZE = 1 }
enum  minivm_option_flags {
  OPT_SILENT = (1 << 0), OPT_BUSY_GREETING = (1 << 1), OPT_UNAVAIL_GREETING = (1 << 2), OPT_TEMP_GREETING = (1 << 3),
  OPT_NAME_GREETING = (1 << 4), OPT_RECORDGAIN = (1 << 5)
}
enum  mvm_messagetype { MVM_MESSAGE_EMAIL, MVM_MESSAGE_PAGE }
 Message types for notification. More...

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int access_counter_file (char *directory, char *countername, int value, int operand)
 Access counter file, lock directory, read and possibly write it again changed.
static int apply_general_options (struct ast_variable *var)
 Apply general configuration options.
static const char * ast_str_encode_mime (struct ast_str **end, ssize_t maxlen, const char *charset, const char *start, size_t preamble, size_t postamble)
static const char * ast_str_quote (struct ast_str **buf, ssize_t maxlen, const char *from)
static int b64_inbuf (struct b64_baseio *bio, FILE *fi)
static int b64_inchar (struct b64_baseio *bio, FILE *fi)
static int b64_ochar (struct b64_baseio *bio, int c, FILE *so)
static int base_encode (char *filename, FILE *so)
static int check_dirpath (char *dest, int len, char *domain, char *username, char *folder)
static int check_mime (const char *str)
static char * complete_minivm_show_users (const char *line, const char *word, int pos, int state)
static int create_dirpath (char *dest, int len, char *domain, char *username, char *folder)
static int create_vmaccount (char *name, struct ast_variable *var, int realtime)
 Append new mailbox to mailbox list from configuration file.
static struct minivm_accountfind_account (const char *domain, const char *username, int createtemp)
static struct minivm_accountfind_user_realtime (const char *domain, const char *username)
static void free_user (struct minivm_account *vmu)
static void free_zone (struct minivm_zone *z)
 Free Mini Voicemail timezone.
static int get_date (char *s, int len)
static char * handle_minivm_list_templates (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI routine for listing templates.
static char * handle_minivm_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Reload cofiguration.
static char * handle_minivm_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI Show settings.
static char * handle_minivm_show_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show stats.
static char * handle_minivm_show_users (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list voicemail accounts.
static char * handle_minivm_show_zones (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show a list of voicemail zones in the CLI.
static int invent_message (struct ast_channel *chan, char *domain, char *username, int busy, char *ecodes)
static int leave_voicemail (struct ast_channel *chan, char *username, struct leave_vm_options *options)
static int load_config (int reload)
 Load minivoicemail configuration.
static int load_module (void)
 Load mini voicemail module.
static int make_dir (char *dest, int len, const char *domain, const char *username, const char *folder)
static void message_destroy_list (void)
static int message_template_build (const char *name, struct ast_variable *var)
static struct minivm_templatemessage_template_create (const char *name)
static struct minivm_templatemessage_template_find (const char *name)
static void message_template_free (struct minivm_template *template)
static char * message_template_parse_emailbody (const char *configuration)
 Parse emailbody template from configuration file.
static char * message_template_parse_filebody (const char *filename)
 Read message template from file.
static int minivm_accmess_exec (struct ast_channel *chan, const char *data)
 Record specific messages for voicemail account.
static int minivm_account_func_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${MINIVMACCOUNT()} Dialplan function - reads account data
static int minivm_counter_func_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${MINIVMCOUNTER()} Dialplan function - read counters
static int minivm_counter_func_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 ${MINIVMCOUNTER()} Dialplan function - changes counter data
static int minivm_delete_exec (struct ast_channel *chan, const char *data)
static int minivm_greet_exec (struct ast_channel *chan, const char *data)
static int minivm_mwi_exec (struct ast_channel *chan, const char *data)
static int minivm_notify_exec (struct ast_channel *chan, const char *data)
static int minivm_record_exec (struct ast_channel *chan, const char *data)
static struct minivm_accountmvm_user_alloc (void)
static int notify_new_message (struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
static int play_record_review (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct minivm_account *vmu, int *duration, int *sound_duration, const char *unlockdir, signed char record_gain)
static void populate_defaults (struct minivm_account *vmu)
static void prep_email_sub_vars (struct ast_channel *channel, const struct minivm_account *vmu, const char *cidnum, const char *cidname, const char *dur, const char *date, const char *counter)
static void queue_mwi_event (const char *mbx, const char *ctx, int urgent, int new, int old)
static int reload (void)
 Reload mini voicemail module.
static void run_externnotify (struct ast_channel *chan, struct minivm_account *vmu)
 Run external notification for voicemail message.
static int sendmail (struct minivm_template *template, struct minivm_account *vmu, char *cidnum, char *cidname, const char *filename, char *format, int duration, int attach_user_voicemail, enum mvm_messagetype type, const char *counter)
static int timezone_add (const char *zonename, const char *config)
 Add time zone to memory list.
static void timezone_destroy_list (void)
 Clear list of timezones.
static int unload_module (void)
 Unload mini voicemail module.
static int vm_delete (char *file)
static int vm_lock_path (const char *path)
 lock directory
static void vmaccounts_destroy_list (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mini VoiceMail (A minimal Voicemail e-mail System)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * app_minivm_accmess = "MinivmAccMess"
static char * app_minivm_delete = "MinivmDelete"
static char * app_minivm_greet = "MinivmGreet"
static char * app_minivm_mwi = "MinivmMWI"
static char * app_minivm_notify = "MinivmNotify"
static char * app_minivm_record = "MinivmRecord"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_minivm []
 CLI commands for Mini-voicemail.
static char default_vmformat [80]
static char global_externnotify [160]
static char global_logfile [PATH_MAX]
static char global_mailcmd [160]
static int global_maxgreet
static int global_maxsilence
static int global_saydurationminfo
static int global_silencethreshold = 128
static struct minivm_stats global_stats
 Statistics for voicemail.
static int global_vmmaxmessage
static int global_vmminmessage
static double global_volgain
static struct ast_flags globalflags = {0}
static struct message_templates message_templates
static struct ast_app_option minivm_accmess_options [128] = { [ 'b' ] = { .flag = OPT_BUSY_GREETING }, [ 'u' ] = { .flag = OPT_UNAVAIL_GREETING }, [ 't' ] = { .flag = OPT_TEMP_GREETING }, [ 'n' ] = { .flag = OPT_NAME_GREETING },}
static struct ast_custom_function minivm_account_function
static struct minivm_accounts minivm_accounts
static struct ast_app_option minivm_app_options [128] = { [ 's' ] = { .flag = OPT_SILENT }, [ 'b' ] = { .flag = OPT_BUSY_GREETING }, [ 'u' ] = { .flag = OPT_UNAVAIL_GREETING }, [ 'g' ] = { .flag = OPT_RECORDGAIN , .arg_index = OPT_ARG_RECORDGAIN + 1 },}
static struct ast_custom_function minivm_counter_function
static struct minivm_zones minivm_zones
static ast_mutex_t minivmlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static FILE * minivmlogfile
static ast_mutex_t minivmloglock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static char MVM_SPOOL_DIR [PATH_MAX]

Detailed Description

MiniVoiceMail - A Minimal Voicemail System for Asterisk.

A voicemail system in small building blocks, working together based on the Comedian Mail voicemail system (app_voicemail.c).

See also

Definition in file app_minivm.c.


Define Documentation

#define ASTERISK_USERNAME   "asterisk"

Default username for sending mail is asterisk@localhost

Definition at line 534 of file app_minivm.c.

#define B64_BASELINELEN   72

Line length for Base 64 endoded messages

Definition at line 524 of file app_minivm.c.

Referenced by b64_ochar().

#define B64_BASEMAXINLINE   256

Buffer size for Base 64 attachment encoding

Definition at line 523 of file app_minivm.c.

Referenced by b64_inbuf(), and base_encode().

#define DEFAULT_CHARSET   "ISO-8859-1"

Definition at line 697 of file app_minivm.c.

Referenced by message_template_create().

#define DEFAULT_DATEFORMAT   "%A, %B %d, %Y at %r"

Definition at line 696 of file app_minivm.c.

Referenced by message_template_create().

#define EOL   "\r\n"

Definition at line 525 of file app_minivm.c.

Referenced by b64_ochar(), and base_encode().

#define ERROR_LOCK_PATH   -100

Definition at line 530 of file app_minivm.c.

Referenced by minivm_record_exec().

#define FALSE   0

Definition at line 506 of file app_minivm.c.

Referenced by __sip_ack(), __sip_semi_ack(), _sip_qualify_peer(), _sip_show_peer(), _sip_show_peers(), add_sdp(), ast_tzset(), build_peer(), cb_extensionstate(), cc_esc_publish_handler(), cc_handle_publish_error(), check_auth(), check_dirpath(), check_peer_ok(), check_pendings(), create_addr(), do_monitor(), expire_register(), find_sdp(), function_sippeer(), handle_invite_replaces(), handle_request_invite(), handle_request_notify(), handle_request_refer(), handle_request_subscribe(), handle_response(), handle_response_invite(), interpret_t38_parameters(), invent_message(), load_config(), minivm_accmess_exec(), minivm_counter_func_read(), minivm_counter_func_write(), parse_register_contact(), pidf_validate_presence(), pidf_validate_tuple(), proc_session_timer(), process_crypto(), process_sdp(), process_sdp_a_audio(), process_sdp_a_image(), process_sdp_a_sendonly(), process_sdp_a_text(), process_sdp_a_video(), process_sdp_c(), process_sdp_o(), proxy_update(), rcvfax_exec(), register_verify(), reload_config(), reqprep(), send_provisional_keepalive_full(), set_destination(), sip_addheader(), sip_answer(), sip_cc_monitor_request_cc(), sip_destroy_peer(), sip_devicestate(), sip_do_debug_peer(), sip_hangup(), sip_is_xml_parsable(), sip_monitor_instance_destructor(), sip_pidf_validate(), sip_poke_noanswer(), sip_prune_realtime(), sip_read(), sip_reg_timeout(), sip_sendhtml(), sip_set_history(), sip_set_rtp_peer(), sip_set_udptl_peer(), sip_show_inuse(), sip_show_settings(), sip_show_user(), sip_show_users(), sndfax_exec(), stop_session_timer(), time1(), time2(), time2sub(), transmit_audio(), transmit_fake_auth_response(), transmit_invite(), transmit_provisional_response(), transmit_publish(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_t38(), tzload(), tzparse(), update_call_counter(), and update_connectedline().

#define HMSU_OUTPUT_FORMAT   "%-23s %-15s %-15s %-10s %-10s %-50s\n"
#define HMSZ_OUTPUT_FORMAT   "%-15s %-20s %-45s\n"
#define HVLT_OUTPUT_FORMAT   "%-15s %-10s %-10s %-15.15s %-50s\n"
#define MAX_DATETIME_FORMAT   512

Definition at line 527 of file app_minivm.c.

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 528 of file app_minivm.c.

#define MVM_ALLOCED   (1 << 13)
#define MVM_ENVELOPE   (1 << 4)

Definition at line 514 of file app_minivm.c.

#define MVM_OPERATOR   (1 << 1)

Operator exit during voicemail recording

Definition at line 511 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), minivm_greet_exec(), and play_record_review().

#define MVM_PBXSKIP   (1 << 9)

Definition at line 515 of file app_minivm.c.

#define MVM_REALTIME   (1 << 2)

This user is a realtime account

Definition at line 512 of file app_minivm.c.

#define MVM_REVIEW   (1 << 0)

Review message

Definition at line 510 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), and play_record_review().

#define MVM_SVMAIL   (1 << 3)

Definition at line 513 of file app_minivm.c.

#define SENDMAIL   "/usr/sbin/sendmail -t"

Default mail command to mail voicemail. Change it with the mailcmd= command in voicemail.conf.

Definition at line 520 of file app_minivm.c.

Referenced by load_config().

#define SOUND_INTRO   "vm-intro"

Definition at line 522 of file app_minivm.c.

Referenced by minivm_greet_exec().

#define TRUE   1

Definition at line 503 of file app_minivm.c.

Referenced by __sip_ack(), __sip_autodestruct(), __sip_semi_ack(), _sip_qualify_peer(), _sip_show_peer(), _sip_show_peers(), add_sdp(), ast_tzset(), build_peer(), cc_esc_publish_handler(), check_auth(), check_dirpath(), check_peer_ok(), check_pendings(), create_addr(), find_account(), find_sdp(), find_user_realtime(), function_sippeer(), get_sip_pvt_byid_locked(), gmtload(), handle_request_invite(), handle_request_notify(), handle_request_refer(), handle_response(), handle_response_invite(), handle_response_peerpoke(), interpret_t38_parameters(), leave_voicemail(), load_config(), local_attended_transfer(), message_template_create(), minivm_accmess_exec(), minivm_account_func_read(), minivm_greet_exec(), minivm_notify_exec(), parse_ok_contact(), parse_register_contact(), pidf_validate_presence(), pidf_validate_tuple(), proc_session_timer(), process_crypto(), process_sdp(), process_sdp_a_audio(), process_sdp_a_image(), process_sdp_a_sendonly(), process_sdp_a_text(), process_sdp_a_video(), process_sdp_c(), process_sdp_o(), proxy_update(), rcvfax_exec(), realtime_peer(), reg_source_db(), register_verify(), reload_config(), reqprep(), respprep(), restart_session_timer(), set_destination(), sip_addheader(), sip_alloc(), sip_answer(), sip_cc_agent_respond(), sip_destroy(), sip_devicestate(), sip_do_debug_peer(), sip_hangup(), sip_indicate(), sip_is_xml_parsable(), sip_park_thread(), sip_pidf_validate(), sip_prune_realtime(), sip_reg_timeout(), sip_reload(), sip_request_call(), sip_scheddestroy(), sip_set_history(), sip_set_udptl_peer(), sip_show_channel(), sip_show_inuse(), sip_show_user(), sip_show_users(), sip_unregister(), sip_write(), sndfax_exec(), spandsp_fax_start(), st_get_se(), start_session_timer(), stop_session_timer(), temp_peer(), time1(), time2(), time2sub(), transmit_audio(), transmit_cc_notify(), transmit_invite(), transmit_publish(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_t38(), tzload(), tzparse(), and update_connectedline().

#define VOICEMAIL_CONFIG   "minivm.conf"

Definition at line 533 of file app_minivm.c.

Referenced by load_config().

#define VOICEMAIL_DIR_MODE   0700

Definition at line 531 of file app_minivm.c.


Enumeration Type Documentation

Enumerator:
OPT_ARG_RECORDGAIN 
OPT_ARG_ARRAY_SIZE 

Definition at line 564 of file app_minivm.c.

Enumerator:
OPT_SILENT 
OPT_BUSY_GREETING 
OPT_UNAVAIL_GREETING 
OPT_TEMP_GREETING 
OPT_NAME_GREETING 
OPT_RECORDGAIN 

Definition at line 555 of file app_minivm.c.

                         {
   OPT_SILENT =      (1 << 0),
   OPT_BUSY_GREETING =    (1 << 1),
   OPT_UNAVAIL_GREETING = (1 << 2),
   OPT_TEMP_GREETING = (1 << 3),
   OPT_NAME_GREETING = (1 << 4),
   OPT_RECORDGAIN =  (1 << 5),
};

Message types for notification.

Enumerator:
MVM_MESSAGE_EMAIL 
MVM_MESSAGE_PAGE 

Definition at line 537 of file app_minivm.c.

                     {
   MVM_MESSAGE_EMAIL,
   MVM_MESSAGE_PAGE
   /* For trunk: MVM_MESSAGE_JABBER, */
};

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 3576 of file app_minivm.c.

static void __unreg_module ( void  ) [static]

Definition at line 3576 of file app_minivm.c.

static int access_counter_file ( char *  directory,
char *  countername,
int  value,
int  operand 
) [static]

Access counter file, lock directory, read and possibly write it again changed.

Parameters:
directoryDirectory to crate file in
counternamefilename
valueIf set to zero, we only read the variable
operand0 to read, 1 to set new value, 2 to change
Returns:
-1 on error, otherwise counter value

Definition at line 3290 of file app_minivm.c.

References ast_debug, ast_log(), ast_unlock_path(), errno, LOG_ERROR, value, and vm_lock_path().

Referenced by minivm_counter_func_read(), and minivm_counter_func_write().

{
   char filename[BUFSIZ];
   char readbuf[BUFSIZ];
   FILE *counterfile;
   int old = 0, counter = 0;

   /* Lock directory */
   if (vm_lock_path(directory)) {
      return -1;  /* Could not lock directory */
   }
   snprintf(filename, sizeof(filename), "%s/%s.counter", directory, countername);
   if (operand != 1) {
      counterfile = fopen(filename, "r");
      if (counterfile) {
         if(fgets(readbuf, sizeof(readbuf), counterfile)) {
            ast_debug(3, "Read this string from counter file: %s\n", readbuf);
            old = counter = atoi(readbuf);
         }
         fclose(counterfile);
      }
   }
   switch (operand) {
   case 0:  /* Read only */
      ast_unlock_path(directory);
      ast_debug(2, "MINIVM Counter %s/%s: Value %d\n", directory, countername, counter);
      return counter;
      break;
   case 1: /* Set new value */
      counter = value;
      break;
   case 2: /* Change value */
      counter += value;
      if (counter < 0)  /* Don't allow counters to fall below zero */
         counter = 0;
      break;
   }
   
   /* Now, write the new value to the file */
   counterfile = fopen(filename, "w");
   if (!counterfile) {
      ast_log(LOG_ERROR, "Could not open counter file for writing : %s - %s\n", filename, strerror(errno));
      ast_unlock_path(directory);
      return -1;  /* Could not open file for writing */
   }
   fprintf(counterfile, "%d\n\n", counter);
   fclose(counterfile);
   ast_unlock_path(directory);
   ast_debug(2, "MINIVM Counter %s/%s: Old value %d New value %d\n", directory, countername, old, counter);
   return counter;
}
static int apply_general_options ( struct ast_variable var) [static]

Apply general configuration options.

Definition at line 2772 of file app_minivm.c.

References ast_config_AST_LOG_DIR, ast_copy_string(), ast_log(), ast_set2_flag, ast_strlen_zero(), ast_true(), default_vmformat, global_externnotify, global_logfile, global_mailcmd, global_maxgreet, global_maxsilence, global_silencethreshold, global_vmmaxmessage, global_vmminmessage, globalflags, LOG_WARNING, MVM_OPERATOR, MVM_REVIEW, ast_variable::name, ast_variable::next, and ast_variable::value.

Referenced by load_config().

{
   int error = 0;

   while (var) {
      /* Mail command */
      if (!strcmp(var->name, "mailcmd")) {
         ast_copy_string(global_mailcmd, var->value, sizeof(global_mailcmd)); /* User setting */
      } else if (!strcmp(var->name, "maxgreet")) {
         global_maxgreet = atoi(var->value);
      } else if (!strcmp(var->name, "maxsilence")) {
         global_maxsilence = atoi(var->value);
         if (global_maxsilence > 0)
            global_maxsilence *= 1000;
      } else if (!strcmp(var->name, "logfile")) {
         if (!ast_strlen_zero(var->value) ) {
            if(*(var->value) == '/')
               ast_copy_string(global_logfile, var->value, sizeof(global_logfile));
            else
               snprintf(global_logfile, sizeof(global_logfile), "%s/%s", ast_config_AST_LOG_DIR, var->value);
         }
      } else if (!strcmp(var->name, "externnotify")) {
         /* External voicemail notify application */
         ast_copy_string(global_externnotify, var->value, sizeof(global_externnotify));
      } else if (!strcmp(var->name, "silencetreshold")) {
         /* Silence treshold */
         global_silencethreshold = atoi(var->value);
      } else if (!strcmp(var->name, "maxmessage")) {
         int x;
         if (sscanf(var->value, "%30d", &x) == 1) {
            global_vmmaxmessage = x;
         } else {
            error ++;
            ast_log(LOG_WARNING, "Invalid max message time length\n");
         }
      } else if (!strcmp(var->name, "minmessage")) {
         int x;
         if (sscanf(var->value, "%30d", &x) == 1) {
            global_vmminmessage = x;
            if (global_maxsilence <= global_vmminmessage)
               ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
         } else {
            error ++;
            ast_log(LOG_WARNING, "Invalid min message time length\n");
         }
      } else if (!strcmp(var->name, "format")) {
         ast_copy_string(default_vmformat, var->value, sizeof(default_vmformat));
      } else if (!strcmp(var->name, "review")) {
         ast_set2_flag((&globalflags), ast_true(var->value), MVM_REVIEW);  
      } else if (!strcmp(var->name, "operator")) {
         ast_set2_flag((&globalflags), ast_true(var->value), MVM_OPERATOR);   
      }
      var = var->next;
   }
   return error;
}
static const char* ast_str_encode_mime ( struct ast_str **  end,
ssize_t  maxlen,
const char *  charset,
const char *  start,
size_t  preamble,
size_t  postamble 
) [static]

Definition at line 1158 of file app_minivm.c.

References ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_set(), and ast_str_strlen().

Referenced by sendmail().

{
   struct ast_str *tmp = ast_str_alloca(80);
   int first_section = 1;
   *end = '\0';

   ast_str_reset(*end);
   ast_str_set(&tmp, -1, "=?%s?Q?", charset);
   for (; *start; start++) {
      int need_encoding = 0;
      if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
         need_encoding = 1;
      }
      if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
         (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
         (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
         (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
         /* Start new line */
         ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
         ast_str_set(&tmp, -1, "=?%s?Q?", charset);
         first_section = 0;
      }
      if (need_encoding && *start == ' ') {
         ast_str_append(&tmp, -1, "_");
      } else if (need_encoding) {
         ast_str_append(&tmp, -1, "=%hhX", *start);
      } else {
         ast_str_append(&tmp, -1, "%c", *start);
      }
   }
   ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
   return ast_str_buffer(*end);
}
static const char* ast_str_quote ( struct ast_str **  buf,
ssize_t  maxlen,
const char *  from 
) [static]

Definition at line 1200 of file app_minivm.c.

References ast_str_append(), ast_str_buffer(), and ast_str_set().

Referenced by sendmail().

{
   const char *ptr;

   /* We're only ever passing 0 to maxlen, so short output isn't possible */
   ast_str_set(buf, maxlen, "\"");
   for (ptr = from; *ptr; ptr++) {
      if (*ptr == '"' || *ptr == '\\') {
         ast_str_append(buf, maxlen, "\\%c", *ptr);
      } else {
         ast_str_append(buf, maxlen, "%c", *ptr);
      }
   }
   ast_str_append(buf, maxlen, "\"");

   return ast_str_buffer(*buf);
}
static int b64_inbuf ( struct b64_baseio bio,
FILE *  fi 
) [static]

Definition at line 836 of file app_minivm.c.

References b64_baseio::ateof, B64_BASEMAXINLINE, b64_baseio::iobuf, b64_baseio::iocp, and b64_baseio::iolen.

Referenced by b64_inchar().

{
   int l;

   if (bio->ateof)
      return 0;

   if ((l = fread(bio->iobuf, 1, B64_BASEMAXINLINE,fi)) <= 0) {
      if (ferror(fi))
         return -1;

      bio->ateof = 1;
      return 0;
   }

   bio->iolen= l;
   bio->iocp= 0;

   return 1;
}
static int b64_inchar ( struct b64_baseio bio,
FILE *  fi 
) [static]

Definition at line 859 of file app_minivm.c.

References b64_inbuf(), b64_baseio::iobuf, b64_baseio::iocp, and b64_baseio::iolen.

Referenced by base_encode().

{
   if (bio->iocp >= bio->iolen) {
      if (!b64_inbuf(bio, fi))
         return EOF;
   }

   return bio->iobuf[bio->iocp++];
}
static int b64_ochar ( struct b64_baseio bio,
int  c,
FILE *  so 
) [static]

Definition at line 871 of file app_minivm.c.

References B64_BASELINELEN, EOL, and b64_baseio::linelength.

Referenced by base_encode().

{
   if (bio->linelength >= B64_BASELINELEN) {
      if (fputs(EOL,so) == EOF)
         return -1;

      bio->linelength= 0;
   }

   if (putc(((unsigned char) c), so) == EOF)
      return -1;

   bio->linelength++;

   return 1;
}
static int base_encode ( char *  filename,
FILE *  so 
) [static]

Definition at line 890 of file app_minivm.c.

References ast_log(), B64_BASEMAXINLINE, b64_inchar(), b64_ochar(), EOL, errno, b64_baseio::iocp, and LOG_WARNING.

Referenced by sendmail().

{
   unsigned char dtable[B64_BASEMAXINLINE];
   int i,hiteof= 0;
   FILE *fi;
   struct b64_baseio bio;

   memset(&bio, 0, sizeof(bio));
   bio.iocp = B64_BASEMAXINLINE;

   if (!(fi = fopen(filename, "rb"))) {
      ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
      return -1;
   }

   for (i= 0; i<9; i++) {
      dtable[i]= 'A'+i;
      dtable[i+9]= 'J'+i;
      dtable[26+i]= 'a'+i;
      dtable[26+i+9]= 'j'+i;
   }
   for (i= 0; i < 8; i++) {
      dtable[i+18]= 'S'+i;
      dtable[26+i+18]= 's'+i;
   }
   for (i= 0; i < 10; i++) {
      dtable[52+i]= '0'+i;
   }
   dtable[62]= '+';
   dtable[63]= '/';

   while (!hiteof){
      unsigned char igroup[3], ogroup[4];
      int c,n;

      igroup[0]= igroup[1]= igroup[2]= 0;

      for (n= 0; n < 3; n++) {
         if ((c = b64_inchar(&bio, fi)) == EOF) {
            hiteof= 1;
            break;
         }
         igroup[n]= (unsigned char)c;
      }

      if (n> 0) {
         ogroup[0]= dtable[igroup[0]>>2];
         ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
         ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
         ogroup[3]= dtable[igroup[2]&0x3F];

         if (n<3) {
            ogroup[3]= '=';

            if (n<2)
               ogroup[2]= '=';
         }

         for (i= 0;i<4;i++)
            b64_ochar(&bio, ogroup[i], so);
      }
   }

   /* Put end of line - line feed */
   if (fputs(EOL, so) == EOF)
      return 0;

   fclose(fi);

   return 1;
}
static int check_dirpath ( char *  dest,
int  len,
char *  domain,
char *  username,
char *  folder 
) [static]

Definition at line 1501 of file app_minivm.c.

References FALSE, make_dir(), and TRUE.

Referenced by leave_voicemail(), minivm_account_func_read(), and minivm_greet_exec().

{
   struct stat filestat;
   make_dir(dest, len, domain, username, folder ? folder : "");
   if (stat(dest, &filestat)== -1)
      return FALSE;
   else
      return TRUE;
}
static int check_mime ( const char *  str) [static]

Definition at line 1129 of file app_minivm.c.

References str.

Referenced by sendmail().

{
   for (; *str; str++) {
      if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
         return 1;
      }
   }
   return 0;
}
static char* complete_minivm_show_users ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 3011 of file app_minivm.c.

References AST_LIST_TRAVERSE, ast_strdup, and minivm_account::domain.

Referenced by handle_minivm_show_users().

{
   int which = 0;
   int wordlen;
   struct minivm_account *vmu;
   const char *domain = "";

   /* 0 - voicemail; 1 - list; 2 - accounts; 3 - for; 4 - <domain> */
   if (pos > 4)
      return NULL;
   if (pos == 3)
      return (state == 0) ? ast_strdup("for") : NULL;
   wordlen = strlen(word);
   AST_LIST_TRAVERSE(&minivm_accounts, vmu, list) {
      if (!strncasecmp(word, vmu->domain, wordlen)) {
         if (domain && strcmp(domain, vmu->domain) && ++which > state)
            return ast_strdup(vmu->domain);
         /* ignore repeated domains ? */
         domain = vmu->domain;
      }
   }
   return NULL;
}
static int create_dirpath ( char *  dest,
int  len,
char *  domain,
char *  username,
char *  folder 
) [static]

Definition at line 1520 of file app_minivm.c.

References ast_debug, ast_log(), ast_mkdir(), LOG_WARNING, and make_dir().

Referenced by leave_voicemail(), minivm_counter_func_read(), and minivm_counter_func_write().

{
   int res;
   make_dir(dest, len, domain, username, folder);
   if ((res = ast_mkdir(dest, 0777))) {
      ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
      return -1;
   }
   ast_debug(2, "Creating directory for %s@%s folder %s : %s\n", username, domain, folder, dest);
   return 0;
}
static int create_vmaccount ( char *  name,
struct ast_variable var,
int  realtime 
) [static]

Append new mailbox to mailbox list from configuration file.

Definition at line 2556 of file app_minivm.c.

References minivm_account::accountcode, ast_calloc, ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strdupa, ast_strlen_zero(), ast_variable_new(), minivm_account::chanvars, minivm_account::domain, minivm_account::email, minivm_account::etemplate, minivm_account::externnotify, minivm_account::fullname, global_stats, minivm_account::language, LOG_ERROR, ast_variable::name, ast_variable::next, minivm_account::pager, minivm_account::pincode, populate_defaults(), minivm_account::ptemplate, minivm_account::serveremail, minivm_account::username, ast_variable::value, minivm_stats::voicemailaccounts, minivm_account::volgain, and minivm_account::zonetag.

Referenced by find_user_realtime(), and load_config().

{
   struct minivm_account *vmu;
   char *domain;
   char *username;
   char accbuf[BUFSIZ];

   ast_debug(3, "Creating %s account for [%s]\n", realtime ? "realtime" : "static", name);

   ast_copy_string(accbuf, name, sizeof(accbuf));
   username = accbuf;
   domain = strchr(accbuf, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   }
   if (ast_strlen_zero(domain)) {
      ast_log(LOG_ERROR, "No domain given for mini-voicemail account %s. Not configured.\n", name);
      return 0;
   }

   ast_debug(3, "Creating static account for user %s domain %s\n", username, domain);

   /* Allocate user account */
   vmu = ast_calloc(1, sizeof(*vmu));
   if (!vmu)
      return 0;
   
   ast_copy_string(vmu->domain, domain, sizeof(vmu->domain));
   ast_copy_string(vmu->username, username, sizeof(vmu->username));

   populate_defaults(vmu);

   ast_debug(3, "...Configuring account %s\n", name);

   while (var) {
      ast_debug(3, "Configuring %s = \"%s\" for account %s\n", var->name, var->value, name);
      if (!strcasecmp(var->name, "serveremail")) {
         ast_copy_string(vmu->serveremail, var->value, sizeof(vmu->serveremail));
      } else if (!strcasecmp(var->name, "email")) {
         ast_copy_string(vmu->email, var->value, sizeof(vmu->email));
      } else if (!strcasecmp(var->name, "accountcode")) {
         ast_copy_string(vmu->accountcode, var->value, sizeof(vmu->accountcode));
      } else if (!strcasecmp(var->name, "pincode")) {
         ast_copy_string(vmu->pincode, var->value, sizeof(vmu->pincode));
      } else if (!strcasecmp(var->name, "domain")) {
         ast_copy_string(vmu->domain, var->value, sizeof(vmu->domain));
      } else if (!strcasecmp(var->name, "language")) {
         ast_copy_string(vmu->language, var->value, sizeof(vmu->language));
      } else if (!strcasecmp(var->name, "timezone")) {
         ast_copy_string(vmu->zonetag, var->value, sizeof(vmu->zonetag));
      } else if (!strcasecmp(var->name, "externnotify")) {
         ast_copy_string(vmu->externnotify, var->value, sizeof(vmu->externnotify));
      } else if (!strcasecmp(var->name, "etemplate")) {
         ast_copy_string(vmu->etemplate, var->value, sizeof(vmu->etemplate));
      } else if (!strcasecmp(var->name, "ptemplate")) {
         ast_copy_string(vmu->ptemplate, var->value, sizeof(vmu->ptemplate));
      } else if (!strcasecmp(var->name, "fullname")) {
         ast_copy_string(vmu->fullname, var->value, sizeof(vmu->fullname));
      } else if (!strcasecmp(var->name, "setvar")) {
         char *varval;
         char *varname = ast_strdupa(var->value);
         struct ast_variable *tmpvar;

         if (varname && (varval = strchr(varname, '='))) {
            *varval = '\0';
            varval++;
            if ((tmpvar = ast_variable_new(varname, varval, ""))) {
               tmpvar->next = vmu->chanvars;
               vmu->chanvars = tmpvar;
            }
         }
      } else if (!strcasecmp(var->name, "pager")) {
         ast_copy_string(vmu->pager, var->value, sizeof(vmu->pager));
      } else if (!strcasecmp(var->name, "volgain")) {
         sscanf(var->value, "%30lf", &vmu->volgain);
      } else {
         ast_log(LOG_ERROR, "Unknown configuration option for minivm account %s : %s\n", name, var->name);
      }
      var = var->next;
   }
   ast_debug(3, "...Linking account %s\n", name);
   
   AST_LIST_LOCK(&minivm_accounts);
   AST_LIST_INSERT_TAIL(&minivm_accounts, vmu, list);
   AST_LIST_UNLOCK(&minivm_accounts);

   global_stats.voicemailaccounts++;

   ast_debug(2, "MVM :: Created account %s@%s - tz %s etemplate %s %s\n", username, domain, ast_strlen_zero(vmu->zonetag) ? "" : vmu->zonetag, ast_strlen_zero(vmu->etemplate) ? "" : vmu->etemplate, realtime ? "(realtime)" : "");
   return 0;
}
static struct minivm_account* find_account ( const char *  domain,
const char *  username,
int  createtemp 
) [static, read]

Definition at line 1052 of file app_minivm.c.

References ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_set2_flag, ast_strlen_zero(), minivm_account::domain, find_user_realtime(), LOG_NOTICE, MVM_ALLOCED, mvm_user_alloc(), TRUE, and minivm_account::username.

Referenced by leave_voicemail(), minivm_accmess_exec(), minivm_account_func_read(), minivm_counter_func_read(), minivm_counter_func_write(), minivm_greet_exec(), and minivm_notify_exec().

{
   struct minivm_account *vmu = NULL, *cur;


   if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
      ast_log(LOG_NOTICE, "No username or domain? \n");
      return NULL;
   }
   ast_debug(3, "Looking for voicemail user %s in domain %s\n", username, domain);

   AST_LIST_LOCK(&minivm_accounts);
   AST_LIST_TRAVERSE(&minivm_accounts, cur, list) {
      /* Is this the voicemail account we're looking for? */
      if (!strcasecmp(domain, cur->domain) && !strcasecmp(username, cur->username))
         break;
   }
   AST_LIST_UNLOCK(&minivm_accounts);

   if (cur) {
      ast_debug(3, "Found account for %s@%s\n", username, domain);
      vmu = cur;

   } else
      vmu = find_user_realtime(domain, username);

   if (createtemp && !vmu) {
      /* Create a temporary user, send e-mail and be gone */
      vmu = mvm_user_alloc();
      ast_set2_flag(vmu, TRUE, MVM_ALLOCED); 
      if (vmu) {
         ast_copy_string(vmu->username, username, sizeof(vmu->username));
         ast_copy_string(vmu->domain, domain, sizeof(vmu->domain));
         ast_debug(1, "Created temporary account\n");
      }

   }
   return vmu;
}
static struct minivm_account * find_user_realtime ( const char *  domain,
const char *  username 
) [static, read]

Definition at line 1096 of file app_minivm.c.

References ast_copy_string(), ast_free, ast_load_realtime(), ast_variables_destroy(), create_vmaccount(), MAXHOSTNAMELEN, mvm_user_alloc(), populate_defaults(), SENTINEL, TRUE, minivm_account::username, and var.

Referenced by find_account().

{
   struct ast_variable *var;
   struct minivm_account *retval;
   char name[MAXHOSTNAMELEN];

   retval = mvm_user_alloc();
   if (!retval)
      return NULL;

   if (username) 
      ast_copy_string(retval->username, username, sizeof(retval->username));

   populate_defaults(retval);
   var = ast_load_realtime("minivm", "username", username, "domain", domain, SENTINEL);

   if (!var) {
      ast_free(retval);
      return NULL;
   }

   snprintf(name, sizeof(name), "%s@%s", username, domain);
   create_vmaccount(name, var, TRUE);

   ast_variables_destroy(var);
   return retval;
}
static void free_user ( struct minivm_account vmu) [static]
static void free_zone ( struct minivm_zone z) [static]

Free Mini Voicemail timezone.

Definition at line 2650 of file app_minivm.c.

References ast_free.

Referenced by timezone_destroy_list().

{
   ast_free(z);
}
static int get_date ( char *  s,
int  len 
) [static]

Definition at line 962 of file app_minivm.c.

References ast_localtime(), ast_strftime(), and ast_tvnow().

Referenced by leave_voicemail().

{
   struct ast_tm tm;
   struct timeval now = ast_tvnow();

   ast_localtime(&now, &tm, NULL);
   return ast_strftime(s, len, "%a %b %e %r %Z %Y", &tm);
}
static char* handle_minivm_list_templates ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI routine for listing templates.

Definition at line 2970 of file app_minivm.c.

References ast_cli_args::argc, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, HVLT_OUTPUT_FORMAT, and ast_cli_entry::usage.

{
   struct minivm_template *this;
#define HVLT_OUTPUT_FORMAT "%-15s %-10s %-10s %-15.15s %-50s\n"
   int count = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "minivm list templates";
      e->usage =
         "Usage: minivm list templates\n"
         "       Lists message templates for e-mail, paging and IM\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc > 3)
      return CLI_SHOWUSAGE;

   AST_LIST_LOCK(&message_templates);
   if (AST_LIST_EMPTY(&message_templates)) {
      ast_cli(a->fd, "There are no message templates defined\n");
      AST_LIST_UNLOCK(&message_templates);
      return CLI_FAILURE;
   }
   ast_cli(a->fd, HVLT_OUTPUT_FORMAT, "Template name", "Charset", "Locale", "Attach media", "Subject");
   ast_cli(a->fd, HVLT_OUTPUT_FORMAT, "-------------", "-------", "------", "------------", "-------");
   AST_LIST_TRAVERSE(&message_templates, this, list) {
      ast_cli(a->fd, HVLT_OUTPUT_FORMAT, this->name, 
         this->charset ? this->charset : "-", 
         this->locale ? this->locale : "-",
         this->attachment ? "Yes" : "No",
         this->subject ? this->subject : "-");
      count++;
   }
   AST_LIST_UNLOCK(&message_templates);
   ast_cli(a->fd, "\n * Total: %d minivoicemail message templates\n", count);
   return CLI_SUCCESS;
}
static char * handle_minivm_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Reload cofiguration.

Definition at line 3529 of file app_minivm.c.

References ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, reload, and ast_cli_entry::usage.

{
   
   switch (cmd) {
   case CLI_INIT:
      e->command = "minivm reload";
      e->usage =
         "Usage: minivm reload\n"
         "       Reload mini-voicemail configuration and reset statistics\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   
   reload();
   ast_cli(a->fd, "\n-- Mini voicemail re-configured \n");
   return CLI_SUCCESS;
}
static char* handle_minivm_show_settings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI Show settings.

Definition at line 3121 of file app_minivm.c.

References ast_cli(), ast_test_flag, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, default_vmformat, ast_cli_args::fd, global_externnotify, global_logfile, global_mailcmd, global_maxsilence, global_silencethreshold, global_vmmaxmessage, global_vmminmessage, globalflags, MVM_OPERATOR, MVM_REVIEW, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "minivm show settings";
      e->usage =
         "Usage: minivm show settings\n"
         "       Display Mini-Voicemail general settings\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   ast_cli(a->fd, "* Mini-Voicemail general settings\n");
   ast_cli(a->fd, "  -------------------------------\n");
   ast_cli(a->fd, "\n");
   ast_cli(a->fd, "  Mail command (shell):               %s\n", global_mailcmd);
   ast_cli(a->fd, "  Max silence:                        %d\n", global_maxsilence);
   ast_cli(a->fd, "  Silence threshold:                  %d\n", global_silencethreshold);
   ast_cli(a->fd, "  Max message length (secs):          %d\n", global_vmmaxmessage);
   ast_cli(a->fd, "  Min message length (secs):          %d\n", global_vmminmessage);
   ast_cli(a->fd, "  Default format:                     %s\n", default_vmformat);
   ast_cli(a->fd, "  Extern notify (shell):              %s\n", global_externnotify);
   ast_cli(a->fd, "  Logfile:                            %s\n", global_logfile[0] ? global_logfile : "<disabled>");
   ast_cli(a->fd, "  Operator exit:                      %s\n", ast_test_flag(&globalflags, MVM_OPERATOR) ? "Yes" : "No");
   ast_cli(a->fd, "  Message review:                     %s\n", ast_test_flag(&globalflags, MVM_REVIEW) ? "Yes" : "No");

   ast_cli(a->fd, "\n");
   return CLI_SUCCESS;
}
static char* handle_minivm_show_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show stats.

Definition at line 3153 of file app_minivm.c.

References ast_cli(), ast_localtime(), ast_strftime(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, global_stats, minivm_stats::lastreceived, minivm_stats::receivedmessages, minivm_stats::reset, minivm_stats::templates, minivm_stats::timezones, ast_cli_entry::usage, and minivm_stats::voicemailaccounts.

{
   struct ast_tm timebuf;
   char buf[BUFSIZ];

   switch (cmd) {
   
   case CLI_INIT:
      e->command = "minivm show stats";
      e->usage =
         "Usage: minivm show stats\n"
         "       Display Mini-Voicemail counters\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   ast_cli(a->fd, "* Mini-Voicemail statistics\n");
   ast_cli(a->fd, "  -------------------------\n");
   ast_cli(a->fd, "\n");
   ast_cli(a->fd, "  Voicemail accounts:                  %5d\n", global_stats.voicemailaccounts);
   ast_cli(a->fd, "  Templates:                           %5d\n", global_stats.templates);
   ast_cli(a->fd, "  Timezones:                           %5d\n", global_stats.timezones);
   if (global_stats.receivedmessages == 0) {
      ast_cli(a->fd, "  Received messages since last reset:  <none>\n");
   } else {
      ast_cli(a->fd, "  Received messages since last reset:  %d\n", global_stats.receivedmessages);
      ast_localtime(&global_stats.lastreceived, &timebuf, NULL);
      ast_strftime(buf, sizeof(buf), "%a %b %e %r %Z %Y", &timebuf);
      ast_cli(a->fd, "  Last received voicemail:             %s\n", buf);
   }
   ast_localtime(&global_stats.reset, &timebuf, NULL);
   ast_strftime(buf, sizeof(buf), "%a %b %e %r %Z %Y", &timebuf);
   ast_cli(a->fd, "  Last reset:                          %s\n", buf);

   ast_cli(a->fd, "\n");
   return CLI_SUCCESS;
}
static char* handle_minivm_show_users ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list voicemail accounts.

Definition at line 3036 of file app_minivm.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, minivm_account::attachfmt, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_minivm_show_users(), minivm_account::domain, minivm_account::etemplate, ast_cli_args::fd, minivm_account::fullname, HMSU_OUTPUT_FORMAT, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, minivm_account::ptemplate, ast_cli_entry::usage, minivm_account::username, ast_cli_args::word, and minivm_account::zonetag.

{
   struct minivm_account *vmu;
#define HMSU_OUTPUT_FORMAT "%-23s %-15s %-15s %-10s %-10s %-50s\n"
   int count = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "minivm list accounts";
      e->usage =
         "Usage: minivm list accounts\n"
         "       Lists all mailboxes currently set up\n";
      return NULL;
   case CLI_GENERATE:
      return complete_minivm_show_users(a->line, a->word, a->pos, a->n);
   }

   if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
      return CLI_SHOWUSAGE;
   if ((a->argc == 5) && strcmp(a->argv[3],"for"))
      return CLI_SHOWUSAGE;

   AST_LIST_LOCK(&minivm_accounts);
   if (AST_LIST_EMPTY(&minivm_accounts)) {
      ast_cli(a->fd, "There are no voicemail users currently defined\n");
      AST_LIST_UNLOCK(&minivm_accounts);
      return CLI_FAILURE;
   }
   ast_cli(a->fd, HMSU_OUTPUT_FORMAT, "User", "E-Template", "P-template", "Zone", "Format", "Full name");
   ast_cli(a->fd, HMSU_OUTPUT_FORMAT, "----", "----------", "----------", "----", "------", "---------");
   AST_LIST_TRAVERSE(&minivm_accounts, vmu, list) {
      char tmp[256] = "";
      if ((a->argc == 3) || ((a->argc == 5) && !strcmp(a->argv[4], vmu->domain))) {
         count++;
         snprintf(tmp, sizeof(tmp), "%s@%s", vmu->username, vmu->domain);
         ast_cli(a->fd, HMSU_OUTPUT_FORMAT, tmp, vmu->etemplate ? vmu->etemplate : "-", 
            vmu->ptemplate ? vmu->ptemplate : "-",
            vmu->zonetag ? vmu->zonetag : "-", 
            vmu->attachfmt ? vmu->attachfmt : "-",
            vmu->fullname);
      }
   }
   AST_LIST_UNLOCK(&minivm_accounts);
   ast_cli(a->fd, "\n * Total: %d minivoicemail accounts\n", count);
   return CLI_SUCCESS;
}
static char* handle_minivm_show_zones ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show a list of voicemail zones in the CLI.

Definition at line 3084 of file app_minivm.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, HMSZ_OUTPUT_FORMAT, minivm_zone::msg_format, minivm_zone::name, minivm_zone::timezone, and ast_cli_entry::usage.

{
   struct minivm_zone *zone;
#define HMSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "minivm list zones";
      e->usage =
         "Usage: minivm list zones\n"
         "       Lists zone message formats\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   AST_LIST_LOCK(&minivm_zones);
   if (!AST_LIST_EMPTY(&minivm_zones)) {
      ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
      ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, "----", "--------", "--------------");
      AST_LIST_TRAVERSE(&minivm_zones, zone, list) {
         ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
      }
   } else {
      ast_cli(a->fd, "There are no voicemail zones currently defined\n");
      res = CLI_FAILURE;
   }
   AST_LIST_UNLOCK(&minivm_zones);

   return res;
}
static int invent_message ( struct ast_channel chan,
char *  domain,
char *  username,
int  busy,
char *  ecodes 
) [static]

Definition at line 1536 of file app_minivm.c.

References ast_debug, ast_fileexists(), ast_say_digit_str(), ast_streamfile(), ast_waitstream(), FALSE, ast_channel::language, and minivm_account::username.

Referenced by minivm_greet_exec().

{
   int res;
   char fn[PATH_MAX];

   ast_debug(2, "Still preparing to play message ...\n");

   snprintf(fn, sizeof(fn), "%s%s/%s/greet", MVM_SPOOL_DIR, domain, username);

   if (ast_fileexists(fn, NULL, NULL) > 0) {
      res = ast_streamfile(chan, fn, chan->language);
      if (res) 
         return -1;
      res = ast_waitstream(chan, ecodes);
      if (res) 
         return res;
   } else {
      int numericusername = 1;
      char *i = username;

      ast_debug(2, "No personal prompts. Using default prompt set for language\n");

      while (*i)  {
         ast_debug(2, "Numeric? Checking %c\n", *i);
         if (!isdigit(*i)) {
            numericusername = FALSE;
            break;
         }
         i++;
      }

      if (numericusername) {
         if (ast_streamfile(chan, "vm-theperson", chan->language))
            return -1;
         if ((res = ast_waitstream(chan, ecodes)))
            return res;

         res = ast_say_digit_str(chan, username, ecodes, chan->language);
         if (res)
            return res;
      } else {
         if (ast_streamfile(chan, "vm-theextensionis", chan->language))
            return -1;
         if ((res = ast_waitstream(chan, ecodes)))
            return res;
      }
   }

   res = ast_streamfile(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language);
   if (res)
      return -1;
   res = ast_waitstream(chan, ecodes);
   return res;
}
static int leave_voicemail ( struct ast_channel chan,
char *  username,
struct leave_vm_options options 
) [static]

Definition at line 1840 of file app_minivm.c.

References minivm_account::accountcode, ast_callerid_merge(), ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_localtime(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, ast_waitstream(), minivm_account::attachfmt, ast_channel::caller, check_dirpath(), ast_channel::context, create_dirpath(), default_vmformat, minivm_account::domain, errno, ast_channel::exten, find_account(), free_user(), get_date(), global_stats, global_vmmaxmessage, global_vmminmessage, ast_party_caller::id, ast_channel::language, minivm_stats::lastreceived, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, minivmlogfile, minivmloglock, MVM_ALLOCED, ast_party_id::name, ast_channel::name, ast_party_id::number, pbx_builtin_setvar_helper(), play_record_review(), ast_channel::priority, minivm_stats::receivedmessages, leave_vm_options::record_gain, S_COR, ast_party_name::str, ast_party_number::str, TRUE, ast_party_name::valid, and ast_party_number::valid.

Referenced by minivm_record_exec().

{
   char tmptxtfile[PATH_MAX];
   char callerid[256];
   FILE *txt;
   int res = 0, txtdes;
   int duration = 0;
   int sound_duration = 0;
   char date[256];
   char tmpdir[PATH_MAX];
   char ext_context[256] = "";
   char fmt[80];
   char *domain;
   char tmp[256] = "";
   struct minivm_account *vmu;
   int userdir;

   ast_copy_string(tmp, username, sizeof(tmp));
   username = tmp;
   domain = strchr(tmp, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   }

   if (!(vmu = find_account(domain, username, TRUE))) {
      /* We could not find user, let's exit */
      ast_log(LOG_ERROR, "Can't allocate temporary account for '%s@%s'\n", username, domain);
      pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
      return 0;
   }

   /* Setup pre-file if appropriate */
   if (strcmp(vmu->domain, "localhost"))
      snprintf(ext_context, sizeof(ext_context), "%s@%s", username, vmu->domain);
   else
      ast_copy_string(ext_context, vmu->domain, sizeof(ext_context));

   /* The meat of recording the message...  All the announcements and beeps have been played*/
   if (ast_strlen_zero(vmu->attachfmt))
      ast_copy_string(fmt, default_vmformat, sizeof(fmt));
   else
      ast_copy_string(fmt, vmu->attachfmt, sizeof(fmt));

   if (ast_strlen_zero(fmt)) {
      ast_log(LOG_WARNING, "No format for saving voicemail? Default %s\n", default_vmformat);
      pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
      return res;
   }

   userdir = check_dirpath(tmpdir, sizeof(tmpdir), vmu->domain, username, "tmp");

   /* If we have no user directory, use generic temporary directory */
   if (!userdir) {
      create_dirpath(tmpdir, sizeof(tmpdir), "0000_minivm_temp", "mediafiles", "");
      ast_debug(3, "Creating temporary directory %s\n", tmpdir);
   }


   snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);

   /* XXX This file needs to be in temp directory */
   txtdes = mkstemp(tmptxtfile);
   if (txtdes < 0) {
      ast_log(LOG_ERROR, "Unable to create message file %s: %s\n", tmptxtfile, strerror(errno));
      res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
      if (!res)
         res = ast_waitstream(chan, "");
      pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
      return res;
   }

   if (res >= 0) {
      /* Unless we're *really* silent, try to send the beep */
      res = ast_streamfile(chan, "beep", chan->language);
      if (!res)
         res = ast_waitstream(chan, "");
   }

   /* OEJ XXX Maybe this can be turned into a log file? Hmm. */
   /* Store information */
   ast_debug(2, "Open file for metadata: %s\n", tmptxtfile);

   res = play_record_review(chan, NULL, tmptxtfile, global_vmmaxmessage, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain);

   txt = fdopen(txtdes, "w+");
   if (!txt) {
      ast_log(LOG_WARNING, "Error opening text file for output\n");
   } else {
      struct ast_tm tm;
      struct timeval now = ast_tvnow();
      char timebuf[30];
      char logbuf[BUFSIZ];
      get_date(date, sizeof(date));
      ast_localtime(&now, &tm, NULL);
      ast_strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm);

      ast_callerid_merge(callerid, sizeof(callerid),
         S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
         "Unknown");
      snprintf(logbuf, sizeof(logbuf),
         /* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
         "%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
         username,
         chan->context,
         chan->macrocontext, 
         chan->exten,
         chan->priority,
         chan->name,
         callerid,
         date, 
         timebuf,
         duration,
         duration < global_vmminmessage ? "IGNORED" : "OK",
         vmu->accountcode
      ); 
      fprintf(txt, "%s", logbuf);
      if (minivmlogfile) {
         ast_mutex_lock(&minivmloglock);
         fprintf(minivmlogfile, "%s", logbuf);
         ast_mutex_unlock(&minivmloglock);
      }

      if (sound_duration < global_vmminmessage) {
         ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, global_vmminmessage);
         fclose(txt);
         ast_filedelete(tmptxtfile, NULL);
         unlink(tmptxtfile);
         pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
         return 0;
      } 
      fclose(txt); /* Close log file */
      if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
         ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
         unlink(tmptxtfile);
         pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
         if(ast_test_flag(vmu, MVM_ALLOCED))
            free_user(vmu);
         return 0;
      }

      /* Set channel variables for the notify application */
      pbx_builtin_setvar_helper(chan, "MVM_FILENAME", tmptxtfile);
      snprintf(timebuf, sizeof(timebuf), "%d", duration);
      pbx_builtin_setvar_helper(chan, "MVM_DURATION", timebuf);
      pbx_builtin_setvar_helper(chan, "MVM_FORMAT", fmt);

   }
   global_stats.lastreceived = ast_tvnow();
   global_stats.receivedmessages++;
#if 0
   /* Go ahead and delete audio files from system, they're not needed any more */
   if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
      ast_filedelete(tmptxtfile, NULL);
       /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
      ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
   }
#endif

   if (res > 0)
      res = 0;

   if(ast_test_flag(vmu, MVM_ALLOCED))
      free_user(vmu);

   pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "SUCCESS");
   return res;
}
static int load_config ( int  reload) [static]

Load minivoicemail configuration.

Definition at line 2830 of file app_minivm.c.

References apply_general_options(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_dsp_get_threshold_from_settings(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set2_flag, ast_strlen_zero(), ast_tvnow(), ast_variable_browse(), ast_variable_retrieve(), chanvar, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, create_vmaccount(), default_vmformat, errno, FALSE, global_externnotify, global_logfile, global_mailcmd, global_maxgreet, global_maxsilence, global_saydurationminfo, global_silencethreshold, global_stats, global_vmmaxmessage, global_vmminmessage, globalflags, LOG_ERROR, LOG_WARNING, message_destroy_list(), message_template_build(), message_template_find(), message_template_parse_emailbody(), minivmlock, minivmlogfile, MVM_OPERATOR, MVM_REVIEW, ast_variable::name, ast_variable::next, minivm_stats::reset, SENDMAIL, THRESHOLD_SILENCE, timezone_add(), timezone_destroy_list(), TRUE, ast_variable::value, var, vmaccounts_destroy_list(), and VOICEMAIL_CONFIG.

Referenced by load_module(), and reload().

{
   struct ast_config *cfg;
   struct ast_variable *var;
   char *cat;
   const char *chanvar;
   int error = 0;
   struct minivm_template *template;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
   if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
      return 0;
   }

   ast_mutex_lock(&minivmlock);

   /* Destroy lists to reconfigure */
   message_destroy_list();    /* Destroy list of voicemail message templates */
   timezone_destroy_list();   /* Destroy list of timezones */
   vmaccounts_destroy_list(); /* Destroy list of voicemail accounts */
   ast_debug(2, "Destroyed memory objects...\n");

   /* First, set some default settings */
   global_externnotify[0] = '\0';
   global_logfile[0] = '\0';
   global_vmmaxmessage = 2000;
   global_maxgreet = 2000;
   global_vmminmessage = 0;
   strcpy(global_mailcmd, SENDMAIL);
   global_maxsilence = 0;
   global_saydurationminfo = 2;
   ast_copy_string(default_vmformat, "wav", sizeof(default_vmformat));
   ast_set2_flag((&globalflags), FALSE, MVM_REVIEW);  
   ast_set2_flag((&globalflags), FALSE, MVM_OPERATOR);   
   /* Reset statistics */
   memset(&global_stats, 0, sizeof(global_stats));
   global_stats.reset = ast_tvnow();

   global_silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);

   /* Make sure we could load configuration file */
   if (!cfg) {
      ast_log(LOG_WARNING, "Failed to load configuration file. Module activated with default settings.\n");
      ast_mutex_unlock(&minivmlock);
      return 0;
   }

   ast_debug(2, "Loaded configuration file, now parsing\n");

   /* General settings */

   cat = ast_category_browse(cfg, NULL);
   while (cat) {
      ast_debug(3, "Found configuration section [%s]\n", cat);
      if (!strcasecmp(cat, "general")) {
         /* Nothing right now */
         error += apply_general_options(ast_variable_browse(cfg, cat));
      } else if (!strncasecmp(cat, "template-", 9))  {
         /* Template */
         char *name = cat + 9;

         /* Now build and link template to list */
         error += message_template_build(name, ast_variable_browse(cfg, cat));
      } else {
         var = ast_variable_browse(cfg, cat);
         if (!strcasecmp(cat, "zonemessages")) {
            /* Timezones in this context */
            while (var) {
               timezone_add(var->name, var->value);
               var = var->next;
            }
         } else {
            /* Create mailbox from this */
            error += create_vmaccount(cat, var, FALSE);
         }
      }
      /* Find next section in configuration file */
      cat = ast_category_browse(cfg, cat);
   }

   /* Configure the default email template */
   message_template_build("email-default", NULL);
   template = message_template_find("email-default");

   /* Load date format config for voicemail mail */
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emaildateformat"))) 
      ast_copy_string(template->dateformat, chanvar, sizeof(template->dateformat));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emailfromstring")))
      ast_copy_string(template->fromaddress, chanvar, sizeof(template->fromaddress));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emailaaddress")))
      ast_copy_string(template->serveremail, chanvar, sizeof(template->serveremail));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emailcharset")))
      ast_copy_string(template->charset, chanvar, sizeof(template->charset));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emailsubject"))) 
      ast_copy_string(template->subject, chanvar, sizeof(template->subject));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "emailbody"))) 
      template->body = message_template_parse_emailbody(chanvar);
   template->attachment = TRUE;

   message_template_build("pager-default", NULL);
   template = message_template_find("pager-default");
   if ((chanvar = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
      ast_copy_string(template->fromaddress, chanvar, sizeof(template->fromaddress));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "pageraddress")))
      ast_copy_string(template->serveremail, chanvar, sizeof(template->serveremail));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "pagercharset")))
      ast_copy_string(template->charset, chanvar, sizeof(template->charset));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "pagersubject")))
      ast_copy_string(template->subject, chanvar,sizeof(template->subject));
   if ((chanvar = ast_variable_retrieve(cfg, "general", "pagerbody"))) 
      template->body = message_template_parse_emailbody(chanvar);
   template->attachment = FALSE;

   if (error)
      ast_log(LOG_ERROR, "--- A total of %d errors found in mini-voicemail configuration\n", error);

   ast_mutex_unlock(&minivmlock);
   ast_config_destroy(cfg);

   /* Close log file if it's open and disabled */
   if(minivmlogfile)
      fclose(minivmlogfile);

   /* Open log file if it's enabled */
   if(!ast_strlen_zero(global_logfile)) {
      minivmlogfile = fopen(global_logfile, "a");
      if(!minivmlogfile)
         ast_log(LOG_ERROR, "Failed to open minivm log file %s : %s\n", global_logfile, strerror(errno));
      if (minivmlogfile)
         ast_debug(3, "Opened log file %s \n", global_logfile);
   }

   return 0;
}
static int make_dir ( char *  dest,
int  len,
const char *  domain,
const char *  username,
const char *  folder 
) [static]

Definition at line 1487 of file app_minivm.c.

References ast_strlen_zero().

Referenced by check_dirpath(), and create_dirpath().

{
   return snprintf(dest, len, "%s%s/%s%s%s", MVM_SPOOL_DIR, domain, username, ast_strlen_zero(folder) ? "" : "/", folder ? folder : "");
}
static void message_destroy_list ( void  ) [static]
static int message_template_build ( const char *  name,
struct ast_variable var 
) [static]

Definition at line 738 of file app_minivm.c.

References ast_copy_string(), ast_debug, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_true(), global_stats, LOG_ERROR, message_template_create(), message_template_parse_emailbody(), message_template_parse_filebody(), ast_variable::name, ast_variable::next, minivm_stats::templates, and ast_variable::value.

Referenced by load_config().

{
   struct minivm_template *template;
   int error = 0;

   template = message_template_create(name);
   if (!template) {
      ast_log(LOG_ERROR, "Out of memory, can't allocate message template object %s.\n", name);
      return -1;
   }

   while (var) {
      ast_debug(3, "Configuring template option %s = \"%s\" for template %s\n", var->name, var->value, name);
      if (!strcasecmp(var->name, "fromaddress")) {
         ast_copy_string(template->fromaddress, var->value, sizeof(template->fromaddress));
      } else if (!strcasecmp(var->name, "fromemail")) {
         ast_copy_string(template->serveremail, var->value, sizeof(template->serveremail));
      } else if (!strcasecmp(var->name, "subject")) {
         ast_copy_string(template->subject, var->value, sizeof(template->subject));
      } else if (!strcasecmp(var->name, "locale")) {
         ast_copy_string(template->locale, var->value, sizeof(template->locale));
      } else if (!strcasecmp(var->name, "attachmedia")) {
         template->attachment = ast_true(var->value);
      } else if (!strcasecmp(var->name, "dateformat")) {
         ast_copy_string(template->dateformat, var->value, sizeof(template->dateformat));
      } else if (!strcasecmp(var->name, "charset")) {
         ast_copy_string(template->charset, var->value, sizeof(template->charset));
      } else if (!strcasecmp(var->name, "templatefile")) {
         if (template->body) 
            ast_free(template->body);
         template->body = message_template_parse_filebody(var->value);
         if (!template->body) {
            ast_log(LOG_ERROR, "Error reading message body definition file %s\n", var->value);
            error++;
         }
      } else if (!strcasecmp(var->name, "messagebody")) {
         if (template->body) 
            ast_free(template->body);
         template->body = message_template_parse_emailbody(var->value);
         if (!template->body) {
            ast_log(LOG_ERROR, "Error parsing message body definition:\n          %s\n", var->value);
            error++;
         }
      } else {
         ast_log(LOG_ERROR, "Unknown message template configuration option \"%s=%s\"\n", var->name, var->value);
         error++;
      }
      var = var->next;
   }
   if (error)
      ast_log(LOG_ERROR, "-- %d errors found parsing message template definition %s\n", error, name);

   AST_LIST_LOCK(&message_templates);
   AST_LIST_INSERT_TAIL(&message_templates, template, list);
   AST_LIST_UNLOCK(&message_templates);

   global_stats.templates++;

   return error;
}
static struct minivm_template* message_template_create ( const char *  name) [static, read]

Definition at line 708 of file app_minivm.c.

References ast_calloc, ast_copy_string(), DEFAULT_CHARSET, DEFAULT_DATEFORMAT, and TRUE.

Referenced by message_template_build().

{
   struct minivm_template *template;

   template = ast_calloc(1, sizeof(*template));
   if (!template)
      return NULL;

   /* Set some defaults for templates */
   ast_copy_string(template->name, name, sizeof(template->name));
   ast_copy_string(template->dateformat, DEFAULT_DATEFORMAT, sizeof(template->dateformat));
   ast_copy_string(template->charset, DEFAULT_CHARSET, sizeof(template->charset));
   ast_copy_string(template->subject, "New message in mailbox ${MVM_USERNAME}@${MVM_DOMAIN}", sizeof(template->subject));
   template->attachment = TRUE;

   return template;
}
static struct minivm_template* message_template_find ( const char *  name) [static, read]

Definition at line 801 of file app_minivm.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_strlen_zero().

Referenced by load_config(), and notify_new_message().

{
   struct minivm_template *this, *res = NULL;

   if (ast_strlen_zero(name))
      return NULL;

   AST_LIST_LOCK(&message_templates);
   AST_LIST_TRAVERSE(&message_templates, this, list) {
      if (!strcasecmp(this->name, name)) {
         res = this;
         break;
      }
   }
   AST_LIST_UNLOCK(&message_templates);

   return res;
}
static void message_template_free ( struct minivm_template template) [static]

Definition at line 728 of file app_minivm.c.

References ast_free.

Referenced by message_destroy_list().

{
   if (template->body)
      ast_free(template->body);

   ast_free (template);
}
static char * message_template_parse_emailbody ( const char *  body) [static]

Parse emailbody template from configuration file.

Definition at line 2745 of file app_minivm.c.

References ast_log(), ast_strdup, emailbody, len(), and LOG_NOTICE.

Referenced by load_config(), and message_template_build().

{
   char *tmpread, *tmpwrite;
   char *emailbody = ast_strdup(configuration);

   /* substitute strings \t and \n into the apropriate characters */
   tmpread = tmpwrite = emailbody;
   while ((tmpwrite = strchr(tmpread,'\\'))) {
          int len = strlen("\n");
          switch (tmpwrite[1]) {
          case 'n':
            memmove(tmpwrite + len, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
            strncpy(tmpwrite, "\n", len);
            break;
          case 't':
            memmove(tmpwrite + len, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
            strncpy(tmpwrite, "\t", len);
            break;
          default:
            ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
          }
          tmpread = tmpwrite + len;
   }
   return emailbody; 
}
static char * message_template_parse_filebody ( const char *  filename) [static]

Read message template from file.

Definition at line 2705 of file app_minivm.c.

References ast_calloc, ast_config_AST_CONFIG_DIR, ast_copy_string(), ast_debug, ast_log(), ast_strlen_zero(), and LOG_ERROR.

Referenced by message_template_build().

                                                                   {
   char buf[BUFSIZ * 6];
   char readbuf[BUFSIZ];
   char filenamebuf[BUFSIZ];
   char *writepos;
   char *messagebody;
   FILE *fi;
   int lines = 0;

   if (ast_strlen_zero(filename))
      return NULL;
   if (*filename == '/') 
      ast_copy_string(filenamebuf, filename, sizeof(filenamebuf));
   else 
      snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ast_config_AST_CONFIG_DIR, filename);

   if (!(fi = fopen(filenamebuf, "r"))) {
      ast_log(LOG_ERROR, "Can't read message template from file: %s\n", filenamebuf);
      return NULL;
   }
   writepos = buf;
   while (fgets(readbuf, sizeof(readbuf), fi)) {
      lines ++;
      if (writepos != buf) {
         *writepos = '\n';    /* Replace EOL with new line */
         writepos++;
      }
      ast_copy_string(writepos, readbuf, sizeof(buf) - (writepos - buf));
      writepos += strlen(readbuf) - 1;
   }
   fclose(fi);
   messagebody = ast_calloc(1, strlen(buf + 1));
   ast_copy_string(messagebody, buf, strlen(buf) + 1);
   ast_debug(4, "---> Size of allocation %d\n", (int) strlen(buf + 1) );
   ast_debug(4, "---> Done reading message template : \n%s\n---- END message template--- \n", messagebody);

   return messagebody;
}
static int minivm_accmess_exec ( struct ast_channel chan,
const char *  data 
) [static]

Record specific messages for voicemail account.

Definition at line 2453 of file app_minivm.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_parse_options(), ast_app_separate_args(), ast_copy_string(), ast_debug, ast_log(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, default_vmformat, minivm_account::domain, FALSE, find_account(), minivm_account::flags, free_user(), global_maxgreet, LOG_ERROR, LOG_WARNING, minivm_accmess_options, MVM_ALLOCED, OPT_ARG_ARRAY_SIZE, OPT_BUSY_GREETING, OPT_NAME_GREETING, OPT_TEMP_GREETING, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), play_record_review(), prompt, TRUE, and minivm_account::username.

Referenced by load_module().

{
   int argc = 0;
   char *argv[2];
   char filename[PATH_MAX];
   char tmp[PATH_MAX];
   char *domain;
   char *tmpptr = NULL;
   struct minivm_account *vmu;
   char *username = argv[0];
   struct ast_flags flags = { 0 };
   char *opts[OPT_ARG_ARRAY_SIZE];
   int error = FALSE;
   char *message = NULL;
   char *prompt = NULL;
   int duration;

   if (ast_strlen_zero(data))  {
      ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
      error = TRUE;
   } else 
      tmpptr = ast_strdupa((char *)data);
   if (!error) {
      if (!tmpptr) {
         ast_log(LOG_ERROR, "Out of memory\n");
         error = TRUE;
      } else
         argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
   }

   if (argc <=1) {
      ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
      error = TRUE;
   }
   if (!error && strlen(argv[1]) > 1) {
      ast_log(LOG_ERROR, "MinivmAccmess can only handle one option at a time. Bad option string: %s\n", argv[1]);
      error = TRUE;
   }

   if (!error && ast_app_parse_options(minivm_accmess_options, &flags, opts, argv[1])) {
      ast_log(LOG_ERROR, "Can't parse option %s\n", argv[1]);
      error = TRUE;
   }

   if (error) {
      pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
      return -1;
   }

   ast_copy_string(tmp, argv[0], sizeof(tmp));
   username = tmp;
   domain = strchr(tmp, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   } 
   if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
      ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument 0 %s\n", argv[0]);
      pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
      return -1;
   }

   if(!(vmu = find_account(domain, username, TRUE))) {
      /* We could not find user, let's exit */
      ast_log(LOG_WARNING, "Could not allocate temporary memory for '%s@%s'\n", username, domain);
      pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
      return -1;
   }

   /* Answer channel if it's not already answered */
   if (chan->_state != AST_STATE_UP)
      ast_answer(chan);
   
   /* Here's where the action is */
   if (ast_test_flag(&flags, OPT_BUSY_GREETING)) {
      message = "busy";
      prompt = "vm-rec-busy";
   } else if (ast_test_flag(&flags, OPT_UNAVAIL_GREETING)) {
      message = "unavailable";
      prompt = "vm-rec-unv";
   } else if (ast_test_flag(&flags, OPT_TEMP_GREETING)) {
      message = "temp";
      prompt = "vm-rec-temp";
   } else if (ast_test_flag(&flags, OPT_NAME_GREETING)) {
      message = "greet";
      prompt = "vm-rec-name";
   }
   snprintf(filename,sizeof(filename), "%s%s/%s/%s", MVM_SPOOL_DIR, vmu->domain, vmu->username, message);
   /* Maybe we should check the result of play_record_review ? */
   play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, NULL, FALSE);

   ast_debug(1, "Recorded new %s message in %s (duration %d)\n", message, filename, duration);

   if(ast_test_flag(vmu, MVM_ALLOCED))
      free_user(vmu);

   pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "SUCCESS");

   /* Ok, we're ready to rock and roll. Return to dialplan */
   return 0;
}
static int minivm_account_func_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

${MINIVMACCOUNT()} Dialplan function - reads account data

Definition at line 3193 of file app_minivm.c.

References minivm_account::accountcode, ast_copy_string(), ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, minivm_account::chanvars, check_dirpath(), minivm_account::domain, minivm_account::email, minivm_account::etemplate, find_account(), free_user(), minivm_account::fullname, minivm_account::language, LOG_ERROR, MVM_ALLOCED, ast_variable::name, ast_variable::next, minivm_account::pager, minivm_account::pincode, minivm_account::ptemplate, TRUE, minivm_account::username, ast_variable::value, var, and minivm_account::zonetag.

{
   struct minivm_account *vmu;
   char *username, *domain, *colname;

   if (!(username = ast_strdupa(data))) {
      ast_log(LOG_ERROR, "Memory Error!\n");
      return -1;
   }

   if ((colname = strchr(username, ':'))) {
      *colname = '\0';
      colname++;
   } else {
      colname = "path";
   }
   if ((domain = strchr(username, '@'))) {
      *domain = '\0';
      domain++;
   }
   if (ast_strlen_zero(username) || ast_strlen_zero(domain)) {
      ast_log(LOG_ERROR, "This function needs a username and a domain: username@domain\n");
      return 0;
   }

   if (!(vmu = find_account(domain, username, TRUE)))
      return 0;

   if (!strcasecmp(colname, "hasaccount")) {
      ast_copy_string(buf, (ast_test_flag(vmu, MVM_ALLOCED) ? "0" : "1"), len);
   } else  if (!strcasecmp(colname, "fullname")) { 
      ast_copy_string(buf, vmu->fullname, len);
   } else  if (!strcasecmp(colname, "email")) { 
      if (!ast_strlen_zero(vmu->email))
         ast_copy_string(buf, vmu->email, len);
      else
         snprintf(buf, len, "%s@%s", vmu->username, vmu->domain);
   } else  if (!strcasecmp(colname, "pager")) { 
      ast_copy_string(buf, vmu->pager, len);
   } else  if (!strcasecmp(colname, "etemplate")) { 
      if (!ast_strlen_zero(vmu->etemplate))
         ast_copy_string(buf, vmu->etemplate, len);
      else
         ast_copy_string(buf, "email-default", len);
   } else  if (!strcasecmp(colname, "language")) { 
      ast_copy_string(buf, vmu->language, len);
   } else  if (!strcasecmp(colname, "timezone")) { 
      ast_copy_string(buf, vmu->zonetag, len);
   } else  if (!strcasecmp(colname, "ptemplate")) { 
      if (!ast_strlen_zero(vmu->ptemplate))
         ast_copy_string(buf, vmu->ptemplate, len);
      else
         ast_copy_string(buf, "email-default", len);
   } else  if (!strcasecmp(colname, "accountcode")) {
      ast_copy_string(buf, vmu->accountcode, len);
   } else  if (!strcasecmp(colname, "pincode")) {
      ast_copy_string(buf, vmu->pincode, len);
   } else  if (!strcasecmp(colname, "path")) {
      check_dirpath(buf, len, vmu->domain, vmu->username, NULL);
   } else { /* Look in channel variables */
      struct ast_variable *var;

      for (var = vmu->chanvars ; var ; var = var->next)
         if (!strcmp(var->name, colname)) {
            ast_copy_string(buf, var->value, len);
            break;
         }
   }

   if(ast_test_flag(vmu, MVM_ALLOCED))
      free_user(vmu);

   return 0;
}
static int minivm_counter_func_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

${MINIVMCOUNTER()} Dialplan function - read counters

Definition at line 3343 of file app_minivm.c.

References access_counter_file(), ast_log(), ast_strdupa, ast_strlen_zero(), create_dirpath(), minivm_account::domain, FALSE, find_account(), LOG_ERROR, LOG_WARNING, and minivm_account::username.

{
   char *username, *domain, *countername;
   struct minivm_account *vmu = NULL;
   char userpath[BUFSIZ];
   int res;

   *buf = '\0';

   if (!(username = ast_strdupa(data))) { /* Copy indata to local buffer */
      ast_log(LOG_WARNING, "Memory error!\n");
      return -1;
   }
   if ((countername = strchr(username, ':'))) {
      *countername = '\0';
      countername++;
   } 

   if ((domain = strchr(username, '@'))) {
      *domain = '\0';
      domain++;
   }

   /* If we have neither username nor domain now, let's give up */
   if (ast_strlen_zero(username) && ast_strlen_zero(domain)) {
      ast_log(LOG_ERROR, "No account given\n");
      return -1;
   }

   if (ast_strlen_zero(countername)) {
      ast_log(LOG_ERROR, "This function needs two arguments: Account:countername\n");
      return -1;
   }

   /* We only have a domain, no username */
   if (!ast_strlen_zero(username) && ast_strlen_zero(domain)) {
      domain = username;
      username = NULL;
   }

   /* If we can't find account or if the account is temporary, return. */
   if (!ast_strlen_zero(username) && !(vmu = find_account(domain, username, FALSE))) {
      ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
      return 0;
   }

   create_dirpath(userpath, sizeof(userpath), domain, username, NULL);

   /* We have the path, now read the counter file */
   res = access_counter_file(userpath, countername, 0, 0);
   if (res >= 0)
      snprintf(buf, len, "%d", res);
   return 0;
}
static int minivm_counter_func_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

${MINIVMCOUNTER()} Dialplan function - changes counter data

Definition at line 3399 of file app_minivm.c.

References access_counter_file(), ast_log(), ast_strdupa, ast_strlen_zero(), create_dirpath(), minivm_account::domain, FALSE, find_account(), LOG_ERROR, LOG_WARNING, and minivm_account::username.

{
   char *username, *domain, *countername, *operand;
   char userpath[BUFSIZ];
   struct minivm_account *vmu;
   int change = 0;
   int operation = 0;

   if(!value)
      return -1;
   change = atoi(value);

   if (!(username = ast_strdupa(data))) { /* Copy indata to local buffer */
      ast_log(LOG_WARNING, "Memory error!\n");
      return -1;
   }

   if ((countername = strchr(username, ':'))) {
      *countername = '\0';
      countername++;
   } 
   if ((operand = strchr(countername, ':'))) {
      *operand = '\0';
      operand++;
   } 

   if ((domain = strchr(username, '@'))) {
      *domain = '\0';
      domain++;
   }

   /* If we have neither username nor domain now, let's give up */
   if (ast_strlen_zero(username) && ast_strlen_zero(domain)) {
      ast_log(LOG_ERROR, "No account given\n");
      return -1;
   }

   /* We only have a domain, no username */
   if (!ast_strlen_zero(username) && ast_strlen_zero(domain)) {
      domain = username;
      username = NULL;
   }

   if (ast_strlen_zero(operand) || ast_strlen_zero(countername)) {
      ast_log(LOG_ERROR, "Writing to this function requires three arguments: Account:countername:operand\n");
      return -1;
   }

   /* If we can't find account or if the account is temporary, return. */
   if (!ast_strlen_zero(username) && !(vmu = find_account(domain, username, FALSE))) {
      ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
      return 0;
   }

   create_dirpath(userpath, sizeof(userpath), domain, username, NULL);
   /* Now, find out our operator */
   if (*operand == 'i') /* Increment */
      operation = 2;
   else if (*operand == 'd') {
      change = change * -1;
      operation = 2;
   } else if (*operand == 's')
      operation = 1;
   else {
      ast_log(LOG_ERROR, "Unknown operator: %s\n", operand);
      return -1;
   }

   /* We have the path, now read the counter file */
   access_counter_file(userpath, countername, change, operation);
   return 0;
}
static int minivm_delete_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 2415 of file app_minivm.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_fileexists(), ast_log(), ast_strlen_zero(), LOG_ERROR, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), and vm_delete().

Referenced by load_module().

{
   int res = 0;
   char filename[BUFSIZ];

   if (!ast_strlen_zero(data)) {
      ast_copy_string(filename, (char *) data, sizeof(filename));
   } else {
      ast_channel_lock(chan);
      ast_copy_string(filename, pbx_builtin_getvar_helper(chan, "MVM_FILENAME"), sizeof(filename));
      ast_channel_unlock(chan);
   }

   if (ast_strlen_zero(filename)) {
      ast_log(LOG_ERROR, "No filename given in application arguments or channel variable MVM_FILENAME\n");
      return res;
   } 

   /* Go ahead and delete audio files from system, they're not needed any more */
   /* We should look for both audio and text files here */
   if (ast_fileexists(filename, NULL, NULL) > 0) {
      res = vm_delete(filename);
      if (res) {
         ast_debug(2, "Can't delete file: %s\n", filename);
         pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "FAILED");
      } else {
         ast_debug(2, "Deleted voicemail file :: %s \n", filename);
         pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "SUCCESS");
      }
   } else {
      ast_debug(2, "Filename does not exist: %s\n", filename);
      pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "FAILED");
   }

   return res;
}
static int minivm_greet_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 2219 of file app_minivm.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_parse_options(), ast_app_separate_args(), ast_copy_flags, ast_copy_string(), ast_debug, ast_exists_extension(), ast_log(), ast_play_and_wait(), ast_set_flag, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), ast_channel::caller, check_dirpath(), ast_channel::context, minivm_account::domain, minivm_account::exit, ast_channel::exten, find_account(), minivm_account::flags, free_user(), ast_party_caller::id, invent_message(), ast_channel::language, LOG_ERROR, ast_channel::macrocontext, minivm_app_options, MVM_ALLOCED, MVM_OPERATOR, ast_party_id::number, OPT_ARG_ARRAY_SIZE, OPT_BUSY_GREETING, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), ast_channel::priority, S_COR, SOUND_INTRO, ast_party_number::str, TRUE, minivm_account::username, and ast_party_number::valid.

Referenced by load_module().

{
   struct leave_vm_options leave_options = { 0, '\0'};
   int argc;
   char *argv[2];
   struct ast_flags flags = { 0 };
   char *opts[OPT_ARG_ARRAY_SIZE];
   int res = 0;
   int ausemacro = 0;
   int ousemacro = 0;
   int ouseexten = 0;
   char tmp[PATH_MAX];
   char dest[PATH_MAX];
   char prefile[PATH_MAX] = "";
   char tempfile[PATH_MAX] = "";
   char ext_context[256] = "";
   char *domain;
   char ecodes[16] = "#";
   char *tmpptr;
   struct minivm_account *vmu;
   char *username = argv[0];

   if (ast_strlen_zero(data))  {
      ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
      return -1;
   }
   tmpptr = ast_strdupa((char *)data);
   if (!tmpptr) {
      ast_log(LOG_ERROR, "Out of memory\n");
      return -1;
   }
   argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));

   if (argc == 2) {
      if (ast_app_parse_options(minivm_app_options, &flags, opts, argv[1]))
         return -1;
      ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING );
   }

   ast_copy_string(tmp, argv[0], sizeof(tmp));
   username = tmp;
   domain = strchr(tmp, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   } 
   if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
      ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument:  %s\n", argv[0]);
      return -1;
   }
   ast_debug(1, "Trying to find configuration for user %s in domain %s\n", username, domain);

   if (!(vmu = find_account(domain, username, TRUE))) {
      ast_log(LOG_ERROR, "Could not allocate memory. \n");
      return -1;
   }

   /* Answer channel if it's not already answered */
   if (chan->_state != AST_STATE_UP)
      ast_answer(chan);

   /* Setup pre-file if appropriate */
   if (strcmp(vmu->domain, "localhost"))
      snprintf(ext_context, sizeof(ext_context), "%s@%s", username, vmu->domain);
   else
      ast_copy_string(ext_context, vmu->domain, sizeof(ext_context));

   if (ast_test_flag(&leave_options, OPT_BUSY_GREETING)) {
      res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "busy");
      if (res)
         snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", MVM_SPOOL_DIR, vmu->domain, username);
   } else if (ast_test_flag(&leave_options, OPT_UNAVAIL_GREETING)) {
      res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "unavail");
      if (res)
         snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", MVM_SPOOL_DIR, vmu->domain, username);
   }
   /* Check for temporary greeting - it overrides busy and unavail */
   snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", MVM_SPOOL_DIR, vmu->domain, username);
   if (!(res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "temp"))) {
      ast_debug(2, "Temporary message directory does not exist, using default (%s)\n", tempfile);
      ast_copy_string(prefile, tempfile, sizeof(prefile));
   }
   ast_debug(2, "Preparing to play message ...\n");

   /* Check current or macro-calling context for special extensions */
   if (ast_test_flag(vmu, MVM_OPERATOR)) {
      if (!ast_strlen_zero(vmu->exit)) {
         if (ast_exists_extension(chan, vmu->exit, "o", 1,
            S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
            strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
            ouseexten = 1;
         }
      } else if (ast_exists_extension(chan, chan->context, "o", 1,
         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
         strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
         ouseexten = 1;
      }
      else if (!ast_strlen_zero(chan->macrocontext)
         && ast_exists_extension(chan, chan->macrocontext, "o", 1,
            S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
         strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
         ousemacro = 1;
      }
   }

   if (!ast_strlen_zero(vmu->exit)) {
      if (ast_exists_extension(chan, vmu->exit, "a", 1,
         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
         strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
      }
   } else if (ast_exists_extension(chan, chan->context, "a", 1,
      S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
      strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
   } else if (!ast_strlen_zero(chan->macrocontext)
      && ast_exists_extension(chan, chan->macrocontext, "a", 1,
         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
      strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
      ausemacro = 1;
   }

   res = 0; /* Reset */
   /* Play the beginning intro if desired */
   if (!ast_strlen_zero(prefile)) {
      if (ast_streamfile(chan, prefile, chan->language) > -1) 
         res = ast_waitstream(chan, ecodes);
   } else {
      ast_debug(2, "%s doesn't exist, doing what we can\n", prefile);
      res = invent_message(chan, vmu->domain, username, ast_test_flag(&leave_options, OPT_BUSY_GREETING), ecodes);
   }
   if (res < 0) {
      ast_debug(2, "Hang up during prefile playback\n");
      pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "FAILED");
      if(ast_test_flag(vmu, MVM_ALLOCED))
         free_user(vmu);
      return -1;
   }
   if (res == '#') {
      /* On a '#' we skip the instructions */
      ast_set_flag(&leave_options, OPT_SILENT);
      res = 0;
   }
   if (!res && !ast_test_flag(&leave_options, OPT_SILENT)) {
      res = ast_streamfile(chan, SOUND_INTRO, chan->language);
      if (!res)
         res = ast_waitstream(chan, ecodes);
      if (res == '#') {
         ast_set_flag(&leave_options, OPT_SILENT);
         res = 0;
      }
   }
   if (res > 0)
      ast_stopstream(chan);
   /* Check for a '*' here in case the caller wants to escape from voicemail to something
      other than the operator -- an automated attendant or mailbox login for example */
   if (res == '*') {
      chan->exten[0] = 'a';
      chan->exten[1] = '\0';
      if (!ast_strlen_zero(vmu->exit)) {
         ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
      } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
         ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
      }
      chan->priority = 0;
      pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
      res = 0;
   } else if (res == '0') { /* Check for a '0' here */
      if(ouseexten || ousemacro) {
         chan->exten[0] = 'o';
         chan->exten[1] = '\0';
         if (!ast_strlen_zero(vmu->exit)) {
            ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
         } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
            ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
         }
         ast_play_and_wait(chan, "transfer");
         chan->priority = 0;
         pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
      }
      res =  0;
   } else if (res < 0) {
      pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "FAILED");
      res = -1;
   } else
      pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "SUCCESS");

   if(ast_test_flag(vmu, MVM_ALLOCED))
      free_user(vmu);


   /* Ok, we're ready to rock and roll. Return to dialplan */
   return res;

}
static int minivm_mwi_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 2037 of file app_minivm.c.

References ARRAY_LEN, ast_app_separate_args(), ast_copy_string(), ast_log(), ast_strdupa, ast_strlen_zero(), minivm_account::domain, LOG_ERROR, mailbox, and queue_mwi_event().

Referenced by load_module().

{
   int argc;
   char *argv[4];
   int res = 0;
   char *tmpptr;
   char tmp[PATH_MAX];
   char *mailbox;
   char *domain;
   if (ast_strlen_zero(data))  {
      ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
      return -1;
   }
   tmpptr = ast_strdupa((char *)data);
   if (!tmpptr) {
      ast_log(LOG_ERROR, "Out of memory\n");
      return -1;
   }
   argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
   if (argc < 4) {
      ast_log(LOG_ERROR, "%d arguments passed to MiniVM_MWI, need 4.\n", argc);
      return -1;
   }
   ast_copy_string(tmp, argv[0], sizeof(tmp));
   mailbox = tmp;
   domain = strchr(tmp, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   }
   if (ast_strlen_zero(domain) || ast_strlen_zero(mailbox)) {
      ast_log(LOG_ERROR, "Need mailbox@context as argument. Sorry. Argument 0 %s\n", argv[0]);
      return -1;
   }
   queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));

   return res;
}
static int minivm_notify_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 2079 of file app_minivm.c.

References ARRAY_LEN, ast_app_separate_args(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::caller, minivm_account::domain, find_account(), format, free_user(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, MVM_ALLOCED, ast_party_id::name, notify_new_message(), ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, ast_party_name::str, ast_party_number::str, TRUE, minivm_account::username, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

{
   int argc;
   char *argv[2];
   int res = 0;
   char tmp[PATH_MAX];
   char *domain;
   char *tmpptr;
   struct minivm_account *vmu;
   char *username = argv[0];
   const char *template = "";
   const char *filename;
   const char *format;
   const char *duration_string;

   if (ast_strlen_zero(data))  {
      ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
      return -1;
   }
   tmpptr = ast_strdupa((char *)data);
   if (!tmpptr) {
      ast_log(LOG_ERROR, "Out of memory\n");
      return -1;
   }
   argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));

   if (argc == 2 && !ast_strlen_zero(argv[1]))
      template = argv[1];

   ast_copy_string(tmp, argv[0], sizeof(tmp));
   username = tmp;
   domain = strchr(tmp, '@');
   if (domain) {
      *domain = '\0';
      domain++;
   } 
   if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
      ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument 0 %s\n", argv[0]);
      return -1;
   }

   if(!(vmu = find_account(domain, username, TRUE))) {
      /* We could not find user, let's exit */
      ast_log(LOG_WARNING, "Could not allocate temporary memory for '%s@%s'\n", username, domain);
      pbx_builtin_setvar_helper(chan, "MVM_NOTIFY_STATUS", "FAILED");
      return -1;
   }

   ast_channel_lock(chan);
   if ((filename = pbx_builtin_getvar_helper(chan, "MVM_FILENAME"))) {
      filename = ast_strdupa(filename);
   }
   ast_channel_unlock(chan);
   /* Notify of new message to e-mail and pager */
   if (!ast_strlen_zero(filename)) {
      ast_channel_lock(chan); 
      if ((format = pbx_builtin_getvar_helper(chan, "MVM_FORMAT"))) {
         format = ast_strdupa(format);
      }
      if ((duration_string = pbx_builtin_getvar_helper(chan, "MVM_DURATION"))) {
         duration_string = ast_strdupa(duration_string);
      }
      ast_channel_unlock(chan);
      res = notify_new_message(chan, template, vmu, filename, atoi(duration_string),
         format,
         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
         S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL));
   }

   pbx_builtin_setvar_helper(chan, "MVM_NOTIFY_STATUS", res == 0 ? "SUCCESS" : "FAILED");


   if(ast_test_flag(vmu, MVM_ALLOCED))
      free_user(vmu);

   /* Ok, we're ready to rock and roll. Return to dialplan */

   return res;

}
static int minivm_record_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 2162 of file app_minivm.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_parse_options(), ast_app_separate_args(), ast_copy_flags, ast_log(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ERROR_LOCK_PATH, minivm_account::flags, leave_voicemail(), LOG_ERROR, LOG_WARNING, minivm_app_options, OPT_ARG_ARRAY_SIZE, OPT_ARG_RECORDGAIN, OPT_BUSY_GREETING, OPT_RECORDGAIN, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), and leave_vm_options::record_gain.

Referenced by load_module().

{
   int res = 0;
   char *tmp;
   struct leave_vm_options leave_options;
   int argc;
   char *argv[2];
   struct ast_flags flags = { 0 };
   char *opts[OPT_ARG_ARRAY_SIZE];

   memset(&leave_options, 0, sizeof(leave_options));

   /* Answer channel if it's not already answered */
   if (chan->_state != AST_STATE_UP)
      ast_answer(chan);

   if (ast_strlen_zero(data))  {
      ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
      return -1;
   }
   tmp = ast_strdupa((char *)data);
   if (!tmp) {
      ast_log(LOG_ERROR, "Out of memory\n");
      return -1;
   }
   argc = ast_app_separate_args(tmp, ',', argv, ARRAY_LEN(argv));
   if (argc == 2) {
      if (ast_app_parse_options(minivm_app_options, &flags, opts, argv[1])) {
         return -1;
      }
      ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING );
      if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
         int gain;

         if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
            ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
            return -1;
         } else 
            leave_options.record_gain = (signed char) gain;
      }
   } 

   /* Now run the appliation and good luck to you! */
   res = leave_voicemail(chan, argv[0], &leave_options);

   if (res == ERROR_LOCK_PATH) {
      ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
      pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
      res = 0;
   }
   pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "SUCCESS");

   return res;
}
static struct minivm_account* mvm_user_alloc ( void  ) [static, read]

Definition at line 1025 of file app_minivm.c.

References ast_calloc, and populate_defaults().

Referenced by find_account(), and find_user_realtime().

{
   struct minivm_account *new;

   new = ast_calloc(1, sizeof(*new));
   if (!new)
      return NULL;
   populate_defaults(new);

   return new;
}
static int notify_new_message ( struct ast_channel chan,
const char *  templatename,
struct minivm_account vmu,
const char *  filename,
long  duration,
const char *  format,
char *  cidnum,
char *  cidname 
) [static]

Definition at line 1760 of file app_minivm.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_strdupa, ast_strlen_zero(), minivm_account::attachfmt, minivm_template::attachment, minivm_account::domain, minivm_account::etemplate, EVENT_FLAG_CALL, minivm_template::locale, LOG_WARNING, message_template_find(), MVM_MESSAGE_EMAIL, MVM_MESSAGE_PAGE, minivm_account::pager, pbx_builtin_getvar_helper(), minivm_account::ptemplate, run_externnotify(), sendmail(), strsep(), and minivm_account::username.

Referenced by minivm_notify_exec().

{
   char *stringp;
   struct minivm_template *etemplate;
   char *messageformat;
   int res = 0;
   char oldlocale[100];
   const char *counter;

   if (!ast_strlen_zero(vmu->attachfmt)) {
      if (strstr(format, vmu->attachfmt)) {
         format = vmu->attachfmt;
      } else {
         ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'.  Falling back to default format for '%s@%s'.\n", vmu->attachfmt, format, vmu->username, vmu->domain);
      }
   }

   etemplate = message_template_find(vmu->etemplate);
   if (!etemplate)
      etemplate = message_template_find(templatename);
   if (!etemplate)
      etemplate = message_template_find("email-default");

   /* Attach only the first format */
   stringp = messageformat = ast_strdupa(format);
   strsep(&stringp, "|");

   if (!ast_strlen_zero(etemplate->locale)) {
      char *new_locale;
      ast_copy_string(oldlocale, setlocale(LC_TIME, NULL), sizeof(oldlocale));
      ast_debug(2, "Changing locale from %s to %s\n", oldlocale, etemplate->locale);
      new_locale = setlocale(LC_TIME, etemplate->locale);
      if (new_locale == NULL) {
         ast_log(LOG_WARNING, "-_-_- Changing to new locale did not work. Locale: %s\n", etemplate->locale);
      }
   }



   /* Read counter if available */
   ast_channel_lock(chan);
   if ((counter = pbx_builtin_getvar_helper(chan, "MVM_COUNTER"))) {
      counter = ast_strdupa(counter);
   }
   ast_channel_unlock(chan);

   if (ast_strlen_zero(counter)) {
      ast_debug(2, "MVM_COUNTER not found\n");
   } else {
      ast_debug(2, "MVM_COUNTER found - will use it with value %s\n", counter);
   }

   res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_EMAIL, counter);

   if (res == 0 && !ast_strlen_zero(vmu->pager))  {
      /* Find template for paging */
      etemplate = message_template_find(vmu->ptemplate);
      if (!etemplate)
         etemplate = message_template_find("pager-default");
      if (etemplate->locale) {
         ast_copy_string(oldlocale, setlocale(LC_TIME, ""), sizeof(oldlocale));
         setlocale(LC_TIME, etemplate->locale);
      }

      res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter);
   }

   ast_manager_event(chan, EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter);

   run_externnotify(chan, vmu);     /* Run external notification */

   if (etemplate->locale) {
      setlocale(LC_TIME, oldlocale); /* Rest to old locale */
   }
   return res;
}
static int play_record_review ( struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime,
char *  fmt,
int  outsidecaller,
struct minivm_account vmu,
int *  duration,
int *  sound_duration,
const char *  unlockdir,
signed char  record_gain 
) [static]

Definition at line 1607 of file app_minivm.c.

References acceptdtmf, ast_channel_setoption(), AST_DIGIT_ANY, ast_log(), AST_OPTION_RXGAIN, ast_play_and_record_full(), ast_play_and_wait(), ast_stream_and_wait(), ast_streamfile(), ast_test_flag, ast_verb, ast_waitfordigit(), ast_waitstream(), global_maxsilence, global_silencethreshold, ast_channel::language, LOG_WARNING, MVM_OPERATOR, MVM_REVIEW, and vm_delete().

Referenced by leave_voicemail(), and minivm_accmess_exec().

{
   int cmd = 0;
   int max_attempts = 3;
   int attempts = 0;
   int recorded = 0;
   int message_exists = 0;
   signed char zero_gain = 0;
   char *acceptdtmf = "#";
   char *canceldtmf = "";

   /* Note that urgent and private are for flagging messages as such in the future */

   /* barf if no pointer passed to store duration in */
   if (duration == NULL) {
      ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
      return -1;
   }

   cmd = '3';   /* Want to start by recording */

   while ((cmd >= 0) && (cmd != 't')) {
      switch (cmd) {
      case '1':
         ast_verb(3, "Saving message as is\n");
         ast_stream_and_wait(chan, "vm-msgsaved", "");
         cmd = 't';
         break;
      case '2':
         /* Review */
         ast_verb(3, "Reviewing the message\n");
         ast_streamfile(chan, recordfile, chan->language);
         cmd = ast_waitstream(chan, AST_DIGIT_ANY);
         break;
      case '3':
         message_exists = 0;
         /* Record */
         if (recorded == 1) 
            ast_verb(3, "Re-recording the message\n");
         else
            ast_verb(3, "Recording the message\n");
         if (recorded && outsidecaller) 
            cmd = ast_play_and_wait(chan, "beep");
         recorded = 1;
         /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
         if (ast_test_flag(vmu, MVM_OPERATOR))
            canceldtmf = "0";
         cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
         if (cmd == -1) /* User has hung up, no options to give */
            return cmd;
         if (cmd == '0')
            break;
         else if (cmd == '*')
            break;
         else {
            /* If all is well, a message exists */
            message_exists = 1;
            cmd = 0;
         }
         break;
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '*':
      case '#':
         cmd = ast_play_and_wait(chan, "vm-sorry");
         break;
      case '0':
         if(!ast_test_flag(vmu, MVM_OPERATOR)) {
            cmd = ast_play_and_wait(chan, "vm-sorry");
            break;
         }
         if (message_exists || recorded) {
            cmd = ast_play_and_wait(chan, "vm-saveoper");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 3000);
            if (cmd == '1') {
               ast_play_and_wait(chan, "vm-msgsaved");
               cmd = '0';
            } else {
               ast_play_and_wait(chan, "vm-deleted");
               vm_delete(recordfile);
               cmd = '0';
            }
         }
         return cmd;
      default:
         /* If the caller is an ouside caller, and the review option is enabled,
            allow them to review the message, but let the owner of the box review
            their OGM's */
         if (outsidecaller && !ast_test_flag(vmu, MVM_REVIEW))
            return cmd;
         if (message_exists) {
            cmd = ast_play_and_wait(chan, "vm-review");
         } else {
            cmd = ast_play_and_wait(chan, "vm-torerecord");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 600);
         }

         if (!cmd && outsidecaller && ast_test_flag(vmu, MVM_OPERATOR)) {
            cmd = ast_play_and_wait(chan, "vm-reachoper");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 600);
         }
         if (!cmd)
            cmd = ast_waitfordigit(chan, 6000);
         if (!cmd) {
            attempts++;
         }
         if (attempts > max_attempts) {
            cmd = 't';
         }
      }
   }
   if (outsidecaller)
      ast_play_and_wait(chan, "vm-goodbye");
   if (cmd == 't')
      cmd = 0;
   return cmd;
}
static void prep_email_sub_vars ( struct ast_channel channel,
const struct minivm_account vmu,
const char *  cidnum,
const char *  cidname,
const char *  dur,
const char *  date,
const char *  counter 
) [static]

Definition at line 987 of file app_minivm.c.

References ast_callerid_merge(), ast_log(), ast_strlen_zero(), minivm_account::chanvars, minivm_account::domain, minivm_account::fullname, LOG_ERROR, ast_variable::name, ast_variable::next, pbx_builtin_setvar_helper(), minivm_account::username, ast_variable::value, and var.

Referenced by sendmail().

{
   char callerid[256];
   struct ast_variable *var;
   
   if (!channel) {
      ast_log(LOG_ERROR, "No allocated channel, giving up...\n");
      return;
   }

   for (var = vmu->chanvars ; var ; var = var->next) {
      pbx_builtin_setvar_helper(channel, var->name, var->value);
   }

   /* Prepare variables for substition in email body and subject */
   pbx_builtin_setvar_helper(channel, "MVM_NAME", vmu->fullname);
   pbx_builtin_setvar_helper(channel, "MVM_DUR", dur);
   pbx_builtin_setvar_helper(channel, "MVM_DOMAIN", vmu->domain);
   pbx_builtin_setvar_helper(channel, "MVM_USERNAME", vmu->username);
   pbx_builtin_setvar_helper(channel, "MVM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
   pbx_builtin_setvar_helper(channel, "MVM_CIDNAME", (cidname ? cidname : "an unknown caller"));
   pbx_builtin_setvar_helper(channel, "MVM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
   pbx_builtin_setvar_helper(channel, "MVM_DATE", date);
   if (!ast_strlen_zero(counter))
      pbx_builtin_setvar_helper(channel, "MVM_COUNTER", counter);
}
static void queue_mwi_event ( const char *  mbx,
const char *  ctx,
int  urgent,
int  new,
int  old 
) [static]
static int reload ( void  ) [static]

Reload mini voicemail module.

Definition at line 3523 of file app_minivm.c.

References load_config().

{
   return(load_config(1));
}
static void run_externnotify ( struct ast_channel chan,
struct minivm_account vmu 
) [static]

Run external notification for voicemail message.

Definition at line 1739 of file app_minivm.c.

References ast_debug, ast_safe_system(), ast_strlen_zero(), ast_channel::caller, minivm_account::domain, minivm_account::externnotify, global_externnotify, ast_party_caller::id, ast_party_id::name, ast_party_id::number, ast_party_name::str, ast_party_number::str, minivm_account::username, ast_party_name::valid, and ast_party_number::valid.

Referenced by notify_new_message().

{
   char arguments[BUFSIZ];

   if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify))
      return;

   snprintf(arguments, sizeof(arguments), "%s %s@%s %s %s&", 
      ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify, 
      vmu->username, vmu->domain,
      (chan->caller.id.name.valid && chan->caller.id.name.str)
         ? chan->caller.id.name.str : "",
      (chan->caller.id.number.valid && chan->caller.id.number.str)
         ? chan->caller.id.number.str : "");

   ast_debug(1, "Executing: %s\n", arguments);
   ast_safe_system(arguments);
}
static int sendmail ( struct minivm_template template,
struct minivm_account vmu,
char *  cidnum,
char *  cidname,
const char *  filename,
char *  format,
int  duration,
int  attach_user_voicemail,
enum mvm_messagetype  type,
const char *  counter 
) [static]

XXX /bug tmpfd is a leaked fd. The file is also never unlinked. See app_voicemail.c for how the code works there that doesn't have this bug.

Definition at line 1220 of file app_minivm.c.

References ast_channel_unref, ast_copy_string(), ast_debug, ast_dummy_channel_alloc(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_log(), ast_random(), ast_safe_system(), ast_str_buffer(), ast_str_create(), ast_str_encode_mime(), ast_str_quote(), ast_str_set(), ast_str_substitute_variables(), ast_strdupa, ast_strftime(), ast_strlen_zero(), ast_tvnow(), base_encode(), check_mime(), minivm_account::domain, minivm_account::email, minivm_account::fullname, global_mailcmd, LOG_WARNING, MAXHOSTNAMELEN, MVM_MESSAGE_EMAIL, MVM_MESSAGE_PAGE, minivm_zone::name, option_debug, minivm_account::pager, prep_email_sub_vars(), minivm_account::serveremail, minivm_zone::timezone, minivm_account::username, minivm_account::volgain, and minivm_account::zonetag.

Referenced by notify_new_message().

{
   FILE *p = NULL;
   int pfd;
   char email[256] = "";
   char who[256] = "";
   char date[256];
   char bound[256];
   char fname[PATH_MAX];
   char dur[PATH_MAX];
   char tmp[80] = "/tmp/astmail-XXXXXX";
   char tmp2[PATH_MAX];
   struct timeval now;
   struct ast_tm tm;
   struct minivm_zone *the_zone = NULL;
   struct ast_channel *ast;
   char *finalfilename = "";
   struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
   char *fromaddress;
   char *fromemail;

   if (!str1 || !str2) {
      ast_free(str1);
      ast_free(str2);
      return -1;
   }

   if (type == MVM_MESSAGE_EMAIL) {
      if (vmu && !ast_strlen_zero(vmu->email)) {
         ast_copy_string(email, vmu->email, sizeof(email)); 
      } else if (!ast_strlen_zero(vmu->username) && !ast_strlen_zero(vmu->domain))
         snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
   } else if (type == MVM_MESSAGE_PAGE) {
      ast_copy_string(email, vmu->pager, sizeof(email));
   }

   if (ast_strlen_zero(email)) {
      ast_log(LOG_WARNING, "No address to send message to.\n");
      return -1;  
   }

   ast_debug(3, "Sending mail to %s@%s - Using template %s\n", vmu->username, vmu->domain, template->name);

   if (!strcmp(format, "wav49"))
      format = "WAV";


   /* If we have a gain option, process it now with sox */
   if (type == MVM_MESSAGE_EMAIL && (vmu->volgain < -.001 || vmu->volgain > .001) ) {
      char newtmp[PATH_MAX];
      char tmpcmd[PATH_MAX];
      int tmpfd;

      /**
       * XXX
       * /bug tmpfd is a leaked fd.  The file is also never unlinked.
       *      See app_voicemail.c for how the code works there that
       *      doesn't have this bug.
       */

      ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
      ast_debug(3, "newtmp: %s\n", newtmp);
      tmpfd = mkstemp(newtmp);
      if (tmpfd > -1) {
         snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
         ast_safe_system(tmpcmd);
         finalfilename = newtmp;
         ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
      }
   } else {
      finalfilename = ast_strdupa(filename);
   }

   /* Create file name */
   snprintf(fname, sizeof(fname), "%s.%s", finalfilename, format);

   if (template->attachment)
      ast_debug(1, "Attaching file '%s', format '%s', uservm is '%d'\n", finalfilename, format, attach_user_voicemail);

   /* Make a temporary file instead of piping directly to sendmail, in case the mail
      command hangs */
   pfd = mkstemp(tmp);
   if (pfd > -1) {
      p = fdopen(pfd, "w");
      if (!p) {
         close(pfd);
         pfd = -1;
      }
      ast_debug(1, "Opening temp file for e-mail: %s\n", tmp);
   }
   if (!p) {
      ast_log(LOG_WARNING, "Unable to open temporary file '%s'\n", tmp);
      return -1;
   }
   /* Allocate channel used for chanvar substitution */
   ast = ast_dummy_channel_alloc();
   if (!ast) {
      return -1;
   }

   snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);

   /* Does this user have a timezone specified? */
   if (!ast_strlen_zero(vmu->zonetag)) {
      /* Find the zone in the list */
      struct minivm_zone *z;
      AST_LIST_LOCK(&minivm_zones);
      AST_LIST_TRAVERSE(&minivm_zones, z, list) {
         if (strcmp(z->name, vmu->zonetag)) 
            continue;
         the_zone = z;
      }
      AST_LIST_UNLOCK(&minivm_zones);
   }

   now = ast_tvnow();
   ast_localtime(&now, &tm, the_zone ? the_zone->timezone : NULL);
   ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);

   /* Start printing the email to the temporary file */
   fprintf(p, "Date: %s\n", date);

   /* Set date format for voicemail mail */
   ast_strftime(date, sizeof(date), template->dateformat, &tm);


   /* Populate channel with channel variables for substitution */
   prep_email_sub_vars(ast, vmu, cidnum, cidname, dur, date, counter);

   /* Find email address to use */
   /* If there's a server e-mail adress in the account, user that, othterwise template */
   fromemail = ast_strlen_zero(vmu->serveremail) ?  template->serveremail : vmu->serveremail;

   /* Find name to user for server e-mail */
   fromaddress = ast_strlen_zero(template->fromaddress) ? "" : template->fromaddress;

   /* If needed, add hostname as domain */
   if (ast_strlen_zero(fromemail))
      fromemail = "asterisk";

   if (strchr(fromemail, '@'))
      ast_copy_string(who, fromemail, sizeof(who));
   else  {
      char host[MAXHOSTNAMELEN];
      gethostname(host, sizeof(host)-1);
      snprintf(who, sizeof(who), "%s@%s", fromemail, host);
   }

   if (ast_strlen_zero(fromaddress)) {
      fprintf(p, "From: Asterisk PBX <%s>\n", who);
   } else {
      ast_debug(4, "Fromaddress template: %s\n", fromaddress);
      ast_str_substitute_variables(&str1, 0, ast, fromaddress);
      if (check_mime(ast_str_buffer(str1))) {
         int first_line = 1;
         char *ptr;
         ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
         while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
            *ptr = '\0';
            fprintf(p, "%s %s\n", first_line ? "From:" : "", ast_str_buffer(str2));
            first_line = 0;
            /* Substring is smaller, so this will never grow */
            ast_str_set(&str2, 0, "%s", ptr + 1);
         }
         fprintf(p, "%s %s <%s>\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
      } else {
         fprintf(p, "From: %s <%s>\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
      }
   } 

   fprintf(p, "Message-ID: <Asterisk-%d-%s-%d-%s>\n", (unsigned int)ast_random(), vmu->username, (int)getpid(), who);

   if (ast_strlen_zero(vmu->email)) {
      snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
   } else {
      ast_copy_string(email, vmu->email, sizeof(email));
   }

   if (check_mime(vmu->fullname)) {
      int first_line = 1;
      char *ptr;
      ast_str_encode_mime(&str2, 0, template->charset, vmu->fullname, strlen("To: "), strlen(email) + 3);
      while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
         *ptr = '\0';
         fprintf(p, "%s %s\n", first_line ? "To:" : "", ast_str_buffer(str2));
         first_line = 0;
         /* Substring is smaller, so this will never grow */
         ast_str_set(&str2, 0, "%s", ptr + 1);
      }
      fprintf(p, "%s %s <%s>\n", first_line ? "To:" : "", ast_str_buffer(str2), email);
   } else {
      fprintf(p, "To: %s <%s>\n", ast_str_quote(&str2, 0, vmu->fullname), email);
   }

   if (!ast_strlen_zero(template->subject)) {
      ast_str_substitute_variables(&str1, 0, ast, template->subject);
      if (check_mime(ast_str_buffer(str1))) {
         int first_line = 1;
         char *ptr;
         ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("Subject: "), 0);
         while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
            *ptr = '\0';
            fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
            first_line = 0;
            /* Substring is smaller, so this will never grow */
            ast_str_set(&str2, 0, "%s", ptr + 1);
         }
         fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
      } else {
         fprintf(p, "Subject: %s\n", ast_str_buffer(str1));
      }
   } else {
      fprintf(p, "Subject: New message in mailbox %s@%s\n", vmu->username, vmu->domain);
      ast_debug(1, "Using default subject for this email \n");
   }

   if (option_debug > 2)
      fprintf(p, "X-Asterisk-debug: template %s user account %s@%s\n", template->name, vmu->username, vmu->domain);
   fprintf(p, "MIME-Version: 1.0\n");

   /* Something unique. */
   snprintf(bound, sizeof(bound), "voicemail_%s%d%d", vmu->username, (int)getpid(), (unsigned int)ast_random());

   fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);

   fprintf(p, "--%s\n", bound);
   fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", template->charset);
   if (!ast_strlen_zero(template->body)) {
      ast_str_substitute_variables(&str1, 0, ast, template->body);
      ast_debug(3, "Message now: %s\n-----\n", ast_str_buffer(str1));
      fprintf(p, "%s\n", ast_str_buffer(str1));
   } else {
      fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message \n"
         "in mailbox %s from %s, on %s so you might\n"
         "want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, 
         dur,  vmu->username, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
      ast_debug(3, "Using default message body (no template)\n-----\n");
   }
   /* Eww. We want formats to tell us their own MIME type */
   if (template->attachment) {
      char *ctype = "audio/x-";
      ast_debug(3, "Attaching file to message: %s\n", fname);
      if (!strcasecmp(format, "ogg"))
         ctype = "application/";

      fprintf(p, "--%s\n", bound);
      fprintf(p, "Content-Type: %s%s; name=\"voicemailmsg.%s\"\n", ctype, format, format);
      fprintf(p, "Content-Transfer-Encoding: base64\n");
      fprintf(p, "Content-Description: Voicemail sound attachment.\n");
      fprintf(p, "Content-Disposition: attachment; filename=\"voicemail%s.%s\"\n\n", counter ? counter : "", format);

      base_encode(fname, p);
      fprintf(p, "\n\n--%s--\n.\n", bound);
   }
   fclose(p);
   snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", global_mailcmd, tmp, tmp);
   ast_safe_system(tmp2);
   ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : "");
   ast_debug(3, "Actual command used: %s\n", tmp2);
   ast = ast_channel_unref(ast);
   ast_free(str1);
   ast_free(str2);
   return 0;
}
static int timezone_add ( const char *  zonename,
const char *  config 
) [static]

Add time zone to memory list.

Definition at line 2668 of file app_minivm.c.

References ast_calloc, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strdupa, global_stats, LOG_WARNING, minivm_zone::msg_format, minivm_zone::name, strsep(), minivm_zone::timezone, and minivm_stats::timezones.

Referenced by load_config().

{
   struct minivm_zone *newzone;
   char *msg_format, *timezone_str;

   newzone = ast_calloc(1, sizeof(*newzone));
   if (newzone == NULL)
      return 0;

   msg_format = ast_strdupa(config);
   if (msg_format == NULL) {
      ast_log(LOG_WARNING, "Out of memory.\n");
      ast_free(newzone);
      return 0;
   }

   timezone_str = strsep(&msg_format, "|");
   if (!msg_format) {
      ast_log(LOG_WARNING, "Invalid timezone definition : %s\n", zonename);
      ast_free(newzone);
      return 0;
   }
         
   ast_copy_string(newzone->name, zonename, sizeof(newzone->name));
   ast_copy_string(newzone->timezone, timezone_str, sizeof(newzone->timezone));
   ast_copy_string(newzone->msg_format, msg_format, sizeof(newzone->msg_format));

   AST_LIST_LOCK(&minivm_zones);
   AST_LIST_INSERT_TAIL(&minivm_zones, newzone, list);
   AST_LIST_UNLOCK(&minivm_zones);

   global_stats.timezones++;

   return 0;
}
static void timezone_destroy_list ( void  ) [static]

Clear list of timezones.

Definition at line 2656 of file app_minivm.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free_zone().

Referenced by load_config(), and unload_module().

static int vm_delete ( char *  file) [static]

Definition at line 1593 of file app_minivm.c.

References ast_debug, and ast_filedelete().

Referenced by minivm_delete_exec(), and play_record_review().

{
   int res;

   ast_debug(1, "Deleting voicemail file %s\n", file);

   res = unlink(file);  /* Remove the meta data file */
   res |=  ast_filedelete(file, NULL); /* remove the media file */
   return res;
}
static int vm_lock_path ( const char *  path) [static]

lock directory

only return failure if ast_lock_path returns 'timeout', not if the path does not exist or any other reason

Definition at line 3273 of file app_minivm.c.

References ast_lock_path(), and AST_LOCK_TIMEOUT.

Referenced by access_counter_file().

{
   switch (ast_lock_path(path)) {
   case AST_LOCK_TIMEOUT:
      return -1;
   default:
      return 0;
   }
}
static void vmaccounts_destroy_list ( void  ) [static]

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mini VoiceMail (A minimal Voicemail e-mail System)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 3576 of file app_minivm.c.

char* app_minivm_accmess = "MinivmAccMess" [static]

Definition at line 550 of file app_minivm.c.

char* app_minivm_delete = "MinivmDelete" [static]

Definition at line 549 of file app_minivm.c.

char* app_minivm_greet = "MinivmGreet" [static]

Definition at line 547 of file app_minivm.c.

char* app_minivm_mwi = "MinivmMWI" [static]

Definition at line 551 of file app_minivm.c.

char* app_minivm_notify = "MinivmNotify" [static]

Definition at line 548 of file app_minivm.c.

char* app_minivm_record = "MinivmRecord" [static]

Definition at line 546 of file app_minivm.c.

Definition at line 3576 of file app_minivm.c.

struct ast_cli_entry cli_minivm[] [static]

CLI commands for Mini-voicemail.

Definition at line 3474 of file app_minivm.c.

Referenced by load_module(), and unload_module().

char global_externnotify[160] [static]

External notification application

Definition at line 685 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), and run_externnotify().

char global_logfile[PATH_MAX] [static]

Global log file for messages

Definition at line 686 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), and load_config().

char global_mailcmd[160] [static]

Configurable mail cmd

Definition at line 684 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), and sendmail().

int global_maxgreet [static]

Maximum length of prompts

Definition at line 682 of file app_minivm.c.

Referenced by apply_general_options(), load_config(), and minivm_accmess_exec().

int global_maxsilence [static]

Maximum silence during recording

Definition at line 681 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), and play_record_review().

Definition at line 690 of file app_minivm.c.

Referenced by load_config().

struct minivm_stats global_stats [static]

Statistics for voicemail.

Definition at line 672 of file app_minivm.c.

Referenced by create_vmaccount(), handle_minivm_show_stats(), leave_voicemail(), load_config(), message_template_build(), and timezone_add().

int global_vmmaxmessage [static]

Maximum duration of message

Definition at line 680 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), leave_voicemail(), and load_config().

int global_vmminmessage [static]

Minimum duration of messages

Definition at line 679 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), leave_voicemail(), and load_config().

double global_volgain [static]

Volume gain for voicmemail via e-mail

Definition at line 692 of file app_minivm.c.

Referenced by populate_defaults().

struct ast_flags globalflags = {0} [static]

Global voicemail flags

Definition at line 689 of file app_minivm.c.

Referenced by apply_general_options(), handle_minivm_show_settings(), load_config(), and populate_defaults().

struct ast_app_option minivm_accmess_options[128] = { [ 'b' ] = { .flag = OPT_BUSY_GREETING }, [ 'u' ] = { .flag = OPT_UNAVAIL_GREETING }, [ 't' ] = { .flag = OPT_TEMP_GREETING }, [ 'n' ] = { .flag = OPT_NAME_GREETING },} [static]

Definition at line 581 of file app_minivm.c.

Referenced by minivm_accmess_exec().

Initial value:
 {
   .name = "MINIVMACCOUNT",
   .read = minivm_account_func_read,
}

Definition at line 3489 of file app_minivm.c.

Referenced by load_module(), and unload_module().

struct ast_app_option minivm_app_options[128] = { [ 's' ] = { .flag = OPT_SILENT }, [ 'b' ] = { .flag = OPT_BUSY_GREETING }, [ 'u' ] = { .flag = OPT_UNAVAIL_GREETING }, [ 'g' ] = { .flag = OPT_RECORDGAIN , .arg_index = OPT_ARG_RECORDGAIN + 1 },} [static]

Definition at line 574 of file app_minivm.c.

Referenced by minivm_greet_exec(), and minivm_record_exec().

Initial value:
 {
   .name = "MINIVMCOUNTER",
   .read = minivm_counter_func_read,
   .write = minivm_counter_func_write,
}

Definition at line 3483 of file app_minivm.c.

Referenced by load_module(), and unload_module().

struct minivm_zones minivm_zones [static]
ast_mutex_t minivmlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Lock to protect voicemail system

Definition at line 674 of file app_minivm.c.

Referenced by load_config().

FILE* minivmlogfile [static]

The minivm log file

Definition at line 677 of file app_minivm.c.

Referenced by leave_voicemail(), and load_config().

ast_mutex_t minivmloglock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Lock to protect voicemail system log file

Definition at line 675 of file app_minivm.c.

Referenced by leave_voicemail().

char MVM_SPOOL_DIR[PATH_MAX] [static]

Definition at line 543 of file app_minivm.c.