Thu Apr 28 2011 17:13:37

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
 Structure for linked list of Mini-Voicemail users: minivm_accounts. More...
struct  minivm_accounts
 The list of e-mail accounts. More...
struct  minivm_stats
 Structure for gathering statistics. More...
struct  minivm_template
 Linked list of e-mail templates in various languages These are used as templates for e-mails, pager messages and jabber messages message_templates. More...
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"
 Default dateformat, can be overridden in configuration file.
#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  {
  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  { OPT_ARG_RECORDGAIN = 0, OPT_ARG_ARRAY_SIZE = 1 }
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 int b64_inbuf (struct b64_baseio *bio, FILE *fi)
 read buffer from file (base64 conversion)
static int b64_inchar (struct b64_baseio *bio, FILE *fi)
 read character from file to buffer (base64 conversion)
static int b64_ochar (struct b64_baseio *bio, int c, FILE *so)
 write buffer to file (base64 conversion)
static int base_encode (char *filename, FILE *so)
 Encode file to base64 encoding for email attachment (base64 conversion)
static int check_dirpath (char *dest, int len, char *domain, char *username, char *folder)
 Checks if directory exists. Does not create directory, but builds string in dest.
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)
 basically mkdir -p $dest/$domain/$username/$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)
 Find user from static memory object list.
static struct minivm_accountfind_user_realtime (const char *domain, const char *username)
 Find user in realtime storage Returns pointer to minivm_account structure.
static void free_user (struct minivm_account *vmu)
 Free user structure - if it's allocated.
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)
 Play intro message before recording voicemail.
static int leave_voicemail (struct ast_channel *chan, char *username, struct leave_vm_options *options)
 Record voicemail message, store into file prepared for sending e-mail.
static int load_config (int reload)
 Load minivoicemail configuration.
static int load_module (void)
 Load mini voicemail module.
static char * mailheader_quote (const char *from, char *to, size_t len)
 Fix quote of mail headers for non-ascii characters.
static int make_dir (char *dest, int len, const char *domain, const char *username, const char *folder)
 Create directory based on components.
static void message_destroy_list (void)
 Clear list of templates.
static int message_template_build (const char *name, struct ast_variable *var)
 Build message template from configuration.
static struct minivm_templatemessage_template_create (const char *name)
 Create message template.
static struct minivm_templatemessage_template_find (const char *name)
 Find named template.
static void message_template_free (struct minivm_template *template)
 Release memory allocated by message 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, void *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, void *data)
 Dialplan application to delete voicemail.
static int minivm_greet_exec (struct ast_channel *chan, void *data)
 Play voicemail prompts - either generic or user specific.
static int minivm_mwi_exec (struct ast_channel *chan, void *data)
 Send MWI using interal Asterisk event subsystem.
static int minivm_notify_exec (struct ast_channel *chan, void *data)
 Notify voicemail account owners - either generic template or user specific.
static int minivm_record_exec (struct ast_channel *chan, void *data)
 Dialplan function to record voicemail.
static struct minivm_accountmvm_user_alloc (void)
 Allocate new vm user and set default values.
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)
 Send message to voicemail account owner.
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, const char *unlockdir, signed char record_gain)
 Record voicemail message & let caller review or re-record it, or set options if applicable.
static void populate_defaults (struct minivm_account *vmu)
 Set default values for Mini-Voicemail users.
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)
 Prepare for voicemail template by adding channel variables to the channel.
static void queue_mwi_event (const char *mbx, const char *ctx, int urgent, int new, int old)
 Queue a message waiting event.
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)
 Send voicemail with audio file as an attachment.
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)
 Delete media files and attribute file.
static int vm_lock_path (const char *path)
 lock directory
static void vmaccounts_destroy_list (void)
 Clear list of users.

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mini VoiceMail (A minimal Voicemail e-mail System)" , .key = ASTERISK_GPL_KEY , .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_charset [32]
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
enum { ... }  minivm_option_args
enum { ... }  minivm_option_flags
static struct minivm_zones minivm_zones
static ast_mutex_t minivmlock = AST_MUTEX_INIT_VALUE
FILE * minivmlogfile
static ast_mutex_t minivmloglock = AST_MUTEX_INIT_VALUE
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 437 of file app_minivm.c.

#define B64_BASELINELEN   72

Line length for Base 64 endoded messages

Definition at line 427 of file app_minivm.c.

Referenced by b64_ochar().

#define B64_BASEMAXINLINE   256

Buffer size for Base 64 attachment encoding

Definition at line 426 of file app_minivm.c.

Referenced by b64_inbuf(), and base_encode().

#define DEFAULT_CHARSET   "ISO-8859-1"

Definition at line 597 of file app_minivm.c.

Referenced by message_template_create().

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

Default dateformat, can be overridden in configuration file.

Definition at line 596 of file app_minivm.c.

Referenced by message_template_create().

#define EOL   "\r\n"

Definition at line 428 of file app_minivm.c.

Referenced by b64_ochar(), and base_encode().

#define ERROR_LOCK_PATH   -100

Definition at line 433 of file app_minivm.c.

Referenced by minivm_record_exec().

#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 430 of file app_minivm.c.

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 431 of file app_minivm.c.

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

Definition at line 417 of file app_minivm.c.

#define MVM_OPERATOR   (1 << 1)

Operator exit during voicemail recording

Definition at line 414 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 418 of file app_minivm.c.

#define MVM_REALTIME   (1 << 2)

This user is a realtime account

Definition at line 415 of file app_minivm.c.

#define MVM_REVIEW   (1 << 0)

Review message

Definition at line 413 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 416 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 423 of file app_minivm.c.

Referenced by load_config().

#define SOUND_INTRO   "vm-intro"

Definition at line 425 of file app_minivm.c.

Referenced by minivm_greet_exec().

#define VOICEMAIL_CONFIG   "minivm.conf"

Definition at line 436 of file app_minivm.c.

Referenced by load_config().

#define VOICEMAIL_DIR_MODE   0700

Definition at line 434 of file app_minivm.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
OPT_SILENT 
OPT_BUSY_GREETING 
OPT_UNAVAIL_GREETING 
OPT_TEMP_GREETING 
OPT_NAME_GREETING 
OPT_RECORDGAIN 

Definition at line 458 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),
} minivm_option_flags;
anonymous enum
Enumerator:
OPT_ARG_RECORDGAIN 
OPT_ARG_ARRAY_SIZE 

Definition at line 467 of file app_minivm.c.

Message types for notification.

Enumerator:
MVM_MESSAGE_EMAIL 
MVM_MESSAGE_PAGE 

Definition at line 440 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 3350 of file app_minivm.c.

static void __unreg_module ( void  ) [static]

Definition at line 3350 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 3036 of file app_minivm.c.

References ast_debug, ast_log(), ast_unlock_path(), errno, LOG_ERROR, 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 2515 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 int b64_inbuf ( struct b64_baseio bio,
FILE *  fi 
) [static]

read buffer from file (base64 conversion)

Definition at line 729 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]

read character from file to buffer (base64 conversion)

Definition at line 751 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]

write buffer to file (base64 conversion)

Definition at line 762 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]

Encode file to base64 encoding for email attachment (base64 conversion)

Definition at line 780 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]

Checks if directory exists. Does not create directory, but builds string in dest.

Parameters:
destString. base directory.
lenInt. Length base directory string.
domainString. Ignored if is null or empty string.
usernameString. Ignored if is null or empty string.
folderString. Ignored if is null or empty string.
Returns:
0 on failure, 1 on success.

Definition at line 1276 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 char* complete_minivm_show_users ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 2755 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]

basically mkdir -p $dest/$domain/$username/$folder

Parameters:
destString. base directory.
lenLength of directory string
domainString. Ignored if is null or empty string.
folderString. Ignored if is null or empty string.
usernameString. Ignored if is null or empty string.
Returns:
-1 on failure, 0 on success.

Definition at line 1294 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 2299 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]

Find user from static memory object list.

Definition at line 955 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]

Find user in realtime storage Returns pointer to minivm_account structure.

Definition at line 998 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]

Free user structure - if it's allocated.

Definition at line 863 of file app_minivm.c.

References ast_free, ast_variables_destroy(), and minivm_account::chanvars.

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

{
   if (vmu->chanvars)
      ast_variables_destroy(vmu->chanvars);
   ast_free(vmu);
}
static void free_zone ( struct minivm_zone z) [static]

Free Mini Voicemail timezone.

Definition at line 2393 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 852 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 2714 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 3303 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 2865 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 2897 of file app_minivm.c.

References ast_cli(), ast_localtime(), ast_strftime(), buf, 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 2780 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 2828 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]

Play intro message before recording voicemail.

Definition at line 1309 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]

Record voicemail message, store into file prepared for sending e-mail.

Definition at line 1604 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, check_dirpath(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, 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_channel::language, minivm_stats::lastreceived, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, minivmlogfile, minivmloglock, MVM_ALLOCED, ast_channel::name, pbx_builtin_setvar_helper(), play_record_review(), ast_channel::priority, minivm_stats::receivedmessages, leave_vm_options::record_gain, and TRUE.

Referenced by minivm_record_exec().

{
   char tmptxtfile[PATH_MAX];
   char callerid[256];
   FILE *txt;
   int res = 0, txtdes;
   int msgnum;
   int 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;
   }
   msgnum = 0;

   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, 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);
      
      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,
         ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
         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 (duration < global_vmminmessage) {
         ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", 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++;
// /* 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);
// }

   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 2573 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_charset, 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);   
   strcpy(global_charset, "ISO-8859-1");
   /* 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 char* mailheader_quote ( const char *  from,
char *  to,
size_t  len 
) [static]

Fix quote of mail headers for non-ascii characters.

Definition at line 911 of file app_minivm.c.

Referenced by sendmail().

{
   char *ptr = to;
   *ptr++ = '"';
   for (; ptr < to + len - 1; from++) {
      if (*from == '"')
         *ptr++ = '\\';
      else if (*from == '\0')
         break;
      *ptr++ = *from;
   }
   if (ptr < to + len - 1)
      *ptr++ = '"';
   *ptr = '\0';
   return to;
}
static int make_dir ( char *  dest,
int  len,
const char *  domain,
const char *  username,
const char *  folder 
) [static]

Create directory based on components.

Definition at line 1263 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]

Build message template from configuration.

Definition at line 635 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]

Create message template.

Definition at line 607 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]

Find named template.

Definition at line 697 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]

Release memory allocated by message template.

Definition at line 626 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 2488 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 2448 of file app_minivm.c.

References ast_calloc, ast_config_AST_CONFIG_DIR, ast_copy_string(), ast_debug, ast_log(), ast_strlen_zero(), buf, 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,
void *  data 
) [static]

Record specific messages for voicemail account.

Definition at line 2195 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;
   int cmd;

   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 ? */
   cmd = play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, 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 2937 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;
      int found = 0;

      for (var = vmu->chanvars ; var ; var = var->next)
         if (!strcmp(var->name, colname)) {
            ast_copy_string(buf, var->value, len);
            found = 1;
            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 3089 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 3145 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,
void *  data 
) [static]

Dialplan application to delete voicemail.

Definition at line 2157 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,
void *  data 
) [static]

Play voicemail prompts - either generic or user specific.

Definition at line 1971 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(), check_dirpath(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, minivm_account::domain, minivm_account::exit, ast_channel::exten, find_account(), minivm_account::flags, free_user(), invent_message(), ast_channel::language, LOG_ERROR, ast_channel::macrocontext, minivm_app_options, MVM_ALLOCED, MVM_OPERATOR, OPT_ARG_ARRAY_SIZE, OPT_BUSY_GREETING, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), ast_channel::priority, SOUND_INTRO, TRUE, and minivm_account::username.

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, chan->cid.cid_num)) {
            strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
            ouseexten = 1;
         }
      } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
         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, chan->cid.cid_num)) {
         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, chan->cid.cid_num))
         strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
   } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
      strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
   else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
      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,
void *  data 
) [static]

Send MWI using interal Asterisk event subsystem.

Definition at line 1795 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,
void *  data 
) [static]

Notify voicemail account owners - either generic template or user specific.

Definition at line 1836 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::cid, ast_callerid::cid_name, ast_callerid::cid_num, minivm_account::domain, find_account(), format, free_user(), LOG_ERROR, LOG_WARNING, MVM_ALLOCED, notify_new_message(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), TRUE, and minivm_account::username.

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, chan->cid.cid_num, chan->cid.cid_name);
   }

   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,
void *  data 
) [static]

Dialplan function to record voicemail.

Definition at line 1915 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]

Allocate new vm user and set default values.

Definition at line 930 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]

Send message to voicemail account owner.

Definition at line 1527 of file app_minivm.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_log(), 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, manager_event, 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);
   }

   manager_event(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,
const char *  unlockdir,
signed char  record_gain 
) [static]

Record voicemail message & let caller review or re-record it, or set options if applicable.

Definition at line 1378 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, 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 populate_defaults ( struct minivm_account vmu) [static]
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]

Prepare for voicemail template by adding channel variables to the channel.

Definition at line 875 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 3297 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 1510 of file app_minivm.c.

References ast_debug, ast_safe_system(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, minivm_account::domain, minivm_account::externnotify, global_externnotify, and minivm_account::username.

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->cid.cid_name, chan->cid.cid_num);

   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]

Send voicemail with audio file as an attachment.

Definition at line 1027 of file app_minivm.c.

References ast_channel_alloc(), ast_channel_free(), ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_log(), ast_random(), ast_safe_system(), AST_STATE_DOWN, ast_strdupa, ast_strftime(), ast_strlen_zero(), ast_tvnow(), base_encode(), minivm_account::domain, minivm_account::email, minivm_account::fullname, global_charset, global_mailcmd, LOG_WARNING, mailheader_quote(), MAXHOSTNAMELEN, MVM_MESSAGE_EMAIL, MVM_MESSAGE_PAGE, minivm_zone::name, option_debug, minivm_account::pager, pbx_substitute_variables_helper(), 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;
   int len_passdata;
   struct ast_channel *ast;
   char *finalfilename;
   char *passdata = NULL;
   char *passdata2 = NULL;
   char *fromaddress;
   char *fromemail;

   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;

      ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
      ast_debug(3, "newtmp: %s\n", newtmp);
      tmpfd = mkstemp(newtmp);
      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_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");


   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 {
      /* Allocate a buffer big enough for variable substitution */
      int vmlen = strlen(fromaddress) * 3 + 200;

      ast_debug(4, "Fromaddress template: %s\n", fromaddress);
      if ((passdata = alloca(vmlen))) {
         pbx_substitute_variables_helper(ast, fromaddress, passdata, vmlen);
         len_passdata = strlen(passdata) * 2 + 3;
         passdata2 = alloca(len_passdata);
         fprintf(p, "From: %s <%s>\n", mailheader_quote(passdata, passdata2, len_passdata), who);
      } else  {
         ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
         fclose(p);
         return -1;  
      }
   } 
   ast_debug(4, "Fromstring now: %s\n", ast_strlen_zero(passdata) ? "-default-" : passdata);

   fprintf(p, "Message-ID: <Asterisk-%d-%s-%d-%s>\n", (unsigned int)ast_random(), vmu->username, (int)getpid(), who);
   len_passdata = strlen(vmu->fullname) * 2 + 3;
   passdata2 = alloca(len_passdata);
   if (!ast_strlen_zero(vmu->email))
      fprintf(p, "To: %s <%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->email);
   else
      fprintf(p, "To: %s <%s@%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->username, vmu->domain);

   if (!ast_strlen_zero(template->subject)) {
      char *pass_data;
      int vmlen = strlen(template->subject) * 3 + 200;
      if ((pass_data = alloca(vmlen))) {
         pbx_substitute_variables_helper(ast, template->subject, pass_data, vmlen);
         fprintf(p, "Subject: %s\n", pass_data);
      } else {
         ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
         fclose(p);
         return -1;  
      }

      ast_debug(4, "Subject now: %s\n", pass_data);

   } 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", global_charset);
   if (!ast_strlen_zero(template->body)) {
      char *pass_data;
      int vmlen = strlen(template->body)*3 + 200;
      if ((pass_data = alloca(vmlen))) {
         pbx_substitute_variables_helper(ast, template->body, pass_data, vmlen);
         ast_debug(3, "Message now: %s\n-----\n", pass_data);
         fprintf(p, "%s\n", pass_data);
      } else
         ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
   } 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);
   if (ast)
      ast_channel_free(ast);
   return 0;
}
static int timezone_add ( const char *  zonename,
const char *  config 
) [static]

Add time zone to memory list.

Definition at line 2411 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 2399 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]

Delete media files and attribute file.

Definition at line 1365 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 3019 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]

Clear list of users.

Definition at line 944 of file app_minivm.c.

References ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, and AST_LIST_UNLOCK.

Referenced by load_config(), and unload_module().


Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mini VoiceMail (A minimal Voicemail e-mail System)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 3350 of file app_minivm.c.

char* app_minivm_accmess = "MinivmAccMess" [static]

Definition at line 453 of file app_minivm.c.

char* app_minivm_delete = "MinivmDelete" [static]

Definition at line 452 of file app_minivm.c.

char* app_minivm_greet = "MinivmGreet" [static]

Definition at line 450 of file app_minivm.c.

char* app_minivm_mwi = "MinivmMWI" [static]

Definition at line 454 of file app_minivm.c.

char* app_minivm_notify = "MinivmNotify" [static]

Definition at line 451 of file app_minivm.c.

char* app_minivm_record = "MinivmRecord" [static]

Definition at line 449 of file app_minivm.c.

Definition at line 3350 of file app_minivm.c.

struct ast_cli_entry cli_minivm[] [static]

CLI commands for Mini-voicemail.

Definition at line 3220 of file app_minivm.c.

Referenced by load_module(), and unload_module().

char global_charset[32] [static]

Global charset in messages

Definition at line 591 of file app_minivm.c.

Referenced by load_config(), and sendmail().

char global_externnotify[160] [static]

External notification application

Definition at line 585 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 586 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 584 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 582 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 581 of file app_minivm.c.

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

Definition at line 590 of file app_minivm.c.

Referenced by load_config().

struct minivm_stats global_stats [static]

Statistics for voicemail.

Definition at line 572 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 580 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 579 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 593 of file app_minivm.c.

Referenced by populate_defaults().

struct ast_flags globalflags = {0} [static]

Global voicemail flags

Definition at line 589 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 484 of file app_minivm.c.

Referenced by minivm_accmess_exec().

Definition at line 3248 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 477 of file app_minivm.c.

Referenced by minivm_greet_exec(), and minivm_record_exec().

Definition at line 3229 of file app_minivm.c.

Referenced by load_module(), and unload_module().

enum { ... } minivm_option_args
enum { ... } minivm_option_flags
struct minivm_zones minivm_zones [static]
ast_mutex_t minivmlock = AST_MUTEX_INIT_VALUE [static]

Lock to protect voicemail system

Definition at line 574 of file app_minivm.c.

Referenced by load_config().

The minivm log file

Definition at line 577 of file app_minivm.c.

Referenced by leave_voicemail(), and load_config().

ast_mutex_t minivmloglock = AST_MUTEX_INIT_VALUE [static]

Lock to protect voicemail system log file

Definition at line 575 of file app_minivm.c.

Referenced by leave_voicemail().

char MVM_SPOOL_DIR[PATH_MAX] [static]

Definition at line 446 of file app_minivm.c.