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/dsp.h"
#include "asterisk/localtime.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/callerid.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/json.h"

Include dependency graph for app_minivm.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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

Variables

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


Detailed Description

MiniVoiceMail - A Minimal Voicemail System for Asterisk.

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

See also

Definition in file app_minivm.c.


Define Documentation

#define ASTERISK_USERNAME   "asterisk"

Default username for sending mail is asterisk@localhost

Definition at line 550 of file app_minivm.c.

Referenced by actual_load_config().

#define B64_BASELINELEN   72

Line length for Base 64 endoded messages

Definition at line 540 of file app_minivm.c.

Referenced by b64_ochar().

#define B64_BASEMAXINLINE   256

Buffer size for Base 64 attachment encoding

Definition at line 539 of file app_minivm.c.

Referenced by b64_inbuf(), and base_encode().

#define DEFAULT_CHARSET   "ISO-8859-1"

Definition at line 713 of file app_minivm.c.

Referenced by message_template_create().

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

Definition at line 712 of file app_minivm.c.

Referenced by message_template_create().

#define EOL   "\r\n"

Definition at line 541 of file app_minivm.c.

Referenced by b64_ochar(), and base_encode().

#define ERROR_LOCK_PATH   -100

#define FALSE   0

Definition at line 522 of file app_minivm.c.

Referenced by __sip_ack(), __sip_semi_ack(), _sip_qualify_peer(), _sip_show_peer(), _sip_show_peers(), add_sdp(), AST_TEST_DEFINE(), ast_tzset(), build_peer(), cb_extensionstate(), cc_handle_publish_error(), check_auth(), check_dirpath(), check_peer_ok(), check_pendings(), create_addr(), do_monitor(), expire_register(), extensionstate_update(), find_sdp(), function_sippeer(), g722_decode_init(), g722_encode_init(), getremainingfilelength(), handle_cli_ooh323_set_debug(), handle_request_invite(), handle_request_invite_st(), handle_request_notify(), handle_response(), handle_response_invite(), interpret_t38_parameters(), invent_message(), load_config(), main(), manager_sip_peer_status(), minivm_accmess_exec(), minivm_counter_func_read(), minivm_counter_func_write(), mwi_event_cb(), ooh323c_call_thread(), ooh323c_set_capability(), ooh323c_set_capability_for_call(), parse_register_contact(), parse_sip_options(), parseargs(), parsedoublearg(), parsefreq(), parseintarg(), parseswitch(), parseswitcharg(), parsetime(), parsetimearg(), parsevolarg(), parsevolume(), proc_session_timer(), process_crypto(), process_sdp(), process_sdp_a_audio(), process_sdp_a_dtls(), process_sdp_a_ice(), process_sdp_a_image(), process_sdp_a_sendonly(), process_sdp_a_text(), process_sdp_a_video(), process_sdp_c(), process_sdp_o(), proxy_from_config(), proxy_update(), rcvfax_exec(), readwavheader(), register_realtime_peers_with_callbackextens(), register_verify(), reload_config(), reqprep(), send_provisional_keepalive_full(), set_destination(), sip_addheader(), sip_answer(), sip_cc_monitor_request_cc(), sip_destroy_peer(), sip_devicestate(), sip_do_debug_peer(), sip_find_peer_by_ip_and_exten(), sip_hangup(), sip_is_xml_parsable(), sip_monitor_instance_destructor(), sip_parse_register_line(), sip_poke_noanswer(), sip_prune_realtime(), sip_read(), sip_reason_code_to_str(), sip_report_security_event(), sip_sendhtml(), sip_set_history(), sip_set_rtp_peer(), sip_show_inuse(), sip_show_settings(), sip_show_user(), sip_show_users(), sndfax_exec(), stop_session_timer(), time1(), time2(), time2sub(), transmit_audio(), transmit_fake_auth_response(), transmit_invite(), transmit_provisional_response(), transmit_publish(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_t38(), tzload(), tzparse(), update_call_counter(), update_connectedline(), and workloop().

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

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 544 of file app_minivm.c.

Referenced by actual_load_config(), and play_message_callerid().

#define MVM_ALLOCED   (1 << 13)

#define MVM_ENVELOPE   (1 << 4)

Definition at line 530 of file app_minivm.c.

#define MVM_OPERATOR   (1 << 1)

Operator exit during voicemail recording

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

#define MVM_REALTIME   (1 << 2)

This user is a realtime account

Definition at line 528 of file app_minivm.c.

#define MVM_REVIEW   (1 << 0)

#define MVM_SVMAIL   (1 << 3)

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

Referenced by actual_load_config(), and load_config().

#define SOUND_INTRO   "vm-intro"

Definition at line 538 of file app_minivm.c.

Referenced by minivm_greet_exec().

#define TRUE   1

Definition at line 519 of file app_minivm.c.

Referenced by __sip_ack(), __sip_alloc(), __sip_autodestruct(), __sip_semi_ack(), _sip_qualify_peer(), _sip_show_peer(), _sip_show_peers(), acl_change_stasis_cb(), add_sdp(), ast_tzset(), build_peer(), check_auth(), check_dirpath(), check_peer_ok(), check_pendings(), create_addr(), find_account(), find_sdp(), find_user_realtime(), forked_invite_init(), function_sippeer(), g722_decode_init(), g722_encode_init(), get_sip_pvt_from_replaces(), getremainingfilelength(), gmtload(), handle_cli_ooh323_set_debug(), handle_request_invite(), handle_request_invite_st(), handle_request_notify(), handle_request_refer(), handle_request_subscribe(), handle_response(), handle_response_invite(), handle_response_notify(), handle_response_peerpoke(), interpret_t38_parameters(), leave_voicemail(), load_config(), local_attended_transfer(), main(), manager_sip_peer_status(), message_template_create(), minivm_accmess_exec(), minivm_account_func_read(), minivm_greet_exec(), minivm_notify_exec(), mwi_event_cb(), ooh323_call(), ooh323c_start_call_thread(), parse_ok_contact(), parse_register_contact(), parse_sip_options(), parsedoublearg(), parsefreq(), parseintarg(), parseswitch(), parseswitcharg(), parsetime(), parsetimearg(), parsevolarg(), parsevolume(), proc_session_timer(), process_crypto(), process_sdp(), process_sdp_a_audio(), process_sdp_a_dtls(), process_sdp_a_ice(), process_sdp_a_image(), process_sdp_a_sendonly(), process_sdp_a_text(), process_sdp_a_video(), process_sdp_c(), process_sdp_o(), proxy_update(), rcvfax_exec(), readwavheader(), realtime_peer(), receive_message(), reg_source_db(), register_realtime_peers_with_callbackextens(), register_verify(), reload_config(), reqprep(), respprep(), restart_session_timer(), set_destination(), sip_addheader(), sip_answer(), sip_cc_agent_respond(), sip_destroy(), sip_devicestate(), sip_do_debug_peer(), sip_find_peer_by_ip_and_exten(), sip_hangup(), sip_indicate(), sip_is_xml_parsable(), sip_msg_send(), sip_prune_realtime(), sip_reason_code_to_str(), sip_reload(), sip_report_security_event(), sip_request_call(), sip_scheddestroy(), sip_set_history(), sip_show_channel(), sip_show_inuse(), sip_show_user(), sip_show_users(), sip_unregister(), sip_write(), sndfax_exec(), spandsp_fax_gateway_start(), spandsp_fax_start(), st_get_se(), start_session_timer(), stop_session_timer(), temp_peer(), time1(), time2(), time2sub(), transmit_audio(), transmit_cc_notify(), transmit_invite(), transmit_publish(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_t38(), tzload(), tzparse(), udptl_rx_packet(), update_connectedline(), and workloop().

#define VOICEMAIL_CONFIG   "minivm.conf"

Definition at line 549 of file app_minivm.c.

#define VOICEMAIL_DIR_MODE   0700


Enumeration Type Documentation

Enumerator:
OPT_ARG_RECORDGAIN 
OPT_ARG_ARRAY_SIZE 

Definition at line 580 of file app_minivm.c.

00580                         {
00581    OPT_ARG_RECORDGAIN = 0,
00582    OPT_ARG_ARRAY_SIZE = 1,
00583 };

Enumerator:
OPT_SILENT 
OPT_BUSY_GREETING 
OPT_UNAVAIL_GREETING 
OPT_TEMP_GREETING 
OPT_NAME_GREETING 
OPT_RECORDGAIN 

Definition at line 571 of file app_minivm.c.

00571                          {
00572    OPT_SILENT =      (1 << 0),
00573    OPT_BUSY_GREETING =    (1 << 1),
00574    OPT_UNAVAIL_GREETING = (1 << 2),
00575    OPT_TEMP_GREETING = (1 << 3),
00576    OPT_NAME_GREETING = (1 << 4),
00577    OPT_RECORDGAIN =  (1 << 5),
00578 };

Message types for notification.

Enumerator:
MVM_MESSAGE_EMAIL 
MVM_MESSAGE_PAGE 

Definition at line 553 of file app_minivm.c.

00553                      {
00554    MVM_MESSAGE_EMAIL,
00555    MVM_MESSAGE_PAGE
00556    /* For trunk: MVM_MESSAGE_JABBER, */
00557 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3568 of file app_minivm.c.

static void __unreg_module ( void   )  [static]

Definition at line 3568 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:
directory Directory to crate file in
countername filename
value If set to zero, we only read the variable
operand 0 to read, 1 to set new value, 2 to change
Returns:
-1 on error, otherwise counter value

Definition at line 3288 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().

03289 {
03290    char filename[BUFSIZ];
03291    char readbuf[BUFSIZ];
03292    FILE *counterfile;
03293    int old = 0, counter = 0;
03294 
03295    /* Lock directory */
03296    if (vm_lock_path(directory)) {
03297       return -1;  /* Could not lock directory */
03298    }
03299    snprintf(filename, sizeof(filename), "%s/%s.counter", directory, countername);
03300    if (operand != 1) {
03301       counterfile = fopen(filename, "r");
03302       if (counterfile) {
03303          if(fgets(readbuf, sizeof(readbuf), counterfile)) {
03304             ast_debug(3, "Read this string from counter file: %s\n", readbuf);
03305             old = counter = atoi(readbuf);
03306          }
03307          fclose(counterfile);
03308       }
03309    }
03310    switch (operand) {
03311    case 0:  /* Read only */
03312       ast_unlock_path(directory);
03313       ast_debug(2, "MINIVM Counter %s/%s: Value %d\n", directory, countername, counter);
03314       return counter;
03315       break;
03316    case 1: /* Set new value */
03317       counter = value;
03318       break;
03319    case 2: /* Change value */
03320       counter += value;
03321       if (counter < 0)  /* Don't allow counters to fall below zero */
03322          counter = 0;
03323       break;
03324    }
03325    
03326    /* Now, write the new value to the file */
03327    counterfile = fopen(filename, "w");
03328    if (!counterfile) {
03329       ast_log(LOG_ERROR, "Could not open counter file for writing : %s - %s\n", filename, strerror(errno));
03330       ast_unlock_path(directory);
03331       return -1;  /* Could not open file for writing */
03332    }
03333    fprintf(counterfile, "%d\n\n", counter);
03334    fclose(counterfile);
03335    ast_unlock_path(directory);
03336    ast_debug(2, "MINIVM Counter %s/%s: Old value %d New value %d\n", directory, countername, old, counter);
03337    return counter;
03338 }

static int apply_general_options ( struct ast_variable var  )  [static]

Apply general configuration options.

Definition at line 2773 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, error(), 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().

02774 {
02775    int error = 0;
02776 
02777    while (var) {
02778       /* Mail command */
02779       if (!strcmp(var->name, "mailcmd")) {
02780          ast_copy_string(global_mailcmd, var->value, sizeof(global_mailcmd)); /* User setting */
02781       } else if (!strcmp(var->name, "maxgreet")) {
02782          global_maxgreet = atoi(var->value);
02783       } else if (!strcmp(var->name, "maxsilence")) {
02784          global_maxsilence = atoi(var->value);
02785          if (global_maxsilence > 0)
02786             global_maxsilence *= 1000;
02787       } else if (!strcmp(var->name, "logfile")) {
02788          if (!ast_strlen_zero(var->value) ) {
02789             if(*(var->value) == '/')
02790                ast_copy_string(global_logfile, var->value, sizeof(global_logfile));
02791             else
02792                snprintf(global_logfile, sizeof(global_logfile), "%s/%s", ast_config_AST_LOG_DIR, var->value);
02793          }
02794       } else if (!strcmp(var->name, "externnotify")) {
02795          /* External voicemail notify application */
02796          ast_copy_string(global_externnotify, var->value, sizeof(global_externnotify));
02797       } else if (!strcmp(var->name, "silencetreshold")) {
02798          /* Silence treshold */
02799          global_silencethreshold = atoi(var->value);
02800       } else if (!strcmp(var->name, "maxmessage")) {
02801          int x;
02802          if (sscanf(var->value, "%30d", &x) == 1) {
02803             global_vmmaxmessage = x;
02804          } else {
02805             error ++;
02806             ast_log(LOG_WARNING, "Invalid max message time length\n");
02807          }
02808       } else if (!strcmp(var->name, "minmessage")) {
02809          int x;
02810          if (sscanf(var->value, "%30d", &x) == 1) {
02811             global_vmminmessage = x;
02812             if (global_maxsilence <= global_vmminmessage)
02813                ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
02814          } else {
02815             error ++;
02816             ast_log(LOG_WARNING, "Invalid min message time length\n");
02817          }
02818       } else if (!strcmp(var->name, "format")) {
02819          ast_copy_string(default_vmformat, var->value, sizeof(default_vmformat));
02820       } else if (!strcmp(var->name, "review")) {
02821          ast_set2_flag((&globalflags), ast_true(var->value), MVM_REVIEW);  
02822       } else if (!strcmp(var->name, "operator")) {
02823          ast_set2_flag((&globalflags), ast_true(var->value), MVM_OPERATOR);   
02824       }
02825       var = var->next;
02826    }
02827    return error;
02828 }

static const char* ast_str_encode_mime ( struct ast_str **  end,
ssize_t  maxlen,
const char *  charset,
const char *  start,
size_t  preamble,
size_t  postamble 
) [static]

Definition at line 1174 of file app_minivm.c.

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

Referenced by make_email_file(), sendmail(), and sendpage().

01175 {
01176    struct ast_str *tmp = ast_str_alloca(80);
01177    int first_section = 1;
01178 
01179    ast_str_reset(*end);
01180    ast_str_set(&tmp, -1, "=?%s?Q?", charset);
01181    for (; *start; start++) {
01182       int need_encoding = 0;
01183       if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
01184          need_encoding = 1;
01185       }
01186       if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
01187          (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
01188          (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
01189          (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
01190          /* Start new line */
01191          ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
01192          ast_str_set(&tmp, -1, "=?%s?Q?", charset);
01193          first_section = 0;
01194       }
01195       if (need_encoding && *start == ' ') {
01196          ast_str_append(&tmp, -1, "_");
01197       } else if (need_encoding) {
01198          ast_str_append(&tmp, -1, "=%hhX", *start);
01199       } else {
01200          ast_str_append(&tmp, -1, "%c", *start);
01201       }
01202    }
01203    ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
01204    return ast_str_buffer(*end);
01205 }

static const char* ast_str_quote ( struct ast_str **  buf,
ssize_t  maxlen,
const char *  from 
) [static]

Definition at line 1215 of file app_minivm.c.

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

Referenced by make_email_file(), sendmail(), and sendpage().

01216 {
01217    const char *ptr;
01218 
01219    /* We're only ever passing 0 to maxlen, so short output isn't possible */
01220    ast_str_set(buf, maxlen, "\"");
01221    for (ptr = from; *ptr; ptr++) {
01222       if (*ptr == '"' || *ptr == '\\') {
01223          ast_str_append(buf, maxlen, "\\%c", *ptr);
01224       } else {
01225          ast_str_append(buf, maxlen, "%c", *ptr);
01226       }
01227    }
01228    ast_str_append(buf, maxlen, "\"");
01229 
01230    return ast_str_buffer(*buf);
01231 }

static int b64_inbuf ( struct b64_baseio bio,
FILE *  fi 
) [static]

Definition at line 852 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().

00853 {
00854    int l;
00855 
00856    if (bio->ateof)
00857       return 0;
00858 
00859    if ((l = fread(bio->iobuf, 1, B64_BASEMAXINLINE,fi)) <= 0) {
00860       if (ferror(fi))
00861          return -1;
00862 
00863       bio->ateof = 1;
00864       return 0;
00865    }
00866 
00867    bio->iolen= l;
00868    bio->iocp= 0;
00869 
00870    return 1;
00871 }

static int b64_inchar ( struct b64_baseio bio,
FILE *  fi 
) [static]

Definition at line 875 of file app_minivm.c.

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

Referenced by base_encode().

00876 {
00877    if (bio->iocp >= bio->iolen) {
00878       if (!b64_inbuf(bio, fi))
00879          return EOF;
00880    }
00881 
00882    return bio->iobuf[bio->iocp++];
00883 }

static int b64_ochar ( struct b64_baseio bio,
int  c,
FILE *  so 
) [static]

Definition at line 887 of file app_minivm.c.

References B64_BASELINELEN, EOL, and b64_baseio::linelength.

Referenced by base_encode().

00888 {
00889    if (bio->linelength >= B64_BASELINELEN) {
00890       if (fputs(EOL,so) == EOF)
00891          return -1;
00892 
00893       bio->linelength= 0;
00894    }
00895 
00896    if (putc(((unsigned char) c), so) == EOF)
00897       return -1;
00898 
00899    bio->linelength++;
00900 
00901    return 1;
00902 }

static int base_encode ( char *  filename,
FILE *  so 
) [static]

Definition at line 906 of file app_minivm.c.

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

Referenced by add_email_attachment(), and sendmail().

00907 {
00908    unsigned char dtable[B64_BASEMAXINLINE];
00909    int i,hiteof= 0;
00910    FILE *fi;
00911    struct b64_baseio bio;
00912 
00913    memset(&bio, 0, sizeof(bio));
00914    bio.iocp = B64_BASEMAXINLINE;
00915 
00916    if (!(fi = fopen(filename, "rb"))) {
00917       ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
00918       return -1;
00919    }
00920 
00921    for (i= 0; i<9; i++) {
00922       dtable[i]= 'A'+i;
00923       dtable[i+9]= 'J'+i;
00924       dtable[26+i]= 'a'+i;
00925       dtable[26+i+9]= 'j'+i;
00926    }
00927    for (i= 0; i < 8; i++) {
00928       dtable[i+18]= 'S'+i;
00929       dtable[26+i+18]= 's'+i;
00930    }
00931    for (i= 0; i < 10; i++) {
00932       dtable[52+i]= '0'+i;
00933    }
00934    dtable[62]= '+';
00935    dtable[63]= '/';
00936 
00937    while (!hiteof){
00938       unsigned char igroup[3], ogroup[4];
00939       int c,n;
00940 
00941       igroup[0]= igroup[1]= igroup[2]= 0;
00942 
00943       for (n= 0; n < 3; n++) {
00944          if ((c = b64_inchar(&bio, fi)) == EOF) {
00945             hiteof= 1;
00946             break;
00947          }
00948          igroup[n]= (unsigned char)c;
00949       }
00950 
00951       if (n> 0) {
00952          ogroup[0]= dtable[igroup[0]>>2];
00953          ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
00954          ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
00955          ogroup[3]= dtable[igroup[2]&0x3F];
00956 
00957          if (n<3) {
00958             ogroup[3]= '=';
00959 
00960             if (n<2)
00961                ogroup[2]= '=';
00962          }
00963 
00964          for (i= 0;i<4;i++)
00965             b64_ochar(&bio, ogroup[i], so);
00966       }
00967    }
00968 
00969    /* Put end of line - line feed */
00970    if (fputs(EOL, so) == EOF)
00971       return 0;
00972 
00973    fclose(fi);
00974 
00975    return 1;
00976 }

static int check_dirpath ( char *  dest,
int  len,
char *  domain,
char *  username,
char *  folder 
) [static]

Definition at line 1520 of file app_minivm.c.

References FALSE, make_dir(), and TRUE.

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

01521 {
01522    struct stat filestat;
01523    make_dir(dest, len, domain, username, folder ? folder : "");
01524    if (stat(dest, &filestat)== -1)
01525       return FALSE;
01526    else
01527       return TRUE;
01528 }

static int check_mime ( const char *  str  )  [static]

Definition at line 1145 of file app_minivm.c.

Referenced by make_email_file(), sendmail(), and sendpage().

01146 {
01147    for (; *str; str++) {
01148       if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
01149          return 1;
01150       }
01151    }
01152    return 0;
01153 }

static char* complete_minivm_show_users ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 3012 of file app_minivm.c.

References AST_LIST_TRAVERSE, ast_strdup, minivm_account::domain, and NULL.

Referenced by handle_minivm_show_users().

03013 {
03014    int which = 0;
03015    int wordlen;
03016    struct minivm_account *vmu;
03017    const char *domain = "";
03018 
03019    /* 0 - voicemail; 1 - list; 2 - accounts; 3 - for; 4 - <domain> */
03020    if (pos > 4)
03021       return NULL;
03022    if (pos == 3)
03023       return (state == 0) ? ast_strdup("for") : NULL;
03024    wordlen = strlen(word);
03025    AST_LIST_TRAVERSE(&minivm_accounts, vmu, list) {
03026       if (!strncasecmp(word, vmu->domain, wordlen)) {
03027          if (domain && strcmp(domain, vmu->domain) && ++which > state)
03028             return ast_strdup(vmu->domain);
03029          /* ignore repeated domains ? */
03030          domain = vmu->domain;
03031       }
03032    }
03033    return NULL;
03034 }

static int create_dirpath ( char *  dest,
int  len,
char *  domain,
char *  username,
char *  folder 
) [static]

Definition at line 1539 of file app_minivm.c.

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

Referenced by add_email_attachment(), copy_message(), invent_message(), leave_voicemail(), minivm_counter_func_read(), minivm_counter_func_write(), msg_create_from_file(), open_mailbox(), and save_to_folder().

01540 {
01541    int res;
01542    make_dir(dest, len, domain, username, folder);
01543    if ((res = ast_mkdir(dest, 0777))) {
01544       ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01545       return -1;
01546    }
01547    ast_debug(2, "Creating directory for %s@%s folder %s : %s\n", username, domain, folder, dest);
01548    return 0;
01549 }

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 2562 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().

02563 {
02564    struct minivm_account *vmu;
02565    char *domain;
02566    char *username;
02567    char accbuf[BUFSIZ];
02568 
02569    ast_debug(3, "Creating %s account for [%s]\n", realtime ? "realtime" : "static", name);
02570 
02571    ast_copy_string(accbuf, name, sizeof(accbuf));
02572    username = accbuf;
02573    domain = strchr(accbuf, '@');
02574    if (domain) {
02575       *domain = '\0';
02576       domain++;
02577    }
02578    if (ast_strlen_zero(domain)) {
02579       ast_log(LOG_ERROR, "No domain given for mini-voicemail account %s. Not configured.\n", name);
02580       return 0;
02581    }
02582 
02583    ast_debug(3, "Creating static account for user %s domain %s\n", username, domain);
02584 
02585    /* Allocate user account */
02586    vmu = ast_calloc(1, sizeof(*vmu));
02587    if (!vmu)
02588       return 0;
02589    
02590    ast_copy_string(vmu->domain, domain, sizeof(vmu->domain));
02591    ast_copy_string(vmu->username, username, sizeof(vmu->username));
02592 
02593    populate_defaults(vmu);
02594 
02595    ast_debug(3, "...Configuring account %s\n", name);
02596 
02597    while (var) {
02598       ast_debug(3, "Configuring %s = \"%s\" for account %s\n", var->name, var->value, name);
02599       if (!strcasecmp(var->name, "serveremail")) {
02600          ast_copy_string(vmu->serveremail, var->value, sizeof(vmu->serveremail));
02601       } else if (!strcasecmp(var->name, "email")) {
02602          ast_copy_string(vmu->email, var->value, sizeof(vmu->email));
02603       } else if (!strcasecmp(var->name, "accountcode")) {
02604          ast_copy_string(vmu->accountcode, var->value, sizeof(vmu->accountcode));
02605       } else if (!strcasecmp(var->name, "pincode")) {
02606          ast_copy_string(vmu->pincode, var->value, sizeof(vmu->pincode));
02607       } else if (!strcasecmp(var->name, "domain")) {
02608          ast_copy_string(vmu->domain, var->value, sizeof(vmu->domain));
02609       } else if (!strcasecmp(var->name, "language")) {
02610          ast_copy_string(vmu->language, var->value, sizeof(vmu->language));
02611       } else if (!strcasecmp(var->name, "timezone")) {
02612          ast_copy_string(vmu->zonetag, var->value, sizeof(vmu->zonetag));
02613       } else if (!strcasecmp(var->name, "externnotify")) {
02614          ast_copy_string(vmu->externnotify, var->value, sizeof(vmu->externnotify));
02615       } else if (!strcasecmp(var->name, "etemplate")) {
02616          ast_copy_string(vmu->etemplate, var->value, sizeof(vmu->etemplate));
02617       } else if (!strcasecmp(var->name, "ptemplate")) {
02618          ast_copy_string(vmu->ptemplate, var->value, sizeof(vmu->ptemplate));
02619       } else if (!strcasecmp(var->name, "fullname")) {
02620          ast_copy_string(vmu->fullname, var->value, sizeof(vmu->fullname));
02621       } else if (!strcasecmp(var->name, "setvar")) {
02622          char *varval;
02623          char *varname = ast_strdupa(var->value);
02624          struct ast_variable *tmpvar;
02625 
02626          if ((varval = strchr(varname, '='))) {
02627             *varval = '\0';
02628             varval++;
02629             if ((tmpvar = ast_variable_new(varname, varval, ""))) {
02630                tmpvar->next = vmu->chanvars;
02631                vmu->chanvars = tmpvar;
02632             }
02633          }
02634       } else if (!strcasecmp(var->name, "pager")) {
02635          ast_copy_string(vmu->pager, var->value, sizeof(vmu->pager));
02636       } else if (!strcasecmp(var->name, "volgain")) {
02637          sscanf(var->value, "%30lf", &vmu->volgain);
02638       } else {
02639          ast_log(LOG_ERROR, "Unknown configuration option for minivm account %s : %s\n", name, var->name);
02640       }
02641       var = var->next;
02642    }
02643    ast_debug(3, "...Linking account %s\n", name);
02644    
02645    AST_LIST_LOCK(&minivm_accounts);
02646    AST_LIST_INSERT_TAIL(&minivm_accounts, vmu, list);
02647    AST_LIST_UNLOCK(&minivm_accounts);
02648 
02649    global_stats.voicemailaccounts++;
02650 
02651    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)" : "");
02652    return 0;
02653 }

static struct minivm_account* find_account ( const char *  domain,
const char *  username,
int  createtemp 
) [static, read]

Definition at line 1068 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(), NULL, 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().

01069 {
01070    struct minivm_account *vmu = NULL, *cur;
01071 
01072 
01073    if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
01074       ast_log(LOG_NOTICE, "No username or domain? \n");
01075       return NULL;
01076    }
01077    ast_debug(3, "Looking for voicemail user %s in domain %s\n", username, domain);
01078 
01079    AST_LIST_LOCK(&minivm_accounts);
01080    AST_LIST_TRAVERSE(&minivm_accounts, cur, list) {
01081       /* Is this the voicemail account we're looking for? */
01082       if (!strcasecmp(domain, cur->domain) && !strcasecmp(username, cur->username))
01083          break;
01084    }
01085    AST_LIST_UNLOCK(&minivm_accounts);
01086 
01087    if (cur) {
01088       ast_debug(3, "Found account for %s@%s\n", username, domain);
01089       vmu = cur;
01090 
01091    } else
01092       vmu = find_user_realtime(domain, username);
01093 
01094    if (createtemp && !vmu) {
01095       /* Create a temporary user, send e-mail and be gone */
01096       vmu = mvm_user_alloc();
01097       ast_set2_flag(vmu, TRUE, MVM_ALLOCED); 
01098       if (vmu) {
01099          ast_copy_string(vmu->username, username, sizeof(vmu->username));
01100          ast_copy_string(vmu->domain, domain, sizeof(vmu->domain));
01101          ast_debug(1, "Created temporary account\n");
01102       }
01103 
01104    }
01105    return vmu;
01106 }

static struct minivm_account * find_user_realtime ( const char *  domain,
const char *  username 
) [static, read]

Definition at line 1112 of file app_minivm.c.

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

Referenced by find_account(), and find_user().

01113 {
01114    struct ast_variable *var;
01115    struct minivm_account *retval;
01116    char name[MAXHOSTNAMELEN];
01117 
01118    retval = mvm_user_alloc();
01119    if (!retval)
01120       return NULL;
01121 
01122    if (username) 
01123       ast_copy_string(retval->username, username, sizeof(retval->username));
01124 
01125    populate_defaults(retval);
01126    var = ast_load_realtime("minivm", "username", username, "domain", domain, SENTINEL);
01127 
01128    if (!var) {
01129       ast_free(retval);
01130       return NULL;
01131    }
01132 
01133    snprintf(name, sizeof(name), "%s@%s", username, domain);
01134    create_vmaccount(name, var, TRUE);
01135 
01136    ast_variables_destroy(var);
01137    return retval;
01138 }

static void free_user ( struct minivm_account vmu  )  [static]

static void free_zone ( struct minivm_zone z  )  [static]

Free Mini Voicemail timezone.

Definition at line 2656 of file app_minivm.c.

References ast_free.

Referenced by free_vm_zones(), and timezone_destroy_list().

02657 {
02658    ast_free(z);
02659 }

static int get_date ( char *  s,
int  len 
) [static]

Definition at line 978 of file app_minivm.c.

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

Referenced by leave_voicemail(), msg_create_from_file(), and tds_log().

00979 {
00980    struct ast_tm tm;
00981    struct timeval now = ast_tvnow();
00982 
00983    ast_localtime(&now, &tm, NULL);
00984    return ast_strftime(s, len, "%a %b %e %r %Z %Y", &tm);
00985 }

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 2971 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, NULL, and ast_cli_entry::usage.

02972 {
02973    struct minivm_template *this;
02974 #define HVLT_OUTPUT_FORMAT "%-15s %-10s %-10s %-15.15s %-50s\n"
02975    int count = 0;
02976 
02977    switch (cmd) {
02978    case CLI_INIT:
02979       e->command = "minivm list templates";
02980       e->usage =
02981          "Usage: minivm list templates\n"
02982          "       Lists message templates for e-mail, paging and IM\n";
02983       return NULL;
02984    case CLI_GENERATE:
02985       return NULL;
02986    }
02987 
02988    if (a->argc > 3)
02989       return CLI_SHOWUSAGE;
02990 
02991    AST_LIST_LOCK(&message_templates);
02992    if (AST_LIST_EMPTY(&message_templates)) {
02993       ast_cli(a->fd, "There are no message templates defined\n");
02994       AST_LIST_UNLOCK(&message_templates);
02995       return CLI_FAILURE;
02996    }
02997    ast_cli(a->fd, HVLT_OUTPUT_FORMAT, "Template name", "Charset", "Locale", "Attach media", "Subject");
02998    ast_cli(a->fd, HVLT_OUTPUT_FORMAT, "-------------", "-------", "------", "------------", "-------");
02999    AST_LIST_TRAVERSE(&message_templates, this, list) {
03000       ast_cli(a->fd, HVLT_OUTPUT_FORMAT, this->name, 
03001          this->charset ? this->charset : "-", 
03002          this->locale ? this->locale : "-",
03003          this->attachment ? "Yes" : "No",
03004          this->subject ? this->subject : "-");
03005       count++;
03006    }
03007    AST_LIST_UNLOCK(&message_templates);
03008    ast_cli(a->fd, "\n * Total: %d minivoicemail message templates\n", count);
03009    return CLI_SUCCESS;
03010 }

static char * handle_minivm_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Reload cofiguration.

Definition at line 3520 of file app_minivm.c.

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

03521 {
03522    
03523    switch (cmd) {
03524    case CLI_INIT:
03525       e->command = "minivm reload";
03526       e->usage =
03527          "Usage: minivm reload\n"
03528          "       Reload mini-voicemail configuration and reset statistics\n";
03529       return NULL;
03530    case CLI_GENERATE:
03531       return NULL;
03532    }
03533    
03534    reload();
03535    ast_cli(a->fd, "\n-- Mini voicemail re-configured \n");
03536    return CLI_SUCCESS;
03537 }

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 3122 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, NULL, and ast_cli_entry::usage.

03123 {
03124    switch (cmd) {
03125    case CLI_INIT:
03126       e->command = "minivm show settings";
03127       e->usage =
03128          "Usage: minivm show settings\n"
03129          "       Display Mini-Voicemail general settings\n";
03130       return NULL;
03131    case CLI_GENERATE:
03132       return NULL;
03133    }
03134 
03135    ast_cli(a->fd, "* Mini-Voicemail general settings\n");
03136    ast_cli(a->fd, "  -------------------------------\n");
03137    ast_cli(a->fd, "\n");
03138    ast_cli(a->fd, "  Mail command (shell):               %s\n", global_mailcmd);
03139    ast_cli(a->fd, "  Max silence:                        %d\n", global_maxsilence);
03140    ast_cli(a->fd, "  Silence threshold:                  %d\n", global_silencethreshold);
03141    ast_cli(a->fd, "  Max message length (secs):          %d\n", global_vmmaxmessage);
03142    ast_cli(a->fd, "  Min message length (secs):          %d\n", global_vmminmessage);
03143    ast_cli(a->fd, "  Default format:                     %s\n", default_vmformat);
03144    ast_cli(a->fd, "  Extern notify (shell):              %s\n", global_externnotify);
03145    ast_cli(a->fd, "  Logfile:                            %s\n", global_logfile[0] ? global_logfile : "<disabled>");
03146    ast_cli(a->fd, "  Operator exit:                      %s\n", ast_test_flag(&globalflags, MVM_OPERATOR) ? "Yes" : "No");
03147    ast_cli(a->fd, "  Message review:                     %s\n", ast_test_flag(&globalflags, MVM_REVIEW) ? "Yes" : "No");
03148 
03149    ast_cli(a->fd, "\n");
03150    return CLI_SUCCESS;
03151 }

static char* handle_minivm_show_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show stats.

Definition at line 3154 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, NULL, minivm_stats::receivedmessages, minivm_stats::reset, minivm_stats::templates, minivm_stats::timezones, ast_cli_entry::usage, and minivm_stats::voicemailaccounts.

03155 {
03156    struct ast_tm timebuf;
03157    char buf[BUFSIZ];
03158 
03159    switch (cmd) {
03160    
03161    case CLI_INIT:
03162       e->command = "minivm show stats";
03163       e->usage =
03164          "Usage: minivm show stats\n"
03165          "       Display Mini-Voicemail counters\n";
03166       return NULL;
03167    case CLI_GENERATE:
03168       return NULL;
03169    }
03170 
03171    ast_cli(a->fd, "* Mini-Voicemail statistics\n");
03172    ast_cli(a->fd, "  -------------------------\n");
03173    ast_cli(a->fd, "\n");
03174    ast_cli(a->fd, "  Voicemail accounts:                  %5d\n", global_stats.voicemailaccounts);
03175    ast_cli(a->fd, "  Templates:                           %5d\n", global_stats.templates);
03176    ast_cli(a->fd, "  Timezones:                           %5d\n", global_stats.timezones);
03177    if (global_stats.receivedmessages == 0) {
03178       ast_cli(a->fd, "  Received messages since last reset:  <none>\n");
03179    } else {
03180       ast_cli(a->fd, "  Received messages since last reset:  %d\n", global_stats.receivedmessages);
03181       ast_localtime(&global_stats.lastreceived, &timebuf, NULL);
03182       ast_strftime(buf, sizeof(buf), "%a %b %e %r %Z %Y", &timebuf);
03183       ast_cli(a->fd, "  Last received voicemail:             %s\n", buf);
03184    }
03185    ast_localtime(&global_stats.reset, &timebuf, NULL);
03186    ast_strftime(buf, sizeof(buf), "%a %b %e %r %Z %Y", &timebuf);
03187    ast_cli(a->fd, "  Last reset:                          %s\n", buf);
03188 
03189    ast_cli(a->fd, "\n");
03190    return CLI_SUCCESS;
03191 }

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 3037 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, NULL, ast_cli_args::pos, minivm_account::ptemplate, tmp(), ast_cli_entry::usage, minivm_account::username, ast_cli_args::word, and minivm_account::zonetag.

03038 {
03039    struct minivm_account *vmu;
03040 #define HMSU_OUTPUT_FORMAT "%-23s %-15s %-15s %-10s %-10s %-50s\n"
03041    int count = 0;
03042 
03043    switch (cmd) {
03044    case CLI_INIT:
03045       e->command = "minivm list accounts";
03046       e->usage =
03047          "Usage: minivm list accounts\n"
03048          "       Lists all mailboxes currently set up\n";
03049       return NULL;
03050    case CLI_GENERATE:
03051       return complete_minivm_show_users(a->line, a->word, a->pos, a->n);
03052    }
03053 
03054    if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
03055       return CLI_SHOWUSAGE;
03056    if ((a->argc == 5) && strcmp(a->argv[3],"for"))
03057       return CLI_SHOWUSAGE;
03058 
03059    AST_LIST_LOCK(&minivm_accounts);
03060    if (AST_LIST_EMPTY(&minivm_accounts)) {
03061       ast_cli(a->fd, "There are no voicemail users currently defined\n");
03062       AST_LIST_UNLOCK(&minivm_accounts);
03063       return CLI_FAILURE;
03064    }
03065    ast_cli(a->fd, HMSU_OUTPUT_FORMAT, "User", "E-Template", "P-template", "Zone", "Format", "Full name");
03066    ast_cli(a->fd, HMSU_OUTPUT_FORMAT, "----", "----------", "----------", "----", "------", "---------");
03067    AST_LIST_TRAVERSE(&minivm_accounts, vmu, list) {
03068       char tmp[256] = "";
03069       if ((a->argc == 3) || ((a->argc == 5) && !strcmp(a->argv[4], vmu->domain))) {
03070          count++;
03071          snprintf(tmp, sizeof(tmp), "%s@%s", vmu->username, vmu->domain);
03072          ast_cli(a->fd, HMSU_OUTPUT_FORMAT, tmp, vmu->etemplate ? vmu->etemplate : "-", 
03073             vmu->ptemplate ? vmu->ptemplate : "-",
03074             vmu->zonetag ? vmu->zonetag : "-", 
03075             vmu->attachfmt ? vmu->attachfmt : "-",
03076             vmu->fullname);
03077       }
03078    }
03079    AST_LIST_UNLOCK(&minivm_accounts);
03080    ast_cli(a->fd, "\n * Total: %d minivoicemail accounts\n", count);
03081    return CLI_SUCCESS;
03082 }

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 3085 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, NULL, minivm_zone::timezone, and ast_cli_entry::usage.

03086 {
03087    struct minivm_zone *zone;
03088 #define HMSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
03089    char *res = CLI_SUCCESS;
03090 
03091    switch (cmd) {
03092    case CLI_INIT:
03093       e->command = "minivm list zones";
03094       e->usage =
03095          "Usage: minivm list zones\n"
03096          "       Lists zone message formats\n";
03097       return NULL;
03098    case CLI_GENERATE:
03099       return NULL;
03100    }
03101 
03102    if (a->argc != e->args)
03103       return CLI_SHOWUSAGE;
03104 
03105    AST_LIST_LOCK(&minivm_zones);
03106    if (!AST_LIST_EMPTY(&minivm_zones)) {
03107       ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
03108       ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, "----", "--------", "--------------");
03109       AST_LIST_TRAVERSE(&minivm_zones, zone, list) {
03110          ast_cli(a->fd, HMSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
03111       }
03112    } else {
03113       ast_cli(a->fd, "There are no voicemail zones currently defined\n");
03114       res = CLI_FAILURE;
03115    }
03116    AST_LIST_UNLOCK(&minivm_zones);
03117 
03118    return res;
03119 }

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

Definition at line 1555 of file app_minivm.c.

References ast_channel_language(), ast_debug, ast_fileexists(), ast_say_digit_str(), ast_streamfile(), ast_waitstream(), FALSE, and NULL.

Referenced by leave_voicemail(), and minivm_greet_exec().

01556 {
01557    int res;
01558    char fn[PATH_MAX];
01559 
01560    ast_debug(2, "Still preparing to play message ...\n");
01561 
01562    snprintf(fn, sizeof(fn), "%s%s/%s/greet", MVM_SPOOL_DIR, domain, username);
01563 
01564    if (ast_fileexists(fn, NULL, NULL) > 0) {
01565       res = ast_streamfile(chan, fn, ast_channel_language(chan));
01566       if (res) 
01567          return -1;
01568       res = ast_waitstream(chan, ecodes);
01569       if (res) 
01570          return res;
01571    } else {
01572       int numericusername = 1;
01573       char *i = username;
01574 
01575       ast_debug(2, "No personal prompts. Using default prompt set for language\n");
01576 
01577       while (*i)  {
01578          ast_debug(2, "Numeric? Checking %c\n", *i);
01579          if (!isdigit(*i)) {
01580             numericusername = FALSE;
01581             break;
01582          }
01583          i++;
01584       }
01585 
01586       if (numericusername) {
01587          if (ast_streamfile(chan, "vm-theperson", ast_channel_language(chan)))
01588             return -1;
01589          if ((res = ast_waitstream(chan, ecodes)))
01590             return res;
01591 
01592          res = ast_say_digit_str(chan, username, ecodes, ast_channel_language(chan));
01593          if (res)
01594             return res;
01595       } else {
01596          if (ast_streamfile(chan, "vm-theextensionis", ast_channel_language(chan)))
01597             return -1;
01598          if ((res = ast_waitstream(chan, ecodes)))
01599             return res;
01600       }
01601    }
01602 
01603    res = ast_streamfile(chan, busy ? "vm-isonphone" : "vm-isunavail", ast_channel_language(chan));
01604    if (res)
01605       return -1;
01606    res = ast_waitstream(chan, ecodes);
01607    return res;
01608 }

static int leave_voicemail ( struct ast_channel chan,
char *  username,
struct leave_vm_options options 
) [static]

Definition at line 1880 of file app_minivm.c.

References minivm_account::accountcode, ast_callerid_merge(), ast_channel_caller(), ast_channel_context(), ast_channel_exten(), ast_channel_language(), ast_channel_macrocontext(), ast_channel_name(), ast_channel_priority(), 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(), create_dirpath(), default_vmformat, minivm_account::domain, errno, find_account(), free_user(), get_date(), global_stats, global_vmmaxmessage, global_vmminmessage, minivm_stats::lastreceived, LOG_ERROR, LOG_WARNING, minivmlogfile, minivmloglock, MVM_ALLOCED, NULL, pbx_builtin_setvar_helper(), play_record_review(), minivm_stats::receivedmessages, leave_vm_options::record_gain, S_COR, tmp(), and TRUE.

Referenced by advanced_options(), forward_message(), minivm_record_exec(), and vm_exec().

01881 {
01882    char tmptxtfile[PATH_MAX];
01883    char callerid[256];
01884    FILE *txt;
01885    int res = 0, txtdes;
01886    int duration = 0;
01887    int sound_duration = 0;
01888    char date[256];
01889    char tmpdir[PATH_MAX];
01890    char ext_context[256] = "";
01891    char fmt[80];
01892    char *domain;
01893    char tmp[256] = "";
01894    struct minivm_account *vmu;
01895    int userdir;
01896 
01897    ast_copy_string(tmp, username, sizeof(tmp));
01898    username = tmp;
01899    domain = strchr(tmp, '@');
01900    if (domain) {
01901       *domain = '\0';
01902       domain++;
01903    }
01904 
01905    if (!(vmu = find_account(domain, username, TRUE))) {
01906       /* We could not find user, let's exit */
01907       ast_log(LOG_ERROR, "Can't allocate temporary account for '%s@%s'\n", username, domain);
01908       pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
01909       return 0;
01910    }
01911 
01912    /* Setup pre-file if appropriate */
01913    if (strcmp(vmu->domain, "localhost"))
01914       snprintf(ext_context, sizeof(ext_context), "%s@%s", username, vmu->domain);
01915    else
01916       ast_copy_string(ext_context, vmu->domain, sizeof(ext_context));
01917 
01918    /* The meat of recording the message...  All the announcements and beeps have been played*/
01919    if (ast_strlen_zero(vmu->attachfmt))
01920       ast_copy_string(fmt, default_vmformat, sizeof(fmt));
01921    else
01922       ast_copy_string(fmt, vmu->attachfmt, sizeof(fmt));
01923 
01924    if (ast_strlen_zero(fmt)) {
01925       ast_log(LOG_WARNING, "No format for saving voicemail? Default %s\n", default_vmformat);
01926       pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
01927       return res;
01928    }
01929 
01930    userdir = check_dirpath(tmpdir, sizeof(tmpdir), vmu->domain, username, "tmp");
01931 
01932    /* If we have no user directory, use generic temporary directory */
01933    if (!userdir) {
01934       create_dirpath(tmpdir, sizeof(tmpdir), "0000_minivm_temp", "mediafiles", "");
01935       ast_debug(3, "Creating temporary directory %s\n", tmpdir);
01936    }
01937 
01938 
01939    snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
01940 
01941    /* XXX This file needs to be in temp directory */
01942    txtdes = mkstemp(tmptxtfile);
01943    if (txtdes < 0) {
01944       ast_log(LOG_ERROR, "Unable to create message file %s: %s\n", tmptxtfile, strerror(errno));
01945       res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
01946       if (!res)
01947          res = ast_waitstream(chan, "");
01948       pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
01949       return res;
01950    }
01951 
01952    if (res >= 0) {
01953       /* Unless we're *really* silent, try to send the beep */
01954       res = ast_streamfile(chan, "beep", ast_channel_language(chan));
01955       if (!res)
01956          res = ast_waitstream(chan, "");
01957    }
01958 
01959    /* OEJ XXX Maybe this can be turned into a log file? Hmm. */
01960    /* Store information */
01961    ast_debug(2, "Open file for metadata: %s\n", tmptxtfile);
01962 
01963    res = play_record_review(chan, NULL, tmptxtfile, global_vmmaxmessage, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain);
01964 
01965    txt = fdopen(txtdes, "w+");
01966    if (!txt) {
01967       ast_log(LOG_WARNING, "Error opening text file for output\n");
01968    } else {
01969       struct ast_tm tm;
01970       struct timeval now = ast_tvnow();
01971       char timebuf[30];
01972       char logbuf[BUFSIZ];
01973       get_date(date, sizeof(date));
01974       ast_localtime(&now, &tm, NULL);
01975       ast_strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm);
01976 
01977       ast_callerid_merge(callerid, sizeof(callerid),
01978          S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
01979          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
01980          "Unknown");
01981       snprintf(logbuf, sizeof(logbuf),
01982          /* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
01983          "%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
01984          username,
01985          ast_channel_context(chan),
01986          ast_channel_macrocontext(chan), 
01987          ast_channel_exten(chan),
01988          ast_channel_priority(chan),
01989          ast_channel_name(chan),
01990          callerid,
01991          date, 
01992          timebuf,
01993          duration,
01994          duration < global_vmminmessage ? "IGNORED" : "OK",
01995          vmu->accountcode
01996       ); 
01997       fprintf(txt, "%s", logbuf);
01998       if (minivmlogfile) {
01999          ast_mutex_lock(&minivmloglock);
02000          fprintf(minivmlogfile, "%s", logbuf);
02001          ast_mutex_unlock(&minivmloglock);
02002       }
02003 
02004       if (sound_duration < global_vmminmessage) {
02005          ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, global_vmminmessage);
02006          fclose(txt);
02007          ast_filedelete(tmptxtfile, NULL);
02008          unlink(tmptxtfile);
02009          pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
02010          return 0;
02011       } 
02012       fclose(txt); /* Close log file */
02013       if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
02014          ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
02015          unlink(tmptxtfile);
02016          pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
02017          if(ast_test_flag(vmu, MVM_ALLOCED))
02018             free_user(vmu);
02019          return 0;
02020       }
02021 
02022       /* Set channel variables for the notify application */
02023       pbx_builtin_setvar_helper(chan, "MVM_FILENAME", tmptxtfile);
02024       snprintf(timebuf, sizeof(timebuf), "%d", duration);
02025       pbx_builtin_setvar_helper(chan, "MVM_DURATION", timebuf);
02026       pbx_builtin_setvar_helper(chan, "MVM_FORMAT", fmt);
02027 
02028    }
02029    global_stats.lastreceived = ast_tvnow();
02030    global_stats.receivedmessages++;
02031 #if 0
02032    /* Go ahead and delete audio files from system, they're not needed any more */
02033    if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
02034       ast_filedelete(tmptxtfile, NULL);
02035        /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
02036       ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
02037    }
02038 #endif
02039 
02040    if (res > 0)
02041       res = 0;
02042 
02043    if(ast_test_flag(vmu, MVM_ALLOCED))
02044       free_user(vmu);
02045 
02046    pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "SUCCESS");
02047    return res;
02048 }

static int load_config ( int  reload  )  [static]

Load minivoicemail configuration.

Definition at line 2831 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_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, create_vmaccount(), default_vmformat, errno, error(), FALSE, global_externnotify, global_logfile, global_mailcmd, global_maxgreet, global_maxsilence, global_saydurationminfo, global_silencethreshold, global_stats, global_vmmaxmessage, global_vmminmessage, globalflags, LOG_ERROR, LOG_WARNING, message_destroy_list(), message_template_build(), message_template_find(), message_template_parse_emailbody(), minivmlock, minivmlogfile, MVM_OPERATOR, MVM_REVIEW, ast_variable::name, ast_variable::next, NULL, minivm_stats::reset, SENDMAIL, THRESHOLD_SILENCE, timezone_add(), timezone_destroy_list(), TRUE, ast_variable::value, var, vmaccounts_destroy_list(), and VOICEMAIL_CONFIG.

02832 {
02833    struct ast_config *cfg;
02834    struct ast_variable *var;
02835    char *cat;
02836    const char *chanvar;
02837    int error = 0;
02838    struct minivm_template *template;
02839    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02840 
02841    cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
02842    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
02843       return 0;
02844    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02845       ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
02846       return 0;
02847    }
02848 
02849    ast_mutex_lock(&minivmlock);
02850 
02851    /* Destroy lists to reconfigure */
02852    message_destroy_list();    /* Destroy list of voicemail message templates */
02853    timezone_destroy_list();   /* Destroy list of timezones */
02854    vmaccounts_destroy_list(); /* Destroy list of voicemail accounts */
02855    ast_debug(2, "Destroyed memory objects...\n");
02856 
02857    /* First, set some default settings */
02858    global_externnotify[0] = '\0';
02859    global_logfile[0] = '\0';
02860    global_vmmaxmessage = 2000;
02861    global_maxgreet = 2000;
02862    global_vmminmessage = 0;
02863    strcpy(global_mailcmd, SENDMAIL);
02864    global_maxsilence = 0;
02865    global_saydurationminfo = 2;
02866    ast_copy_string(default_vmformat, "wav", sizeof(default_vmformat));
02867    ast_set2_flag((&globalflags), FALSE, MVM_REVIEW);  
02868    ast_set2_flag((&globalflags), FALSE, MVM_OPERATOR);   
02869    /* Reset statistics */
02870    memset(&global_stats, 0, sizeof(global_stats));
02871    global_stats.reset = ast_tvnow();
02872 
02873    global_silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
02874 
02875    /* Make sure we could load configuration file */
02876    if (!cfg) {
02877       ast_log(LOG_WARNING, "Failed to load configuration file. Module activated with default settings.\n");
02878       ast_mutex_unlock(&minivmlock);
02879       return 0;
02880    }
02881 
02882    ast_debug(2, "Loaded configuration file, now parsing\n");
02883 
02884    /* General settings */
02885 
02886    cat = ast_category_browse(cfg, NULL);
02887    while (cat) {
02888       ast_debug(3, "Found configuration section [%s]\n", cat);
02889       if (!strcasecmp(cat, "general")) {
02890          /* Nothing right now */
02891          error += apply_general_options(ast_variable_browse(cfg, cat));
02892       } else if (!strncasecmp(cat, "template-", 9))  {
02893          /* Template */
02894          char *name = cat + 9;
02895 
02896          /* Now build and link template to list */
02897          error += message_template_build(name, ast_variable_browse(cfg, cat));
02898       } else {
02899          var = ast_variable_browse(cfg, cat);
02900          if (!strcasecmp(cat, "zonemessages")) {
02901             /* Timezones in this context */
02902             while (var) {
02903                timezone_add(var->name, var->value);
02904                var = var->next;
02905             }
02906          } else {
02907             /* Create mailbox from this */
02908             error += create_vmaccount(cat, var, FALSE);
02909          }
02910       }
02911       /* Find next section in configuration file */
02912       cat = ast_category_browse(cfg, cat);
02913    }
02914 
02915    /* Configure the default email template */
02916    message_template_build("email-default", NULL);
02917    template = message_template_find("email-default");
02918 
02919    /* Load date format config for voicemail mail */
02920    if ((chanvar = ast_variable_retrieve(cfg, "general", "emaildateformat"))) 
02921       ast_copy_string(template->dateformat, chanvar, sizeof(template->dateformat));
02922    if ((chanvar = ast_variable_retrieve(cfg, "general", "emailfromstring")))
02923       ast_copy_string(template->fromaddress, chanvar, sizeof(template->fromaddress));
02924    if ((chanvar = ast_variable_retrieve(cfg, "general", "emailaaddress")))
02925       ast_copy_string(template->serveremail, chanvar, sizeof(template->serveremail));
02926    if ((chanvar = ast_variable_retrieve(cfg, "general", "emailcharset")))
02927       ast_copy_string(template->charset, chanvar, sizeof(template->charset));
02928    if ((chanvar = ast_variable_retrieve(cfg, "general", "emailsubject"))) 
02929       ast_copy_string(template->subject, chanvar, sizeof(template->subject));
02930    if ((chanvar = ast_variable_retrieve(cfg, "general", "emailbody"))) 
02931       template->body = message_template_parse_emailbody(chanvar);
02932    template->attachment = TRUE;
02933 
02934    message_template_build("pager-default", NULL);
02935    template = message_template_find("pager-default");
02936    if ((chanvar = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
02937       ast_copy_string(template->fromaddress, chanvar, sizeof(template->fromaddress));
02938    if ((chanvar = ast_variable_retrieve(cfg, "general", "pageraddress")))
02939       ast_copy_string(template->serveremail, chanvar, sizeof(template->serveremail));
02940    if ((chanvar = ast_variable_retrieve(cfg, "general", "pagercharset")))
02941       ast_copy_string(template->charset, chanvar, sizeof(template->charset));
02942    if ((chanvar = ast_variable_retrieve(cfg, "general", "pagersubject")))
02943       ast_copy_string(template->subject, chanvar,sizeof(template->subject));
02944    if ((chanvar = ast_variable_retrieve(cfg, "general", "pagerbody"))) 
02945       template->body = message_template_parse_emailbody(chanvar);
02946    template->attachment = FALSE;
02947 
02948    if (error)
02949       ast_log(LOG_ERROR, "--- A total of %d errors found in mini-voicemail configuration\n", error);
02950 
02951    ast_mutex_unlock(&minivmlock);
02952    ast_config_destroy(cfg);
02953 
02954    /* Close log file if it's open and disabled */
02955    if(minivmlogfile)
02956       fclose(minivmlogfile);
02957 
02958    /* Open log file if it's enabled */
02959    if(!ast_strlen_zero(global_logfile)) {
02960       minivmlogfile = fopen(global_logfile, "a");
02961       if(!minivmlogfile)
02962          ast_log(LOG_ERROR, "Failed to open minivm log file %s : %s\n", global_logfile, strerror(errno));
02963       if (minivmlogfile)
02964          ast_debug(3, "Opened log file %s \n", global_logfile);
02965    }
02966 
02967    return 0;
02968 }

static int load_module ( void   )  [static]

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

Definition at line 1506 of file app_minivm.c.

References ast_strlen_zero.

Referenced by check_dirpath(), copy_message(), create_dirpath(), make_email_file(), manager_list_voicemail_users(), notify_new_message(), and prep_email_sub_vars().

01507 {
01508    return snprintf(dest, len, "%s%s/%s%s%s", MVM_SPOOL_DIR, domain, username, ast_strlen_zero(folder) ? "" : "/", folder ? folder : "");
01509 }

static void message_destroy_list ( void   )  [static]

Definition at line 839 of file app_minivm.c.

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

Referenced by load_config(), and unload_module().

00840 {
00841    struct minivm_template *this;
00842    AST_LIST_LOCK(&message_templates);
00843    while ((this = AST_LIST_REMOVE_HEAD(&message_templates, list))) {
00844       message_template_free(this);
00845    }
00846 
00847    AST_LIST_UNLOCK(&message_templates);
00848 }

static int message_template_build ( const char *  name,
struct ast_variable var 
) [static]

Definition at line 754 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(), error(), 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().

00755 {
00756    struct minivm_template *template;
00757    int error = 0;
00758 
00759    template = message_template_create(name);
00760    if (!template) {
00761       ast_log(LOG_ERROR, "Out of memory, can't allocate message template object %s.\n", name);
00762       return -1;
00763    }
00764 
00765    while (var) {
00766       ast_debug(3, "Configuring template option %s = \"%s\" for template %s\n", var->name, var->value, name);
00767       if (!strcasecmp(var->name, "fromaddress")) {
00768          ast_copy_string(template->fromaddress, var->value, sizeof(template->fromaddress));
00769       } else if (!strcasecmp(var->name, "fromemail")) {
00770          ast_copy_string(template->serveremail, var->value, sizeof(template->serveremail));
00771       } else if (!strcasecmp(var->name, "subject")) {
00772          ast_copy_string(template->subject, var->value, sizeof(template->subject));
00773       } else if (!strcasecmp(var->name, "locale")) {
00774          ast_copy_string(template->locale, var->value, sizeof(template->locale));
00775       } else if (!strcasecmp(var->name, "attachmedia")) {
00776          template->attachment = ast_true(var->value);
00777       } else if (!strcasecmp(var->name, "dateformat")) {
00778          ast_copy_string(template->dateformat, var->value, sizeof(template->dateformat));
00779       } else if (!strcasecmp(var->name, "charset")) {
00780          ast_copy_string(template->charset, var->value, sizeof(template->charset));
00781       } else if (!strcasecmp(var->name, "templatefile")) {
00782          if (template->body) 
00783             ast_free(template->body);
00784          template->body = message_template_parse_filebody(var->value);
00785          if (!template->body) {
00786             ast_log(LOG_ERROR, "Error reading message body definition file %s\n", var->value);
00787             error++;
00788          }
00789       } else if (!strcasecmp(var->name, "messagebody")) {
00790          if (template->body) 
00791             ast_free(template->body);
00792          template->body = message_template_parse_emailbody(var->value);
00793          if (!template->body) {
00794             ast_log(LOG_ERROR, "Error parsing message body definition:\n          %s\n", var->value);
00795             error++;
00796          }
00797       } else {
00798          ast_log(LOG_ERROR, "Unknown message template configuration option \"%s=%s\"\n", var->name, var->value);
00799          error++;
00800       }
00801       var = var->next;
00802    }
00803    if (error)
00804       ast_log(LOG_ERROR, "-- %d errors found parsing message template definition %s\n", error, name);
00805 
00806    AST_LIST_LOCK(&message_templates);
00807    AST_LIST_INSERT_TAIL(&message_templates, template, list);
00808    AST_LIST_UNLOCK(&message_templates);
00809 
00810    global_stats.templates++;
00811 
00812    return error;
00813 }

static struct minivm_template* message_template_create ( const char *  name  )  [static, read]

Definition at line 724 of file app_minivm.c.

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

Referenced by message_template_build().

00725 {
00726    struct minivm_template *template;
00727 
00728    template = ast_calloc(1, sizeof(*template));
00729    if (!template)
00730       return NULL;
00731 
00732    /* Set some defaults for templates */
00733    ast_copy_string(template->name, name, sizeof(template->name));
00734    ast_copy_string(template->dateformat, DEFAULT_DATEFORMAT, sizeof(template->dateformat));
00735    ast_copy_string(template->charset, DEFAULT_CHARSET, sizeof(template->charset));
00736    ast_copy_string(template->subject, "New message in mailbox ${MVM_USERNAME}@${MVM_DOMAIN}", sizeof(template->subject));
00737    template->attachment = TRUE;
00738 
00739    return template;
00740 }

static struct minivm_template* message_template_find ( const char *  name  )  [static, read]

Definition at line 817 of file app_minivm.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero, and NULL.

Referenced by load_config(), and notify_new_message().

00818 {
00819    struct minivm_template *this, *res = NULL;
00820 
00821    if (ast_strlen_zero(name))
00822       return NULL;
00823 
00824    AST_LIST_LOCK(&message_templates);
00825    AST_LIST_TRAVERSE(&message_templates, this, list) {
00826       if (!strcasecmp(this->name, name)) {
00827          res = this;
00828          break;
00829       }
00830    }
00831    AST_LIST_UNLOCK(&message_templates);
00832 
00833    return res;
00834 }

static void message_template_free ( struct minivm_template template  )  [static]

Definition at line 744 of file app_minivm.c.

References ast_free.

Referenced by message_destroy_list().

00745 {
00746    if (template->body)
00747       ast_free(template->body);
00748 
00749    ast_free (template);
00750 }

static char * message_template_parse_emailbody ( const char *  body  )  [static]

Parse emailbody template from configuration file.

Definition at line 2746 of file app_minivm.c.

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

Referenced by load_config(), and message_template_build().

02747 {
02748    char *tmpread, *tmpwrite;
02749    char *emailbody = ast_strdup(configuration);
02750 
02751    /* substitute strings \t and \n into the apropriate characters */
02752    tmpread = tmpwrite = emailbody;
02753    while ((tmpwrite = strchr(tmpread,'\\'))) {
02754           int len = strlen("\n");
02755           switch (tmpwrite[1]) {
02756           case 'n':
02757             memmove(tmpwrite + len, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
02758             strncpy(tmpwrite, "\n", len);
02759             break;
02760           case 't':
02761             memmove(tmpwrite + len, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
02762             strncpy(tmpwrite, "\t", len);
02763             break;
02764           default:
02765             ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
02766           }
02767           tmpread = tmpwrite + len;
02768    }
02769    return emailbody; 
02770 }

static char * message_template_parse_filebody ( const char *  filename  )  [static]

Read message template from file.

Definition at line 2706 of file app_minivm.c.

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

Referenced by message_template_build().

02706                                                                    {
02707    char buf[BUFSIZ * 6];
02708    char readbuf[BUFSIZ];
02709    char filenamebuf[BUFSIZ];
02710    char *writepos;
02711    char *messagebody;
02712    FILE *fi;
02713    int lines = 0;
02714 
02715    if (ast_strlen_zero(filename))
02716       return NULL;
02717    if (*filename == '/') 
02718       ast_copy_string(filenamebuf, filename, sizeof(filenamebuf));
02719    else 
02720       snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
02721 
02722    if (!(fi = fopen(filenamebuf, "r"))) {
02723       ast_log(LOG_ERROR, "Can't read message template from file: %s\n", filenamebuf);
02724       return NULL;
02725    }
02726    writepos = buf;
02727    while (fgets(readbuf, sizeof(readbuf), fi)) {
02728       lines ++;
02729       if (writepos != buf) {
02730          *writepos = '\n';    /* Replace EOL with new line */
02731          writepos++;
02732       }
02733       ast_copy_string(writepos, readbuf, sizeof(buf) - (writepos - buf));
02734       writepos += strlen(readbuf) - 1;
02735    }
02736    fclose(fi);
02737    messagebody = ast_calloc(1, strlen(buf + 1));
02738    ast_copy_string(messagebody, buf, strlen(buf) + 1);
02739    ast_debug(4, "---> Size of allocation %d\n", (int) strlen(buf + 1) );
02740    ast_debug(4, "---> Done reading message template : \n%s\n---- END message template--- \n", messagebody);
02741 
02742    return messagebody;
02743 }

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

Record specific messages for voicemail account.

Definition at line 2464 of file app_minivm.c.

References 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, error(), FALSE, find_account(), minivm_account::flags, free_user(), global_maxgreet, LOG_ERROR, LOG_WARNING, minivm_accmess_options, MVM_ALLOCED, NULL, OPT_ARG_ARRAY_SIZE, OPT_BUSY_GREETING, OPT_NAME_GREETING, OPT_TEMP_GREETING, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), play_record_review(), prompt, tmp(), TRUE, and minivm_account::username.

Referenced by load_module().

02465 {
02466    int argc = 0;
02467    char *argv[2];
02468    char filename[PATH_MAX];
02469    char tmp[PATH_MAX];
02470    char *domain;
02471    char *tmpptr = NULL;
02472    struct minivm_account *vmu;
02473    char *username;
02474    struct ast_flags flags = { 0 };
02475    char *opts[OPT_ARG_ARRAY_SIZE];
02476    int error = FALSE;
02477    char *message = NULL;
02478    char *prompt = NULL;
02479    int duration;
02480 
02481    if (ast_strlen_zero(data))  {
02482       ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
02483       error = TRUE;
02484    } else {
02485       tmpptr = ast_strdupa((char *)data);
02486       argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
02487    }
02488 
02489    if (argc <=1) {
02490       ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
02491       error = TRUE;
02492    }
02493    if (!error && strlen(argv[1]) > 1) {
02494       ast_log(LOG_ERROR, "MinivmAccmess can only handle one option at a time. Bad option string: %s\n", argv[1]);
02495       error = TRUE;
02496    }
02497 
02498    if (!error && ast_app_parse_options(minivm_accmess_options, &flags, opts, argv[1])) {
02499       ast_log(LOG_ERROR, "Can't parse option %s\n", argv[1]);
02500       error = TRUE;
02501    }
02502 
02503    if (error) {
02504       pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
02505       return -1;
02506    }
02507 
02508    ast_copy_string(tmp, argv[0], sizeof(tmp));
02509    username = tmp;
02510    domain = strchr(tmp, '@');
02511    if (domain) {
02512       *domain = '\0';
02513       domain++;
02514    } 
02515    if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
02516       ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument 0 %s\n", argv[0]);
02517       pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
02518       return -1;
02519    }
02520 
02521    if(!(vmu = find_account(domain, username, TRUE))) {
02522       /* We could not find user, let's exit */
02523       ast_log(LOG_WARNING, "Could not allocate temporary memory for '%s@%s'\n", username, domain);
02524       pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "FAILED");
02525       return -1;
02526    }
02527 
02528    /* Answer channel if it's not already answered */
02529    if (ast_channel_state(chan) != AST_STATE_UP)
02530       ast_answer(chan);
02531    
02532    /* Here's where the action is */
02533    if (ast_test_flag(&flags, OPT_BUSY_GREETING)) {
02534       message = "busy";
02535       prompt = "vm-rec-busy";
02536    } else if (ast_test_flag(&flags, OPT_UNAVAIL_GREETING)) {
02537       message = "unavailable";
02538       prompt = "vm-rec-unv";
02539    } else if (ast_test_flag(&flags, OPT_TEMP_GREETING)) {
02540       message = "temp";
02541       prompt = "vm-rec-temp";
02542    } else if (ast_test_flag(&flags, OPT_NAME_GREETING)) {
02543       message = "greet";
02544       prompt = "vm-rec-name";
02545    }
02546    snprintf(filename,sizeof(filename), "%s%s/%s/%s", MVM_SPOOL_DIR, vmu->domain, vmu->username, message);
02547    /* Maybe we should check the result of play_record_review ? */
02548    play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, NULL, FALSE);
02549 
02550    ast_debug(1, "Recorded new %s message in %s (duration %d)\n", message, filename, duration);
02551 
02552    if(ast_test_flag(vmu, MVM_ALLOCED))
02553       free_user(vmu);
02554 
02555    pbx_builtin_setvar_helper(chan, "MVM_ACCMESS_STATUS", "SUCCESS");
02556 
02557    /* Ok, we're ready to rock and roll. Return to dialplan */
02558    return 0;
02559 }

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 3194 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, NULL, minivm_account::pager, minivm_account::pincode, minivm_account::ptemplate, TRUE, minivm_account::username, ast_variable::value, var, and minivm_account::zonetag.

03195 {
03196    struct minivm_account *vmu;
03197    char *username, *domain, *colname;
03198 
03199    username = ast_strdupa(data);
03200 
03201    if ((colname = strchr(username, ':'))) {
03202       *colname = '\0';
03203       colname++;
03204    } else {
03205       colname = "path";
03206    }
03207    if ((domain = strchr(username, '@'))) {
03208       *domain = '\0';
03209       domain++;
03210    }
03211    if (ast_strlen_zero(username) || ast_strlen_zero(domain)) {
03212       ast_log(LOG_ERROR, "This function needs a username and a domain: username@domain\n");
03213       return 0;
03214    }
03215 
03216    if (!(vmu = find_account(domain, username, TRUE)))
03217       return 0;
03218 
03219    if (!strcasecmp(colname, "hasaccount")) {
03220       ast_copy_string(buf, (ast_test_flag(vmu, MVM_ALLOCED) ? "0" : "1"), len);
03221    } else  if (!strcasecmp(colname, "fullname")) { 
03222       ast_copy_string(buf, vmu->fullname, len);
03223    } else  if (!strcasecmp(colname, "email")) { 
03224       if (!ast_strlen_zero(vmu->email))
03225          ast_copy_string(buf, vmu->email, len);
03226       else
03227          snprintf(buf, len, "%s@%s", vmu->username, vmu->domain);
03228    } else  if (!strcasecmp(colname, "pager")) { 
03229       ast_copy_string(buf, vmu->pager, len);
03230    } else  if (!strcasecmp(colname, "etemplate")) { 
03231       if (!ast_strlen_zero(vmu->etemplate))
03232          ast_copy_string(buf, vmu->etemplate, len);
03233       else
03234          ast_copy_string(buf, "email-default", len);
03235    } else  if (!strcasecmp(colname, "language")) { 
03236       ast_copy_string(buf, vmu->language, len);
03237    } else  if (!strcasecmp(colname, "timezone")) { 
03238       ast_copy_string(buf, vmu->zonetag, len);
03239    } else  if (!strcasecmp(colname, "ptemplate")) { 
03240       if (!ast_strlen_zero(vmu->ptemplate))
03241          ast_copy_string(buf, vmu->ptemplate, len);
03242       else
03243          ast_copy_string(buf, "email-default", len);
03244    } else  if (!strcasecmp(colname, "accountcode")) {
03245       ast_copy_string(buf, vmu->accountcode, len);
03246    } else  if (!strcasecmp(colname, "pincode")) {
03247       ast_copy_string(buf, vmu->pincode, len);
03248    } else  if (!strcasecmp(colname, "path")) {
03249       check_dirpath(buf, len, vmu->domain, vmu->username, NULL);
03250    } else { /* Look in channel variables */
03251       struct ast_variable *var;
03252 
03253       for (var = vmu->chanvars ; var ; var = var->next)
03254          if (!strcmp(var->name, colname)) {
03255             ast_copy_string(buf, var->value, len);
03256             break;
03257          }
03258    }
03259 
03260    if(ast_test_flag(vmu, MVM_ALLOCED))
03261       free_user(vmu);
03262 
03263    return 0;
03264 }

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

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

03342 {
03343    char *username, *domain, *countername;
03344    char userpath[BUFSIZ];
03345    int res;
03346 
03347    *buf = '\0';
03348 
03349    username = ast_strdupa(data);
03350 
03351    if ((countername = strchr(username, ':'))) {
03352       *countername = '\0';
03353       countername++;
03354    } 
03355 
03356    if ((domain = strchr(username, '@'))) {
03357       *domain = '\0';
03358       domain++;
03359    }
03360 
03361    /* If we have neither username nor domain now, let's give up */
03362    if (ast_strlen_zero(username) && ast_strlen_zero(domain)) {
03363       ast_log(LOG_ERROR, "No account given\n");
03364       return -1;
03365    }
03366 
03367    if (ast_strlen_zero(countername)) {
03368       ast_log(LOG_ERROR, "This function needs two arguments: Account:countername\n");
03369       return -1;
03370    }
03371 
03372    /* We only have a domain, no username */
03373    if (!ast_strlen_zero(username) && ast_strlen_zero(domain)) {
03374       domain = username;
03375       username = NULL;
03376    }
03377 
03378    /* If we can't find account or if the account is temporary, return. */
03379    if (!ast_strlen_zero(username) && !find_account(domain, username, FALSE)) {
03380       ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
03381       return 0;
03382    }
03383 
03384    create_dirpath(userpath, sizeof(userpath), domain, username, NULL);
03385 
03386    /* We have the path, now read the counter file */
03387    res = access_counter_file(userpath, countername, 0, 0);
03388    if (res >= 0)
03389       snprintf(buf, len, "%d", res);
03390    return 0;
03391 }

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

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

03395 {
03396    char *username, *domain, *countername, *operand;
03397    char userpath[BUFSIZ];
03398    int change = 0;
03399    int operation = 0;
03400 
03401    if(!value)
03402       return -1;
03403    change = atoi(value);
03404 
03405    username = ast_strdupa(data);
03406 
03407    if ((countername = strchr(username, ':'))) {
03408       *countername = '\0';
03409       countername++;
03410    } 
03411    if ((operand = strchr(countername, ':'))) {
03412       *operand = '\0';
03413       operand++;
03414    } 
03415 
03416    if ((domain = strchr(username, '@'))) {
03417       *domain = '\0';
03418       domain++;
03419    }
03420 
03421    /* If we have neither username nor domain now, let's give up */
03422    if (ast_strlen_zero(username) && ast_strlen_zero(domain)) {
03423       ast_log(LOG_ERROR, "No account given\n");
03424       return -1;
03425    }
03426 
03427    /* We only have a domain, no username */
03428    if (!ast_strlen_zero(username) && ast_strlen_zero(domain)) {
03429       domain = username;
03430       username = NULL;
03431    }
03432 
03433    if (ast_strlen_zero(operand) || ast_strlen_zero(countername)) {
03434       ast_log(LOG_ERROR, "Writing to this function requires three arguments: Account:countername:operand\n");
03435       return -1;
03436    }
03437 
03438    /* If we can't find account or if the account is temporary, return. */
03439    if (!ast_strlen_zero(username) && !find_account(domain, username, FALSE)) {
03440       ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
03441       return 0;
03442    }
03443 
03444    create_dirpath(userpath, sizeof(userpath), domain, username, NULL);
03445    /* Now, find out our operator */
03446    if (*operand == 'i') /* Increment */
03447       operation = 2;
03448    else if (*operand == 'd') {
03449       change = change * -1;
03450       operation = 2;
03451    } else if (*operand == 's')
03452       operation = 1;
03453    else {
03454       ast_log(LOG_ERROR, "Unknown operator: %s\n", operand);
03455       return -1;
03456    }
03457 
03458    /* We have the path, now read the counter file */
03459    access_counter_file(userpath, countername, change, operation);
03460    return 0;
03461 }

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

Definition at line 2426 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, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), and vm_delete().

Referenced by load_module().

02427 {
02428    int res = 0;
02429    char filename[BUFSIZ];
02430 
02431    if (!ast_strlen_zero(data)) {
02432       ast_copy_string(filename, (char *) data, sizeof(filename));
02433    } else {
02434       ast_channel_lock(chan);
02435       ast_copy_string(filename, pbx_builtin_getvar_helper(chan, "MVM_FILENAME"), sizeof(filename));
02436       ast_channel_unlock(chan);
02437    }
02438 
02439    if (ast_strlen_zero(filename)) {
02440       ast_log(LOG_ERROR, "No filename given in application arguments or channel variable MVM_FILENAME\n");
02441       return res;
02442    } 
02443 
02444    /* Go ahead and delete audio files from system, they're not needed any more */
02445    /* We should look for both audio and text files here */
02446    if (ast_fileexists(filename, NULL, NULL) > 0) {
02447       res = vm_delete(filename);
02448       if (res) {
02449          ast_debug(2, "Can't delete file: %s\n", filename);
02450          pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "FAILED");
02451       } else {
02452          ast_debug(2, "Deleted voicemail file :: %s \n", filename);
02453          pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "SUCCESS");
02454       }
02455    } else {
02456       ast_debug(2, "Filename does not exist: %s\n", filename);
02457       pbx_builtin_setvar_helper(chan, "MVM_DELETE_STATUS", "FAILED");
02458    }
02459 
02460    return res;
02461 }

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

Definition at line 2236 of file app_minivm.c.

References ARRAY_LEN, ast_answer(), ast_app_parse_options(), ast_app_separate_args, ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_language(), ast_channel_macrocontext(), ast_channel_priority_set(), 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(), minivm_account::domain, minivm_account::exit, find_account(), minivm_account::flags, free_user(), invent_message(), LOG_ERROR, minivm_app_options, MVM_ALLOCED, MVM_OPERATOR, NULL, OPT_ARG_ARRAY_SIZE, OPT_BUSY_GREETING, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), S_COR, SOUND_INTRO, tmp(), TRUE, and minivm_account::username.

Referenced by load_module().

02237 {
02238    struct leave_vm_options leave_options = { 0, '\0'};
02239    int argc;
02240    char *argv[2];
02241    struct ast_flags flags = { 0 };
02242    char *opts[OPT_ARG_ARRAY_SIZE];
02243    int res = 0;
02244    int ausemacro = 0;
02245    int ousemacro = 0;
02246    int ouseexten = 0;
02247    char tmp[PATH_MAX];
02248    char dest[PATH_MAX];
02249    char prefile[PATH_MAX] = "";
02250    char tempfile[PATH_MAX] = "";
02251    char ext_context[256] = "";
02252    char *domain;
02253    char ecodes[16] = "#";
02254    char *tmpptr;
02255    struct minivm_account *vmu;
02256    char *username = argv[0];
02257 
02258    if (ast_strlen_zero(data))  {
02259       ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
02260       return -1;
02261    }
02262    tmpptr = ast_strdupa((char *)data);
02263    argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
02264 
02265    if (argc == 2) {
02266       if (ast_app_parse_options(minivm_app_options, &flags, opts, argv[1]))
02267          return -1;
02268       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING );
02269    }
02270 
02271    ast_copy_string(tmp, argv[0], sizeof(tmp));
02272    username = tmp;
02273    domain = strchr(tmp, '@');
02274    if (domain) {
02275       *domain = '\0';
02276       domain++;
02277    } 
02278    if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
02279       ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument:  %s\n", argv[0]);
02280       return -1;
02281    }
02282    ast_debug(1, "Trying to find configuration for user %s in domain %s\n", username, domain);
02283 
02284    if (!(vmu = find_account(domain, username, TRUE))) {
02285       ast_log(LOG_ERROR, "Could not allocate memory. \n");
02286       return -1;
02287    }
02288 
02289    /* Answer channel if it's not already answered */
02290    if (ast_channel_state(chan) != AST_STATE_UP)
02291       ast_answer(chan);
02292 
02293    /* Setup pre-file if appropriate */
02294    if (strcmp(vmu->domain, "localhost"))
02295       snprintf(ext_context, sizeof(ext_context), "%s@%s", username, vmu->domain);
02296    else
02297       ast_copy_string(ext_context, vmu->domain, sizeof(ext_context));
02298 
02299    if (ast_test_flag(&leave_options, OPT_BUSY_GREETING)) {
02300       res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "busy");
02301       if (res)
02302          snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", MVM_SPOOL_DIR, vmu->domain, username);
02303    } else if (ast_test_flag(&leave_options, OPT_UNAVAIL_GREETING)) {
02304       res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "unavail");
02305       if (res)
02306          snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", MVM_SPOOL_DIR, vmu->domain, username);
02307    }
02308    /* Check for temporary greeting - it overrides busy and unavail */
02309    snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", MVM_SPOOL_DIR, vmu->domain, username);
02310    if (!(res = check_dirpath(dest, sizeof(dest), vmu->domain, username, "temp"))) {
02311       ast_debug(2, "Temporary message directory does not exist, using default (%s)\n", tempfile);
02312       ast_copy_string(prefile, tempfile, sizeof(prefile));
02313    }
02314    ast_debug(2, "Preparing to play message ...\n");
02315 
02316    /* Check current or macro-calling context for special extensions */
02317    if (ast_test_flag(vmu, MVM_OPERATOR)) {
02318       if (!ast_strlen_zero(vmu->exit)) {
02319          if (ast_exists_extension(chan, vmu->exit, "o", 1,
02320             S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02321             strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02322             ouseexten = 1;
02323          }
02324       } else if (ast_exists_extension(chan, ast_channel_context(chan), "o", 1,
02325          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02326          strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02327          ouseexten = 1;
02328       }
02329       else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
02330          && ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
02331             S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02332          strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02333          ousemacro = 1;
02334       }
02335    }
02336 
02337    if (!ast_strlen_zero(vmu->exit)) {
02338       if (ast_exists_extension(chan, vmu->exit, "a", 1,
02339          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02340          strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
02341       }
02342    } else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
02343       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02344       strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
02345    } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
02346       && ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
02347          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
02348       strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
02349       ausemacro = 1;
02350    }
02351 
02352    res = 0; /* Reset */
02353    /* Play the beginning intro if desired */
02354    if (!ast_strlen_zero(prefile)) {
02355       if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1) 
02356          res = ast_waitstream(chan, ecodes);
02357    } else {
02358       ast_debug(2, "%s doesn't exist, doing what we can\n", prefile);
02359       res = invent_message(chan, vmu->domain, username, ast_test_flag(&leave_options, OPT_BUSY_GREETING), ecodes);
02360    }
02361    if (res < 0) {
02362       ast_debug(2, "Hang up during prefile playback\n");
02363       pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "FAILED");
02364       if(ast_test_flag(vmu, MVM_ALLOCED))
02365          free_user(vmu);
02366       return -1;
02367    }
02368    if (res == '#') {
02369       /* On a '#' we skip the instructions */
02370       ast_set_flag(&leave_options, OPT_SILENT);
02371       res = 0;
02372    }
02373    if (!res && !ast_test_flag(&leave_options, OPT_SILENT)) {
02374       res = ast_streamfile(chan, SOUND_INTRO, ast_channel_language(chan));
02375       if (!res)
02376          res = ast_waitstream(chan, ecodes);
02377       if (res == '#') {
02378          ast_set_flag(&leave_options, OPT_SILENT);
02379          res = 0;
02380       }
02381    }
02382    if (res > 0)
02383       ast_stopstream(chan);
02384    /* Check for a '*' here in case the caller wants to escape from voicemail to something
02385       other than the operator -- an automated attendant or mailbox login for example */
02386    if (res == '*') {
02387       ast_channel_exten_set(chan, "a");
02388       if (!ast_strlen_zero(vmu->exit)) {
02389          ast_channel_context_set(chan, vmu->exit);
02390       } else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
02391          ast_channel_context_set(chan, ast_channel_macrocontext(chan));
02392       }
02393       ast_channel_priority_set(chan, 0);
02394       pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
02395       res = 0;
02396    } else if (res == '0') { /* Check for a '0' here */
02397       if(ouseexten || ousemacro) {
02398          ast_channel_exten_set(chan, "o");
02399          if (!ast_strlen_zero(vmu->exit)) {
02400             ast_channel_context_set(chan, vmu->exit);
02401          } else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
02402             ast_channel_context_set(chan, ast_channel_macrocontext(chan));
02403          }
02404          ast_play_and_wait(chan, "transfer");
02405          ast_channel_priority_set(chan, 0);
02406          pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
02407       }
02408       res =  0;
02409    } else if (res < 0) {
02410       pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "FAILED");
02411       res = -1;
02412    } else
02413       pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "SUCCESS");
02414 
02415    if(ast_test_flag(vmu, MVM_ALLOCED))
02416       free_user(vmu);
02417 
02418 
02419    /* Ok, we're ready to rock and roll. Return to dialplan */
02420    return res;
02421 
02422 }

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

Definition at line 2067 of file app_minivm.c.

References ARRAY_LEN, ast_app_separate_args, ast_channel_uniqueid(), ast_copy_string(), ast_log, ast_strdupa, ast_strlen_zero, LOG_ERROR, mailbox, queue_mwi_event(), and tmp().

Referenced by load_module().

02068 {
02069    int argc;
02070    char *argv[4];
02071    int res = 0;
02072    char *tmpptr;
02073    char tmp[PATH_MAX];
02074    char *mailbox;
02075    char *domain;
02076    if (ast_strlen_zero(data))  {
02077       ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
02078       return -1;
02079    }
02080    tmpptr = ast_strdupa((char *)data);
02081    argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
02082    if (argc < 4) {
02083       ast_log(LOG_ERROR, "%d arguments passed to MiniVM_MWI, need 4.\n", argc);
02084       return -1;
02085    }
02086    ast_copy_string(tmp, argv[0], sizeof(tmp));
02087    mailbox = tmp;
02088    domain = strchr(tmp, '@');
02089    if (domain) {
02090       *domain = '\0';
02091       domain++;
02092    }
02093    if (ast_strlen_zero(domain) || ast_strlen_zero(mailbox)) {
02094       ast_log(LOG_ERROR, "Need mailbox@context as argument. Sorry. Argument 0 %s\n", argv[0]);
02095       return -1;
02096    }
02097    queue_mwi_event(ast_channel_uniqueid(chan), mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
02098 
02099    return res;
02100 }

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

Definition at line 2105 of file app_minivm.c.

References ARRAY_LEN, ast_app_separate_args, ast_channel_caller(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log, ast_strdupa, ast_strlen_zero, ast_test_flag, find_account(), format, free_user(), LOG_ERROR, LOG_WARNING, MVM_ALLOCED, notify_new_message(), NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, tmp(), TRUE, and minivm_account::username.

Referenced by load_module().

02106 {
02107    int argc;
02108    char *argv[2];
02109    int res = 0;
02110    char tmp[PATH_MAX];
02111    char *domain;
02112    char *tmpptr;
02113    struct minivm_account *vmu;
02114    char *username;
02115    const char *template = "";
02116    const char *filename;
02117    const char *format;
02118    const char *duration_string;
02119    if (ast_strlen_zero(data))  {
02120       ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
02121       return -1;
02122    }
02123    tmpptr = ast_strdupa((char *)data);
02124    argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
02125 
02126    if (argc == 2 && !ast_strlen_zero(argv[1]))
02127       template = argv[1];
02128 
02129    ast_copy_string(tmp, argv[0], sizeof(tmp));
02130    username = tmp;
02131    domain = strchr(tmp, '@');
02132    if (domain) {
02133       *domain = '\0';
02134       domain++;
02135    } 
02136    if (ast_strlen_zero(domain) || ast_strlen_zero(username)) {
02137       ast_log(LOG_ERROR, "Need username@domain as argument. Sorry. Argument 0 %s\n", argv[0]);
02138       return -1;
02139    }
02140 
02141    if(!(vmu = find_account(domain, username, TRUE))) {
02142       /* We could not find user, let's exit */
02143       ast_log(LOG_WARNING, "Could not allocate temporary memory for '%s@%s'\n", username, domain);
02144       pbx_builtin_setvar_helper(chan, "MVM_NOTIFY_STATUS", "FAILED");
02145       return -1;
02146    }
02147 
02148    ast_channel_lock(chan);
02149    if ((filename = pbx_builtin_getvar_helper(chan, "MVM_FILENAME"))) {
02150       filename = ast_strdupa(filename);
02151    }
02152    ast_channel_unlock(chan);
02153    /* Notify of new message to e-mail and pager */
02154    if (!ast_strlen_zero(filename)) {
02155       ast_channel_lock(chan); 
02156       if ((format = pbx_builtin_getvar_helper(chan, "MVM_FORMAT"))) {
02157          format = ast_strdupa(format);
02158       }
02159       if ((duration_string = pbx_builtin_getvar_helper(chan, "MVM_DURATION"))) {
02160          duration_string = ast_strdupa(duration_string);
02161       }
02162       ast_channel_unlock(chan);
02163       res = notify_new_message(chan, template, vmu, filename, atoi(duration_string),
02164          format,
02165          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
02166          S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL));
02167    }
02168 
02169    pbx_builtin_setvar_helper(chan, "MVM_NOTIFY_STATUS", res == 0 ? "SUCCESS" : "FAILED");
02170 
02171 
02172    if(ast_test_flag(vmu, MVM_ALLOCED))
02173       free_user(vmu);
02174 
02175    /* Ok, we're ready to rock and roll. Return to dialplan */
02176 
02177    return res;
02178 
02179 }

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

Definition at line 2183 of file app_minivm.c.

References 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(), leave_vm_options::record_gain, and tmp().

Referenced by load_module().

02184 {
02185    int res = 0;
02186    char *tmp;
02187    struct leave_vm_options leave_options;
02188    int argc;
02189    char *argv[2];
02190    struct ast_flags flags = { 0 };
02191    char *opts[OPT_ARG_ARRAY_SIZE];
02192 
02193    memset(&leave_options, 0, sizeof(leave_options));
02194 
02195    /* Answer channel if it's not already answered */
02196    if (ast_channel_state(chan) != AST_STATE_UP)
02197       ast_answer(chan);
02198 
02199    if (ast_strlen_zero(data))  {
02200       ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
02201       return -1;
02202    }
02203    tmp = ast_strdupa((char *)data);
02204    argc = ast_app_separate_args(tmp, ',', argv, ARRAY_LEN(argv));
02205    if (argc == 2) {
02206       if (ast_app_parse_options(minivm_app_options, &flags, opts, argv[1])) {
02207          return -1;
02208       }
02209       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING );
02210       if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
02211          int gain;
02212 
02213          if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
02214             ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
02215             return -1;
02216          } else 
02217             leave_options.record_gain = (signed char) gain;
02218       }
02219    } 
02220 
02221    /* Now run the appliation and good luck to you! */
02222    res = leave_voicemail(chan, argv[0], &leave_options);
02223 
02224    if (res == ERROR_LOCK_PATH) {
02225       ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
02226       pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
02227       res = 0;
02228    }
02229    pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "SUCCESS");
02230 
02231    return res;
02232 }

static struct minivm_account* mvm_user_alloc ( void   )  [static, read]

Definition at line 1041 of file app_minivm.c.

References ast_calloc, NULL, and populate_defaults().

Referenced by find_account(), and find_user_realtime().

01042 {
01043    struct minivm_account *new;
01044 
01045    new = ast_calloc(1, sizeof(*new));
01046    if (!new)
01047       return NULL;
01048    populate_defaults(new);
01049 
01050    return new;
01051 }

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

Definition at line 1779 of file app_minivm.c.

References ao2_cleanup, ast_channel_lock, ast_channel_snapshot_get_latest(), ast_channel_uniqueid(), ast_channel_unlock, ast_copy_string(), ast_debug, ast_json_pack(), ast_json_unref(), ast_log, ast_mwi_blob_create(), ast_mwi_create(), ast_mwi_topic(), ast_mwi_vm_app_type(), ast_strdupa, ast_strlen_zero, minivm_account::attachfmt, minivm_template::attachment, minivm_account::domain, minivm_account::etemplate, minivm_template::locale, LOG_WARNING, message_template_find(), MVM_MESSAGE_EMAIL, MVM_MESSAGE_PAGE, NULL, minivm_account::pager, pbx_builtin_getvar_helper(), minivm_account::ptemplate, RAII_VAR, run_externnotify(), sendmail(), stasis_publish(), strsep(), and minivm_account::username.

Referenced by copy_message(), leave_voicemail(), and minivm_notify_exec().

01780 {
01781    RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
01782    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
01783    RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
01784    char *stringp;
01785    struct minivm_template *etemplate;
01786    char *messageformat;
01787    int res = 0;
01788    char oldlocale[100];
01789    const char *counter;
01790 
01791    if (!ast_strlen_zero(vmu->attachfmt)) {
01792       if (strstr(format, vmu->attachfmt)) {
01793          format = vmu->attachfmt;
01794       } else {
01795          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);
01796       }
01797    }
01798 
01799    etemplate = message_template_find(vmu->etemplate);
01800    if (!etemplate)
01801       etemplate = message_template_find(templatename);
01802    if (!etemplate)
01803       etemplate = message_template_find("email-default");
01804 
01805    /* Attach only the first format */
01806    stringp = messageformat = ast_strdupa(format);
01807    strsep(&stringp, "|");
01808 
01809    if (!ast_strlen_zero(etemplate->locale)) {
01810       char *new_locale;
01811       ast_copy_string(oldlocale, setlocale(LC_TIME, NULL), sizeof(oldlocale));
01812       ast_debug(2, "Changing locale from %s to %s\n", oldlocale, etemplate->locale);
01813       new_locale = setlocale(LC_TIME, etemplate->locale);
01814       if (new_locale == NULL) {
01815          ast_log(LOG_WARNING, "-_-_- Changing to new locale did not work. Locale: %s\n", etemplate->locale);
01816       }
01817    }
01818 
01819 
01820 
01821    /* Read counter if available */
01822    ast_channel_lock(chan);
01823    if ((counter = pbx_builtin_getvar_helper(chan, "MVM_COUNTER"))) {
01824       counter = ast_strdupa(counter);
01825    }
01826    ast_channel_unlock(chan);
01827 
01828    if (ast_strlen_zero(counter)) {
01829       ast_debug(2, "MVM_COUNTER not found\n");
01830    } else {
01831       ast_debug(2, "MVM_COUNTER found - will use it with value %s\n", counter);
01832    }
01833 
01834    res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_EMAIL, counter);
01835 
01836    if (res == 0 && !ast_strlen_zero(vmu->pager))  {
01837       /* Find template for paging */
01838       etemplate = message_template_find(vmu->ptemplate);
01839       if (!etemplate)
01840          etemplate = message_template_find("pager-default");
01841 
01842       if (!ast_strlen_zero(etemplate->locale)) {
01843          ast_copy_string(oldlocale, setlocale(LC_TIME, ""), sizeof(oldlocale));
01844          setlocale(LC_TIME, etemplate->locale);
01845       }
01846 
01847       res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter);
01848    }
01849 
01850    mwi_state = ast_mwi_create(vmu->username, vmu->domain);
01851    if (!mwi_state) {
01852       goto notify_cleanup;
01853    }
01854    mwi_state->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
01855 
01856    json_object = ast_json_pack("{s: s, s: s}",
01857          "Event", "MiniVoiceMail"
01858          "Action", "SentNotification",
01859          "Counter", counter);
01860    if (!json_object) {
01861       goto notify_cleanup;
01862    }
01863    message = ast_mwi_blob_create(mwi_state, ast_mwi_vm_app_type(), json_object);
01864    if (!message) {
01865       goto notify_cleanup;
01866    }
01867    stasis_publish(ast_mwi_topic(mwi_state->uniqueid), message);
01868 
01869 notify_cleanup:
01870    run_externnotify(chan, vmu);     /* Run external notification */
01871    if (!ast_strlen_zero(etemplate->locale)) {
01872       setlocale(LC_TIME, oldlocale);   /* Reset to old locale */
01873    }
01874    return res;
01875 }

static int play_record_review ( struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime,
char *  fmt,
int  outsidecaller,
struct minivm_account vmu,
int *  duration,
int *  sound_duration,
const char *  unlockdir,
signed char  record_gain 
) [static]

Definition at line 1626 of file app_minivm.c.

References ast_channel_language(), ast_channel_setoption(), AST_DIGIT_ANY, ast_log, AST_OPTION_RXGAIN, ast_play_and_record_full(), ast_play_and_wait(), AST_RECORD_IF_EXISTS_OVERWRITE, ast_stream_and_wait(), ast_streamfile(), ast_test_flag, ast_verb, ast_waitfordigit(), ast_waitstream(), global_maxsilence, global_silencethreshold, LOG_WARNING, MVM_OPERATOR, MVM_REVIEW, NULL, and vm_delete().

Referenced by leave_voicemail(), minivm_accmess_exec(), vm_forwardoptions(), vm_newuser(), vm_options(), and vm_tempgreeting().

01629 {
01630    int cmd = 0;
01631    int max_attempts = 3;
01632    int attempts = 0;
01633    int recorded = 0;
01634    int message_exists = 0;
01635    signed char zero_gain = 0;
01636    char *acceptdtmf = "#";
01637    char *canceldtmf = "";
01638 
01639    /* Note that urgent and private are for flagging messages as such in the future */
01640 
01641    /* barf if no pointer passed to store duration in */
01642    if (duration == NULL) {
01643       ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
01644       return -1;
01645    }
01646 
01647    cmd = '3';   /* Want to start by recording */
01648 
01649    while ((cmd >= 0) && (cmd != 't')) {
01650       switch (cmd) {
01651       case '1':
01652          ast_verb(3, "Saving message as is\n");
01653          ast_stream_and_wait(chan, "vm-msgsaved", "");
01654          cmd = 't';
01655          break;
01656       case '2':
01657          /* Review */
01658          ast_verb(3, "Reviewing the message\n");
01659          ast_streamfile(chan, recordfile, ast_channel_language(chan));
01660          cmd = ast_waitstream(chan, AST_DIGIT_ANY);
01661          break;
01662       case '3':
01663          message_exists = 0;
01664          /* Record */
01665          if (recorded == 1) 
01666             ast_verb(3, "Re-recording the message\n");
01667          else
01668             ast_verb(3, "Recording the message\n");
01669          if (recorded && outsidecaller) 
01670             cmd = ast_play_and_wait(chan, "beep");
01671          recorded = 1;
01672          /* 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 */
01673          if (record_gain)
01674             ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
01675          if (ast_test_flag(vmu, MVM_OPERATOR))
01676             canceldtmf = "0";
01677          cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
01678          if (record_gain)
01679             ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
01680          if (cmd == -1) /* User has hung up, no options to give */
01681             return cmd;
01682          if (cmd == '0')
01683             break;
01684          else if (cmd == '*')
01685             break;
01686          else {
01687             /* If all is well, a message exists */
01688             message_exists = 1;
01689             cmd = 0;
01690          }
01691          break;
01692       case '4':
01693       case '5':
01694       case '6':
01695       case '7':
01696       case '8':
01697       case '9':
01698       case '*':
01699       case '#':
01700          cmd = ast_play_and_wait(chan, "vm-sorry");
01701          break;
01702       case '0':
01703          if(!ast_test_flag(vmu, MVM_OPERATOR)) {
01704             cmd = ast_play_and_wait(chan, "vm-sorry");
01705             break;
01706          }
01707          if (message_exists || recorded) {
01708             cmd = ast_play_and_wait(chan, "vm-saveoper");
01709             if (!cmd)
01710                cmd = ast_waitfordigit(chan, 3000);
01711             if (cmd == '1') {
01712                ast_play_and_wait(chan, "vm-msgsaved");
01713                cmd = '0';
01714             } else {
01715                ast_play_and_wait(chan, "vm-deleted");
01716                vm_delete(recordfile);
01717                cmd = '0';
01718             }
01719          }
01720          return cmd;
01721       default:
01722          /* If the caller is an ouside caller, and the review option is enabled,
01723             allow them to review the message, but let the owner of the box review
01724             their OGM's */
01725          if (outsidecaller && !ast_test_flag(vmu, MVM_REVIEW))
01726             return cmd;
01727          if (message_exists) {
01728             cmd = ast_play_and_wait(chan, "vm-review");
01729          } else {
01730             cmd = ast_play_and_wait(chan, "vm-torerecord");
01731             if (!cmd)
01732                cmd = ast_waitfordigit(chan, 600);
01733          }
01734 
01735          if (!cmd && outsidecaller && ast_test_flag(vmu, MVM_OPERATOR)) {
01736             cmd = ast_play_and_wait(chan, "vm-reachoper");
01737             if (!cmd)
01738                cmd = ast_waitfordigit(chan, 600);
01739          }
01740          if (!cmd)
01741             cmd = ast_waitfordigit(chan, 6000);
01742          if (!cmd) {
01743             attempts++;
01744          }
01745          if (attempts > max_attempts) {
01746             cmd = 't';
01747          }
01748       }
01749    }
01750    if (outsidecaller)
01751       ast_play_and_wait(chan, "vm-goodbye");
01752    if (cmd == 't')
01753       cmd = 0;
01754    return cmd;
01755 }

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]

Definition at line 1003 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 make_email_file(), sendmail(), and sendpage().

01004 {
01005    char callerid[256];
01006    struct ast_variable *var;
01007    
01008    if (!channel) {
01009       ast_log(LOG_ERROR, "No allocated channel, giving up...\n");
01010       return;
01011    }
01012 
01013    for (var = vmu->chanvars ; var ; var = var->next) {
01014       pbx_builtin_setvar_helper(channel, var->name, var->value);
01015    }
01016 
01017    /* Prepare variables for substition in email body and subject */
01018    pbx_builtin_setvar_helper(channel, "MVM_NAME", vmu->fullname);
01019    pbx_builtin_setvar_helper(channel, "MVM_DUR", dur);
01020    pbx_builtin_setvar_helper(channel, "MVM_DOMAIN", vmu->domain);
01021    pbx_builtin_setvar_helper(channel, "MVM_USERNAME", vmu->username);
01022    pbx_builtin_setvar_helper(channel, "MVM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
01023    pbx_builtin_setvar_helper(channel, "MVM_CIDNAME", (cidname ? cidname : "an unknown caller"));
01024    pbx_builtin_setvar_helper(channel, "MVM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
01025    pbx_builtin_setvar_helper(channel, "MVM_DATE", date);
01026    if (!ast_strlen_zero(counter))
01027       pbx_builtin_setvar_helper(channel, "MVM_COUNTER", counter);
01028 }

static void queue_mwi_event ( const char *  channel_id,
const char *  mbx,
const char *  ctx,
int  urgent,
int  new,
int  old 
) [static]

Definition at line 2052 of file app_minivm.c.

References ast_publish_mwi_state_channel, ast_strdupa, ast_strlen_zero, context, and mailbox.

Referenced by append_mailbox(), minivm_mwi_exec(), notify_new_message(), notify_new_state(), poll_subscribed_mailbox(), and vm_execmain().

02053 {
02054    char *mailbox, *context;
02055 
02056    mailbox = ast_strdupa(mbx);
02057    context = ast_strdupa(ctx);
02058    if (ast_strlen_zero(context)) {
02059       context = "default";
02060    }
02061 
02062    ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
02063 }

static int reload ( void   )  [static]

Reload mini voicemail module.

Definition at line 3514 of file app_minivm.c.

References load_config().

03515 {
03516    return(load_config(1));
03517 }

static void run_externnotify ( struct ast_channel chan,
struct minivm_account vmu 
) [static]

Run external notification for voicemail message.

Definition at line 1758 of file app_minivm.c.

References ast_channel_caller(), ast_debug, ast_safe_system(), ast_strlen_zero, minivm_account::domain, minivm_account::externnotify, global_externnotify, and minivm_account::username.

Referenced by forward_message(), notify_new_message(), notify_new_state(), poll_subscribed_mailbox(), and vm_execmain().

01759 {
01760    char arguments[BUFSIZ];
01761 
01762    if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify))
01763       return;
01764 
01765    snprintf(arguments, sizeof(arguments), "%s %s@%s %s %s&", 
01766       ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify, 
01767       vmu->username, vmu->domain,
01768       (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str)
01769          ? ast_channel_caller(chan)->id.name.str : "",
01770       (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str)
01771          ? ast_channel_caller(chan)->id.number.str : "");
01772 
01773    ast_debug(1, "Executing: %s\n", arguments);
01774    ast_safe_system(arguments);
01775 }

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]

Definition at line 1235 of file app_minivm.c.

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

Referenced by forward_message(), and notify_new_message().

01236 {
01237    FILE *p = NULL;
01238    int pfd;
01239    char email[256] = "";
01240    char who[256] = "";
01241    char date[256];
01242    char bound[256];
01243    char fname[PATH_MAX];
01244    char dur[PATH_MAX];
01245    char tmp[80] = "/tmp/astmail-XXXXXX";
01246    char tmp2[PATH_MAX];
01247    char newtmp[PATH_MAX]; /* Only used with volgain */
01248    struct timeval now;
01249    struct ast_tm tm;
01250    struct minivm_zone *the_zone = NULL;
01251    struct ast_channel *ast;
01252    char *finalfilename = "";
01253    struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
01254    char *fromaddress;
01255    char *fromemail;
01256 
01257    if (!str1 || !str2) {
01258       ast_free(str1);
01259       ast_free(str2);
01260       return -1;
01261    }
01262 
01263    if (type == MVM_MESSAGE_EMAIL) {
01264       if (vmu && !ast_strlen_zero(vmu->email)) {
01265          ast_copy_string(email, vmu->email, sizeof(email)); 
01266       } else if (!ast_strlen_zero(vmu->username) && !ast_strlen_zero(vmu->domain))
01267          snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
01268    } else if (type == MVM_MESSAGE_PAGE) {
01269       ast_copy_string(email, vmu->pager, sizeof(email));
01270    }
01271 
01272    if (ast_strlen_zero(email)) {
01273       ast_log(LOG_WARNING, "No address to send message to.\n");
01274       ast_free(str1);
01275       ast_free(str2);
01276       return -1;  
01277    }
01278 
01279    ast_debug(3, "Sending mail to %s@%s - Using template %s\n", vmu->username, vmu->domain, template->name);
01280 
01281    if (!strcmp(format, "wav49"))
01282       format = "WAV";
01283 
01284 
01285    /* If we have a gain option, process it now with sox */
01286    if (type == MVM_MESSAGE_EMAIL && (vmu->volgain < -.001 || vmu->volgain > .001) ) {
01287       char tmpcmd[PATH_MAX];
01288       int tmpfd;
01289 
01290       ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
01291       ast_debug(3, "newtmp: %s\n", newtmp);
01292       tmpfd = mkstemp(newtmp);
01293       if (tmpfd < 0) {
01294          ast_log(LOG_WARNING, "Failed to create temporary file for volgain: %d\n", errno);
01295          ast_free(str1);
01296          ast_free(str2);
01297          return -1;
01298       }
01299       snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
01300       ast_safe_system(tmpcmd);
01301       close(tmpfd);
01302       finalfilename = newtmp;
01303       ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
01304    } else {
01305       finalfilename = ast_strdupa(filename);
01306    }
01307 
01308    /* Create file name */
01309    snprintf(fname, sizeof(fname), "%s.%s", finalfilename, format);
01310 
01311    if (template->attachment)
01312       ast_debug(1, "Attaching file '%s', format '%s', uservm is '%d'\n", finalfilename, format, attach_user_voicemail);
01313 
01314    /* Make a temporary file instead of piping directly to sendmail, in case the mail
01315       command hangs */
01316    pfd = mkstemp(tmp);
01317    if (pfd > -1) {
01318       p = fdopen(pfd, "w");
01319       if (!p) {
01320          close(pfd);
01321          pfd = -1;
01322       }
01323       ast_debug(1, "Opening temp file for e-mail: %s\n", tmp);
01324    }
01325    if (!p) {
01326       ast_log(LOG_WARNING, "Unable to open temporary file '%s'\n", tmp);
01327       ast_free(str1);
01328       ast_free(str2);
01329       return -1;
01330    }
01331    /* Allocate channel used for chanvar substitution */
01332    ast = ast_dummy_channel_alloc();
01333    if (!ast) {
01334       ast_free(str1);
01335       ast_free(str2);
01336       return -1;
01337    }
01338 
01339    snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
01340 
01341    /* Does this user have a timezone specified? */
01342    if (!ast_strlen_zero(vmu->zonetag)) {
01343       /* Find the zone in the list */
01344       struct minivm_zone *z;
01345       AST_LIST_LOCK(&minivm_zones);
01346       AST_LIST_TRAVERSE(&minivm_zones, z, list) {
01347          if (strcmp(z->name, vmu->zonetag)) 
01348             continue;
01349          the_zone = z;
01350       }
01351       AST_LIST_UNLOCK(&minivm_zones);
01352    }
01353 
01354    now = ast_tvnow();
01355    ast_localtime(&now, &tm, the_zone ? the_zone->timezone : NULL);
01356    ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
01357 
01358    /* Start printing the email to the temporary file */
01359    fprintf(p, "Date: %s\n", date);
01360 
01361    /* Set date format for voicemail mail */
01362    ast_strftime(date, sizeof(date), template->dateformat, &tm);
01363 
01364 
01365    /* Populate channel with channel variables for substitution */
01366    prep_email_sub_vars(ast, vmu, cidnum, cidname, dur, date, counter);
01367 
01368    /* Find email address to use */
01369    /* If there's a server e-mail address in the account, use that, othterwise template */
01370    fromemail = ast_strlen_zero(vmu->serveremail) ?  template->serveremail : vmu->serveremail;
01371 
01372    /* Find name to user for server e-mail */
01373    fromaddress = ast_strlen_zero(template->fromaddress) ? "" : template->fromaddress;
01374 
01375    /* If needed, add hostname as domain */
01376    if (ast_strlen_zero(fromemail))
01377       fromemail = "asterisk";
01378 
01379    if (strchr(fromemail, '@'))
01380       ast_copy_string(who, fromemail, sizeof(who));
01381    else  {
01382       char host[MAXHOSTNAMELEN];
01383       gethostname(host, sizeof(host)-1);
01384       snprintf(who, sizeof(who), "%s@%s", fromemail, host);
01385    }
01386 
01387    if (ast_strlen_zero(fromaddress)) {
01388       fprintf(p, "From: Asterisk PBX <%s>\n", who);
01389    } else {
01390       ast_debug(4, "Fromaddress template: %s\n", fromaddress);
01391       ast_str_substitute_variables(&str1, 0, ast, fromaddress);
01392       if (check_mime(ast_str_buffer(str1))) {
01393          int first_line = 1;
01394          char *ptr;
01395          ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
01396          while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
01397             *ptr = '\0';
01398             fprintf(p, "%s %s\n", first_line ? "From:" : "", ast_str_buffer(str2));
01399             first_line = 0;
01400             /* Substring is smaller, so this will never grow */
01401             ast_str_set(&str2, 0, "%s", ptr + 1);
01402          }
01403          fprintf(p, "%s %s <%s>\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
01404       } else {
01405          fprintf(p, "From: %s <%s>\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
01406       }
01407    } 
01408 
01409    fprintf(p, "Message-ID: <Asterisk-%u-%s-%d-%s>\n", (unsigned int)ast_random(), vmu->username, (int)getpid(), who);
01410 
01411    if (ast_strlen_zero(vmu->email)) {
01412       snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
01413    } else {
01414       ast_copy_string(email, vmu->email, sizeof(email));
01415    }
01416 
01417    if (check_mime(vmu->fullname)) {
01418       int first_line = 1;
01419       char *ptr;
01420       ast_str_encode_mime(&str2, 0, template->charset, vmu->fullname, strlen("To: "), strlen(email) + 3);
01421       while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
01422          *ptr = '\0';
01423          fprintf(p, "%s %s\n", first_line ? "To:" : "", ast_str_buffer(str2));
01424          first_line = 0;
01425          /* Substring is smaller, so this will never grow */
01426          ast_str_set(&str2, 0, "%s", ptr + 1);
01427       }
01428       fprintf(p, "%s %s <%s>\n", first_line ? "To:" : "", ast_str_buffer(str2), email);
01429    } else {
01430       fprintf(p, "To: %s <%s>\n", ast_str_quote(&str2, 0, vmu->fullname), email);
01431    }
01432 
01433    if (!ast_strlen_zero(template->subject)) {
01434       ast_str_substitute_variables(&str1, 0, ast, template->subject);
01435       if (check_mime(ast_str_buffer(str1))) {
01436          int first_line = 1;
01437          char *ptr;
01438          ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("Subject: "), 0);
01439          while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
01440             *ptr = '\0';
01441             fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
01442             first_line = 0;
01443             /* Substring is smaller, so this will never grow */
01444             ast_str_set(&str2, 0, "%s", ptr + 1);
01445          }
01446          fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
01447       } else {
01448          fprintf(p, "Subject: %s\n", ast_str_buffer(str1));
01449       }
01450    } else {
01451       fprintf(p, "Subject: New message in mailbox %s@%s\n", vmu->username, vmu->domain);
01452       ast_debug(1, "Using default subject for this email \n");
01453    }
01454 
01455    if (option_debug > 2)
01456       fprintf(p, "X-Asterisk-debug: template %s user account %s@%s\n", template->name, vmu->username, vmu->domain);
01457    fprintf(p, "MIME-Version: 1.0\n");
01458 
01459    /* Something unique. */
01460    snprintf(bound, sizeof(bound), "voicemail_%s%d%u", vmu->username, (int)getpid(), (unsigned int)ast_random());
01461 
01462    fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
01463 
01464    fprintf(p, "--%s\n", bound);
01465    fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", template->charset);
01466    if (!ast_strlen_zero(template->body)) {
01467       ast_str_substitute_variables(&str1, 0, ast, template->body);
01468       ast_debug(3, "Message now: %s\n-----\n", ast_str_buffer(str1));
01469       fprintf(p, "%s\n", ast_str_buffer(str1));
01470    } else {
01471       fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message \n"
01472          "in mailbox %s from %s, on %s so you might\n"
01473          "want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, 
01474          dur,  vmu->username, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
01475       ast_debug(3, "Using default message body (no template)\n-----\n");
01476    }
01477    /* Eww. We want formats to tell us their own MIME type */
01478    if (template->attachment) {
01479       char *ctype = "audio/x-";
01480       ast_debug(3, "Attaching file to message: %s\n", fname);
01481       if (!strcasecmp(format, "ogg"))
01482          ctype = "application/";
01483 
01484       fprintf(p, "--%s\n", bound);
01485       fprintf(p, "Content-Type: %s%s; name=\"voicemailmsg.%s\"\n", ctype, format, format);
01486       fprintf(p, "Content-Transfer-Encoding: base64\n");
01487       fprintf(p, "Content-Description: Voicemail sound attachment.\n");
01488       fprintf(p, "Content-Disposition: attachment; filename=\"voicemail%s.%s\"\n\n", counter ? counter : "", format);
01489 
01490       base_encode(fname, p);
01491       fprintf(p, "\n\n--%s--\n.\n", bound);
01492    }
01493    fclose(p);
01494    snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", global_mailcmd, tmp, tmp);
01495    ast_safe_system(tmp2);
01496    ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : "");
01497    ast_debug(3, "Actual command used: %s\n", tmp2);
01498    ast = ast_channel_unref(ast);
01499    ast_free(str1);
01500    ast_free(str2);
01501    return 0;
01502 }

static int timezone_add ( const char *  zonename,
const char *  config 
) [static]

Add time zone to memory list.

Definition at line 2674 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, NULL, strsep(), minivm_zone::timezone, and minivm_stats::timezones.

Referenced by load_config().

02675 {
02676    struct minivm_zone *newzone;
02677    char *msg_format, *timezone_str;
02678 
02679    newzone = ast_calloc(1, sizeof(*newzone));
02680    if (newzone == NULL)
02681       return 0;
02682 
02683    msg_format = ast_strdupa(config);
02684 
02685    timezone_str = strsep(&msg_format, "|");
02686    if (!msg_format) {
02687       ast_log(LOG_WARNING, "Invalid timezone definition : %s\n", zonename);
02688       ast_free(newzone);
02689       return 0;
02690    }
02691          
02692    ast_copy_string(newzone->name, zonename, sizeof(newzone->name));
02693    ast_copy_string(newzone->timezone, timezone_str, sizeof(newzone->timezone));
02694    ast_copy_string(newzone->msg_format, msg_format, sizeof(newzone->msg_format));
02695 
02696    AST_LIST_LOCK(&minivm_zones);
02697    AST_LIST_INSERT_TAIL(&minivm_zones, newzone, list);
02698    AST_LIST_UNLOCK(&minivm_zones);
02699 
02700    global_stats.timezones++;
02701 
02702    return 0;
02703 }

static void timezone_destroy_list ( void   )  [static]

Clear list of timezones.

Definition at line 2662 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().

02663 {
02664    struct minivm_zone *this;
02665 
02666    AST_LIST_LOCK(&minivm_zones);
02667    while ((this = AST_LIST_REMOVE_HEAD(&minivm_zones, list))) 
02668       free_zone(this);
02669       
02670    AST_LIST_UNLOCK(&minivm_zones);
02671 }

static int unload_module ( void   )  [static]

static int vm_delete ( char *  file  )  [static]

Definition at line 1612 of file app_minivm.c.

References ast_debug, ast_filedelete(), and NULL.

Referenced by copy_message(), minivm_delete_exec(), notify_new_message(), and play_record_review().

01613 {
01614    int res;
01615 
01616    ast_debug(1, "Deleting voicemail file %s\n", file);
01617 
01618    res = unlink(file);  /* Remove the meta data file */
01619    res |=  ast_filedelete(file, NULL); /* remove the media file */
01620    return res;
01621 }

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

References ast_lock_path(), and AST_LOCK_TIMEOUT.

Referenced by access_counter_file(), close_mailbox(), copy_message(), count_messages(), leave_voicemail(), msg_create_from_file(), open_mailbox(), resequence_mailbox(), and save_to_folder().

03272 {
03273    switch (ast_lock_path(path)) {
03274    case AST_LOCK_TIMEOUT:
03275       return -1;
03276    default:
03277       return 0;
03278    }
03279 }

static void vmaccounts_destroy_list ( void   )  [static]

Definition at line 1056 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().

01057 {
01058    struct minivm_account *this;
01059    AST_LIST_LOCK(&minivm_accounts);
01060    while ((this = AST_LIST_REMOVE_HEAD(&minivm_accounts, list))) 
01061       ast_free(this);
01062    AST_LIST_UNLOCK(&minivm_accounts);
01063 }


Variable Documentation

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

Definition at line 3568 of file app_minivm.c.

char* app_minivm_accmess = "MinivmAccMess" [static]

Definition at line 566 of file app_minivm.c.

char* app_minivm_delete = "MinivmDelete" [static]

Definition at line 565 of file app_minivm.c.

char* app_minivm_greet = "MinivmGreet" [static]

Definition at line 563 of file app_minivm.c.

char* app_minivm_mwi = "MinivmMWI" [static]

Definition at line 567 of file app_minivm.c.

char* app_minivm_notify = "MinivmNotify" [static]

Definition at line 564 of file app_minivm.c.

char* app_minivm_record = "MinivmRecord" [static]

Definition at line 562 of file app_minivm.c.

Definition at line 3568 of file app_minivm.c.

struct ast_cli_entry cli_minivm[] [static]

CLI commands for Mini-voicemail.

Definition at line 3465 of file app_minivm.c.

Referenced by load_module(), and unload_module().

char default_vmformat[80] [static]

char global_externnotify[160] [static]

External notification application

Definition at line 701 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 702 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 700 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 698 of file app_minivm.c.

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

int global_maxsilence [static]

Definition at line 706 of file app_minivm.c.

Referenced by load_config().

int global_silencethreshold = 128 [static]

struct minivm_stats global_stats [static]

Statistics for voicemail.

Definition at line 688 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 696 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 695 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 708 of file app_minivm.c.

Referenced by populate_defaults().

struct ast_flags globalflags = {0} [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]

Definition at line 597 of file app_minivm.c.

Referenced by minivm_accmess_exec().

Initial value:

 {
   .name = "MINIVMACCOUNT",
   .read = minivm_account_func_read,
}

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

Referenced by minivm_greet_exec(), and minivm_record_exec().

Initial value:

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

Definition at line 3474 of file app_minivm.c.

Referenced by load_module(), and unload_module().

ast_mutex_t minivmlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Lock to protect voicemail system

Definition at line 690 of file app_minivm.c.

Referenced by load_config().

FILE* minivmlogfile [static]

The minivm log file

Definition at line 693 of file app_minivm.c.

Referenced by leave_voicemail(), and load_config().

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

Lock to protect voicemail system log file

Definition at line 691 of file app_minivm.c.

Referenced by leave_voicemail().

char MVM_SPOOL_DIR[PATH_MAX] [static]

Definition at line 559 of file app_minivm.c.


Generated on Thu Apr 16 06:28:34 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6