Wed Oct 28 13:31:41 2009

Asterisk developer's documentation


app_voicemail.c File Reference

Comedian Mail - Voicemail System. More...

#include "asterisk.h"
#include "asterisk/paths.h"
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <time.h>
#include <dirent.h>
#include "asterisk/logger.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/adsi.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/dsp.h"
#include "asterisk/localtime.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/stringfields.h"
#include "asterisk/smdi.h"
#include "asterisk/event.h"
#include "asterisk/taskprocessor.h"

Include dependency graph for app_voicemail.c:

Go to the source code of this file.

Data Structures

struct  ast_vm_user
struct  baseio
struct  leave_vm_options
 Options for leaving voicemail with the voicemail() application. More...
struct  mwi_sub
 An MWI subscription. More...
struct  mwi_sub_task
struct  mwi_subs
struct  users
 list of users found in the config file More...
struct  vm_state
struct  vm_zone
struct  zones

Defines

#define ASTERISK_USERNAME   "asterisk"
#define BASELINELEN   72
#define BASEMAXINLINE   256
#define CHUNKSIZE   65536
#define COMMAND_TIMEOUT   5000
#define COPY(a, b, c, d, e, f, g, h)   (copy_plain_file(g,h));
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY   "#"
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY   "0"
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY   "2"
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY   "*"
#define DEFAULT_LISTEN_CONTROL_STOP_KEY   "13456789"
#define DEFAULT_POLL_FREQ   30
#define DELETE(a, b, c, d)   (vm_delete(c))
#define DISPOSE(a, b)
#define ENDL   "\n"
#define eol   "\r\n"
#define ERROR_LOCK_PATH   -100
#define EXISTS(a, b, c, d)   (ast_fileexists(c,NULL,d) > 0)
#define HVSU_OUTPUT_FORMAT   "%-10s %-5s %-25s %-10s %6s\n"
#define HVSZ_OUTPUT_FORMAT   "%-15s %-20s %-45s\n"
#define INTRO   "vm-intro"
#define MAX_DATETIME_FORMAT   512
#define MAX_NUM_CID_CONTEXTS   10
#define MAXMSG   100
#define MAXMSGLIMIT   9999
#define MINPASSWORD   0
#define PWDCHANGE_EXTERNAL   (1 << 2)
#define PWDCHANGE_INTERNAL   (1 << 1)
#define RENAME(a, b, c, d, e, f, g, h)   (rename_file(g,h));
#define RETRIEVE(a, b, c, d)
#define SENDMAIL   "/usr/sbin/sendmail -t"
#define SMDI_MWI_WAIT_TIMEOUT   1000
#define STORE(a, b, c, d, e, f, g, h, i, j)
#define tdesc   "Comedian Mail (Voicemail System)"
#define VALID_DTMF   "1234567890*#"
#define VM_ALLOCED   (1 << 13)
#define VM_ATTACH   (1 << 11)
#define VM_DELETE   (1 << 12)
#define VM_DIRECFORWARD   (1 << 10)
#define VM_ENVELOPE   (1 << 4)
#define VM_FORCEGREET   (1 << 8)
#define VM_FORCENAME   (1 << 7)
#define VM_FWDURGAUTO   (1 << 18)
#define VM_MESSAGEWRAP   (1 << 17)
#define VM_MOVEHEARD   (1 << 16)
#define VM_OPERATOR   (1 << 1)
#define VM_PBXSKIP   (1 << 9)
#define VM_REVIEW   (1 << 0)
#define VM_SAYCID   (1 << 2)
#define VM_SAYDURATION   (1 << 5)
#define VM_SEARCH   (1 << 14)
#define VM_SKIPAFTERCMD   (1 << 6)
#define VM_SVMAIL   (1 << 3)
#define VM_TEMPGREETWARN   (1 << 15)
#define VMSTATE_MAX_MSG_ARRAY   256
#define VOICEMAIL_CONFIG   "voicemail.conf"
#define VOICEMAIL_DIR_MODE   0777
#define VOICEMAIL_FILE_MODE   0666

Enumerations

enum  vm_box {
  NEW_FOLDER, OLD_FOLDER, WORK_FOLDER, FAMILY_FOLDER,
  FRIENDS_FOLDER, GREETINGS_FOLDER
}
enum  vm_option_args { OPT_ARG_RECORDGAIN = 0, OPT_ARG_PLAYFOLDER = 1, OPT_ARG_DTMFEXIT = 2, OPT_ARG_ARRAY_SIZE = 3 }
enum  vm_option_flags {
  OPT_SILENT = (1 << 0), OPT_BUSY_GREETING = (1 << 1), OPT_UNAVAIL_GREETING = (1 << 2), OPT_RECORDGAIN = (1 << 3),
  OPT_PREPEND_MAILBOX = (1 << 4), OPT_AUTOPLAY = (1 << 6), OPT_DTMFEXIT = (1 << 7), OPT_MESSAGE_Urgent = (1 << 8),
  OPT_MESSAGE_PRIORITY = (1 << 9)
}
enum  vm_passwordlocation { OPT_PWLOC_VOICEMAILCONF = 0, OPT_PWLOC_SPOOLDIR = 1, OPT_PWLOC_USERSCONF = 2 }

Functions

static void __fini_mwi_subs (void)
static int __has_voicemail (const char *context, const char *mailbox, const char *folder, int shortcircuit)
static void __init_mwi_subs (void)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_mailbox_exists (struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
static int add_email_attachment (FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
static void adsi_begin (struct ast_channel *chan, int *useadsi)
static void adsi_delete (struct ast_channel *chan, struct vm_state *vms)
static void adsi_folders (struct ast_channel *chan, int start, char *label)
static void adsi_goodbye (struct ast_channel *chan)
static int adsi_load_vmail (struct ast_channel *chan, int *useadsi)
static void adsi_login (struct ast_channel *chan)
static int adsi_logo (unsigned char *buf)
static void adsi_message (struct ast_channel *chan, struct vm_state *vms)
static void adsi_password (struct ast_channel *chan)
static void adsi_status (struct ast_channel *chan, struct vm_state *vms)
static void adsi_status2 (struct ast_channel *chan, struct vm_state *vms)
static int advanced_options (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
 The advanced options within a message.
static int append_mailbox (const char *context, const char *box, const char *data)
static void apply_option (struct ast_vm_user *vmu, const char *var, const char *value)
 Sets a a specific property value.
static void apply_options (struct ast_vm_user *vmu, const char *options)
 Destructively Parse options and apply.
static void apply_options_full (struct ast_vm_user *retval, struct ast_variable *var)
 Loads the options specific to a voicemail user.
static const char * ast_str_encode_mime (struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
 Encode a string according to the MIME rules for encoding strings that are not 7-bit clean or contain control characters.
static const char * ast_str_quote (struct ast_str **buf, ssize_t maxlen, const char *from)
 Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
static int base_encode (char *filename, FILE *so)
 Performs a base 64 encode algorithm on the contents of a File.
static int change_password_realtime (struct ast_vm_user *vmu, const char *password)
 Performs a change of the voicemail passowrd in the realtime engine.
static int check_mime (const char *str)
 Check if the string would need encoding within the MIME standard, to avoid confusing certain mail software that expects messages to be 7-bit clean.
static int check_password (struct ast_vm_user *vmu, char *password)
 Check that password meets minimum required length.
static int close_mailbox (struct vm_state *vms, struct ast_vm_user *vmu)
static char * complete_voicemail_show_users (const char *line, const char *word, int pos, int state)
static int copy (char *infile, char *outfile)
 Utility function to copy a file.
static int copy_message (struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag)
 Copies a message from one mailbox to another.
static void copy_plain_file (char *frompath, char *topath)
 Copies a voicemail information (envelope) file.
static int count_messages (struct ast_vm_user *vmu, char *dir)
 Find all .txt files - even if they are not in sequence from 0000.
static int create_dirpath (char *dest, int len, const char *context, const char *ext, const char *folder)
 basically mkdir -p $dest/$context/$ext/$folder
static int dialout (struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
static struct ast_vm_userfind_or_create (const char *context, const char *box)
static struct ast_vm_userfind_user (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the users file or the realtime engine.
static struct ast_vm_userfind_user_realtime (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the realtime engine.
static int forward_message (struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
 Sends a voicemail message to a mailbox recipient.
static void free_user (struct ast_vm_user *vmu)
static void free_vm_users (void)
 Free the users structure.
static void free_vm_zones (void)
 Free the zones structure.
static void free_zone (struct vm_zone *z)
static int get_date (char *s, int len)
 Gets the current date and time, as formatted string.
static int get_folder (struct ast_channel *chan, int start)
 get_folder: Folder menu Plays "press 1 for INBOX messages" etc. Should possibly be internationalized
static int get_folder2 (struct ast_channel *chan, char *fn, int start)
 plays a prompt and waits for a keypress.
static int get_folder_by_name (const char *name)
static int handle_subscribe (void *datap)
static int handle_unsubscribe (void *datap)
static char * handle_voicemail_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Reload voicemail configuration from the CLI.
static char * handle_voicemail_show_users (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show a list of voicemail users in the CLI.
static char * handle_voicemail_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 has_voicemail (const char *mailbox, const char *folder)
 Determines if the given folder has messages.
static int inboxcount (const char *mailbox, int *newmsgs, int *oldmsgs)
static int inboxcount2 (const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
static int inbuf (struct baseio *bio, FILE *fi)
 utility used by inchar(), for base_encode()
static int inchar (struct baseio *bio, FILE *fi)
 utility used by base_encode()
static int invent_message (struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
static int is_valid_dtmf (const char *key)
 Determines if a DTMF key entered is valid.
static int last_message_index (struct ast_vm_user *vmu, char *dir)
 Determines the highest message number in use for a given user and mailbox folder.
static int leave_voicemail (struct ast_channel *chan, char *ext, struct leave_vm_options *options)
 Prompts the user and records a voicemail to a mailbox.
static int load_config (int reload)
static int load_module (void)
static int make_dir (char *dest, int len, const char *context, const char *ext, const char *folder)
 Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
static void make_email_file (FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
 Creates the email file to be sent to indicate a new voicemail exists for a user.
static int make_file (char *dest, const int len, const char *dir, const int num)
 Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
static int manager_list_voicemail_users (struct mansession *s, const struct message *m)
 Manager list voicemail users command.
static void * mb_poll_thread (void *data)
static const char * mbox (int id)
static int messagecount (const char *context, const char *mailbox, const char *folder)
static void mwi_sub_destroy (struct mwi_sub *mwi_sub)
static void mwi_sub_event_cb (const struct ast_event *event, void *userdata)
static void mwi_unsub_event_cb (const struct ast_event *event, void *userdata)
static int notify_new_message (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
 Sends email notification that a user has a new voicemail waiting for them.
static int ochar (struct baseio *bio, int c, FILE *so)
 utility used by base_encode()
static int open_mailbox (struct vm_state *vms, struct ast_vm_user *vmu, int box)
static int play_message (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static int play_message_callerid (struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
static int play_message_category (struct ast_channel *chan, const char *category)
static int play_message_datetime (struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
static int play_message_duration (struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
static int play_record_review (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir, signed char record_gain, struct vm_state *vms, char *flag)
static void poll_subscribed_mailbox (struct mwi_sub *mwi_sub)
static void poll_subscribed_mailboxes (void)
static void populate_defaults (struct ast_vm_user *vmu)
 Sets default voicemail system options to a voicemail user.
static void prep_email_sub_vars (struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
static void queue_mwi_event (const char *box, int urgent, int new, int old)
static void read_password_from_file (const char *secretfn, char *password, int passwordlen)
static int reload (void)
static void rename_file (char *sfn, char *dfn)
 Renames a message in a mailbox folder.
static int reset_user_pw (const char *context, const char *mailbox, const char *newpass)
 Resets a user password to a specified password.
static void run_externnotify (char *context, char *extension, const char *flag)
static int save_to_folder (struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
static int say_and_wait (struct ast_channel *chan, int num, const char *language)
static int sayname (struct ast_channel *chan, const char *mailbox, const char *context)
static int sendmail (char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
static int sendpage (char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
static char * show_users_realtime (int fd, const char *context)
static void start_poll_thread (void)
static void stop_poll_thread (void)
static char * strip_control (const char *input, char *buf, size_t buflen)
static const char * substitute_escapes (const char *value)
static int unload_module (void)
static int vm_authenticate (struct ast_channel *chan, char *mailbox, int mailbox_size, struct ast_vm_user *res_vmu, const char *context, const char *prefix, int skipuser, int max_logins, int silent)
static int vm_box_exists (struct ast_channel *chan, const char *data)
static int vm_browse_messages (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Top level method to invoke the language variant vm_browse_messages_XX function.
static int vm_browse_messages_en (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Default English syntax for 'You have N messages' greeting.
static int vm_browse_messages_es (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Spanish syntax for 'You have N messages' greeting.
static int vm_browse_messages_gr (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Greek syntax for 'You have N messages' greeting.
static int vm_browse_messages_he (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
static int vm_browse_messages_it (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Italian syntax for 'You have N messages' greeting.
static int vm_browse_messages_pt (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Portuguese syntax for 'You have N messages' greeting.
static int vm_browse_messages_zh (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Chinese (Taiwan)syntax for 'You have N messages' greeting.
static void vm_change_password (struct ast_vm_user *vmu, const char *newpassword)
 The handler for the change password option.
static void vm_change_password_shell (struct ast_vm_user *vmu, char *newpassword)
static char * vm_check_password_shell (char *command, char *buf, size_t len)
static int vm_delete (char *file)
 Removes the voicemail sound and information file.
static int vm_exec (struct ast_channel *chan, const char *data)
static int vm_execmain (struct ast_channel *chan, const char *data)
static int vm_forwardoptions (struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts, char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
 presents the option to prepend to an existing message when forwarding it.
static int vm_instructions (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
static int vm_instructions_en (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
static int vm_instructions_zh (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
static int vm_intro (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static int vm_intro_cz (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_de (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_en (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_es (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_fr (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_gr (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_he (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_it (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_multilang (struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
static int vm_intro_nl (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_no (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_pl (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_pt (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_pt_BR (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_se (struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_zh (struct ast_channel *chan, struct vm_state *vms)
static int vm_lock_path (const char *path)
 Lock file path only return failure if ast_lock_path returns 'timeout', not if the path does not exist or any other reason.
static FILE * vm_mkftemp (char *template)
static int vm_newuser (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
static int vm_options (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
static int vm_play_folder_name (struct ast_channel *chan, char *mbox)
static int vm_play_folder_name_gr (struct ast_channel *chan, char *box)
static int vm_play_folder_name_pl (struct ast_channel *chan, char *box)
static int vm_play_folder_name_ua (struct ast_channel *chan, char *box)
static int vm_tempgreeting (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 The handler for 'record a temporary greeting'.
static int vmauthenticate (struct ast_channel *chan, const char *data)
static struct ast_tmvmu_tm (const struct ast_vm_user *vmu, struct ast_tm *tm)
 fill in *tm for current time according to the proper timezone, if any.
static int wait_file (struct ast_channel *chan, struct vm_state *vms, char *file)
static int wait_file2 (struct ast_channel *chan, struct vm_state *vms, char *file)
static int write_password_to_file (const char *secretfn, const char *password)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Comedian Mail (Voicemail System)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * addesc = "Comedian Mail"
static unsigned char adsifdn [4] = "\x00\x00\x00\x0F"
static unsigned char adsisec [4] = "\x9B\xDB\xF7\xAC"
static int adsiver = 1
static char * app = "VoiceMail"
static char * app2 = "VoiceMailMain"
static char * app3 = "MailboxExists"
static char * app4 = "VMAuthenticate"
static struct ast_module_infoast_module_info = &__mod_info
static char callcontext [AST_MAX_CONTEXT] = ""
static char charset [32] = "ISO-8859-1"
static char cidinternalcontexts [MAX_NUM_CID_CONTEXTS][64]
static struct ast_cli_entry cli_voicemail []
static char dialcontext [AST_MAX_CONTEXT] = ""
static char * emailbody = NULL
static char emaildateformat [32] = "%A, %B %d, %Y at %r"
static char * emailsubject = NULL
static char exitcontext [AST_MAX_CONTEXT] = ""
static char ext_pass_check_cmd [128]
static char ext_pass_cmd [128]
static char externnotify [160]
static char fromstring [100]
static struct ast_flags globalflags = {0}
static char listen_control_forward_key [12]
static char listen_control_pause_key [12]
static char listen_control_restart_key [12]
static char listen_control_reverse_key [12]
static char listen_control_stop_key [12]
static struct ast_custom_function mailbox_exists_acf
static const char *const mailbox_folders []
static char mailcmd [160]
static int maxdeletedmsg
static int maxgreet
static int maxlogins
static int maxmsg
static int maxsilence
static int minpassword
static struct ast_event_submwi_sub_sub
static struct ast_taskprocessormwi_subscription_tps
static struct ast_event_submwi_unsub_sub
static int my_umask
static char * pagerbody = NULL
static char pagerfromstring [100]
static char * pagersubject = NULL
static int passwordlocation
static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER
static unsigned int poll_freq
static ast_mutex_t poll_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static unsigned int poll_mailboxes
static pthread_t poll_thread = AST_PTHREADT_NULL
static unsigned char poll_thread_run
static int pwdchange = PWDCHANGE_INTERNAL
static int saydurationminfo
static char serveremail [80]
static int silencethreshold = 128
static int skipms
static struct ast_smdi_interfacesmdi_iface = NULL
static char userscontext [AST_MAX_EXTENSION] = "default"
static struct ast_app_option vm_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 }, [ 'd' ] = { .flag = OPT_DTMFEXIT , .arg_index = OPT_ARG_DTMFEXIT + 1 }, [ 'p' ] = { .flag = OPT_PREPEND_MAILBOX }, [ 'a' ] = { .flag = OPT_AUTOPLAY , .arg_index = OPT_ARG_PLAYFOLDER + 1 }, [ 'U' ] = { .flag = OPT_MESSAGE_Urgent }, [ 'P' ] = { .flag = OPT_MESSAGE_PRIORITY }}
static char vm_invalid_password [80] = "vm-invalid-password"
static char vm_mismatch [80] = "vm-mismatch"
static char vm_newpassword [80] = "vm-newpassword"
static char vm_passchanged [80] = "vm-passchanged"
static char vm_password [80] = "vm-password"
static char vm_pls_try_again [80] = "vm-pls-try-again"
static char vm_reenterpassword [80] = "vm-reenterpassword"
static char VM_SPOOL_DIR [PATH_MAX]
static char vmfmts [80]
static int vmmaxsecs
static int vmminsecs
static double volgain
static char zonetag [80]


Detailed Description

Comedian Mail - Voicemail System.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
unixODBC (http://www.unixodbc.org/)
ExtRef:
A source distribution of University of Washington's IMAP c-client (http://www.washington.edu/imap/)
See also
Note:
For information about voicemail IMAP storage, read doc/imapstorage.txt

This module requires res_adsi to load. This needs to be optional during compilation.

This file is now almost impossible to work with, due to all #ifdefs. Feels like the database code before realtime. Someone - please come up with a plan to clean this up.

Definition in file app_voicemail.c.


Define Documentation

#define ASTERISK_USERNAME   "asterisk"

Definition at line 393 of file app_voicemail.c.

#define BASELINELEN   72

Definition at line 416 of file app_voicemail.c.

Referenced by ochar().

#define BASEMAXINLINE   256

Definition at line 417 of file app_voicemail.c.

Referenced by base_encode(), and inbuf().

#define CHUNKSIZE   65536

Definition at line 390 of file app_voicemail.c.

#define COMMAND_TIMEOUT   5000

Definition at line 386 of file app_voicemail.c.

#define COPY ( a,
b,
c,
d,
e,
f,
g,
 )     (copy_plain_file(g,h));

Definition at line 690 of file app_voicemail.c.

Referenced by copy_message(), and save_to_folder().

#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY   "#"

Definition at line 398 of file app_voicemail.c.

Referenced by load_config().

#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY   "0"

Definition at line 400 of file app_voicemail.c.

Referenced by load_config().

#define DEFAULT_LISTEN_CONTROL_RESTART_KEY   "2"

Definition at line 401 of file app_voicemail.c.

Referenced by load_config().

#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY   "*"

Definition at line 399 of file app_voicemail.c.

Referenced by load_config().

#define DEFAULT_LISTEN_CONTROL_STOP_KEY   "13456789"

Definition at line 402 of file app_voicemail.c.

Referenced by load_config().

#define DEFAULT_POLL_FREQ   30

By default, poll every 30 seconds

Definition at line 757 of file app_voicemail.c.

Referenced by load_config().

#define DELETE ( a,
b,
c,
 )     (vm_delete(c))

#define DISPOSE ( a,
 ) 

#define ENDL   "\n"

#define eol   "\r\n"

Definition at line 418 of file app_voicemail.c.

Referenced by base_encode(), and ochar().

#define ERROR_LOCK_PATH   -100

Definition at line 442 of file app_voicemail.c.

#define EXISTS ( a,
b,
c,
 )     (ast_fileexists(c,NULL,d) > 0)

Definition at line 688 of file app_voicemail.c.

Referenced by close_mailbox(), copy_message(), and save_to_folder().

#define HVSU_OUTPUT_FORMAT   "%-10s %-5s %-25s %-10s %6s\n"

#define HVSZ_OUTPUT_FORMAT   "%-15s %-20s %-45s\n"

#define INTRO   "vm-intro"

Definition at line 409 of file app_voicemail.c.

Referenced by leave_voicemail(), play_record_review(), and vm_forwardoptions().

#define MAX_DATETIME_FORMAT   512

Definition at line 420 of file app_voicemail.c.

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 421 of file app_voicemail.c.

#define MAXMSG   100

Definition at line 411 of file app_voicemail.c.

Referenced by apply_option(), and load_config().

#define MAXMSGLIMIT   9999

Definition at line 412 of file app_voicemail.c.

Referenced by apply_option(), last_message_index(), and load_config().

#define MINPASSWORD   0

Default minimum mailbox password length

Definition at line 414 of file app_voicemail.c.

Referenced by load_config().

#define PWDCHANGE_EXTERNAL   (1 << 2)

Definition at line 703 of file app_voicemail.c.

Referenced by load_config(), vm_newuser(), and vm_options().

#define PWDCHANGE_INTERNAL   (1 << 1)

Definition at line 702 of file app_voicemail.c.

Referenced by load_config(), vm_newuser(), and vm_options().

#define RENAME ( a,
b,
c,
d,
e,
f,
g,
 )     (rename_file(g,h));

Definition at line 689 of file app_voicemail.c.

Referenced by close_mailbox(), leave_voicemail(), and save_to_folder().

#define RETRIEVE ( a,
b,
c,
 ) 

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

Definition at line 407 of file app_voicemail.c.

#define SMDI_MWI_WAIT_TIMEOUT   1000

Definition at line 384 of file app_voicemail.c.

Referenced by run_externnotify().

#define STORE ( a,
b,
c,
d,
e,
f,
g,
h,
i,
 ) 

#define tdesc   "Comedian Mail (Voicemail System)"

Definition at line 712 of file app_voicemail.c.

#define VALID_DTMF   "1234567890*#"

Definition at line 403 of file app_voicemail.c.

Referenced by is_valid_dtmf().

#define VM_ALLOCED   (1 << 13)

Structure was malloc'ed, instead of placed in a return (usually static) buffer

Definition at line 436 of file app_voicemail.c.

Referenced by find_user(), find_user_realtime(), free_user(), and free_vm_users().

#define VM_ATTACH   (1 << 11)

Attach message to voicemail notifications?

Definition at line 434 of file app_voicemail.c.

Referenced by apply_option(), forward_message(), load_config(), manager_list_voicemail_users(), notify_new_message(), and sendmail().

#define VM_DELETE   (1 << 12)

Delete message after sending notification

Definition at line 435 of file app_voicemail.c.

Referenced by apply_option(), manager_list_voicemail_users(), and notify_new_message().

#define VM_DIRECFORWARD   (1 << 10)

Permit caller to use the Directory app for selecting to which mailbox to forward a VM

Definition at line 433 of file app_voicemail.c.

Referenced by forward_message(), and load_config().

#define VM_ENVELOPE   (1 << 4)

Play the envelope information (who-from, time received, etc.)

Definition at line 427 of file app_voicemail.c.

Referenced by apply_option(), load_config(), manager_list_voicemail_users(), and play_message().

#define VM_FORCEGREET   (1 << 8)

Have new users record their greetings

Definition at line 431 of file app_voicemail.c.

Referenced by apply_option(), load_config(), vm_execmain(), and vm_newuser().

#define VM_FORCENAME   (1 << 7)

Have new users record their name

Definition at line 430 of file app_voicemail.c.

Referenced by apply_option(), load_config(), vm_execmain(), and vm_newuser().

#define VM_FWDURGAUTO   (1 << 18)

Autoset of Urgent flag on forwarded Urgent messages set globally

Definition at line 441 of file app_voicemail.c.

Referenced by forward_message(), and load_config().

#define VM_MESSAGEWRAP   (1 << 17)

Wrap around from the last message to the first, and vice-versa

Definition at line 440 of file app_voicemail.c.

Referenced by apply_option(), load_config(), vm_execmain(), and vm_instructions_en().

#define VM_MOVEHEARD   (1 << 16)

Move a "heard" message to Old after listening to it

Definition at line 439 of file app_voicemail.c.

Referenced by apply_option(), close_mailbox(), and load_config().

#define VM_OPERATOR   (1 << 1)

Allow 0 to be pressed to go to 'o' extension

Definition at line 424 of file app_voicemail.c.

Referenced by apply_option(), leave_voicemail(), load_config(), manager_list_voicemail_users(), and play_record_review().

#define VM_PBXSKIP   (1 << 9)

Skip the [PBX] preamble in the Subject line of emails

Definition at line 432 of file app_voicemail.c.

Referenced by load_config(), and make_email_file().

#define VM_REVIEW   (1 << 0)

After recording, permit the caller to review the recording before saving

Definition at line 423 of file app_voicemail.c.

Referenced by apply_option(), load_config(), manager_list_voicemail_users(), and play_record_review().

#define VM_SAYCID   (1 << 2)

Repeat the CallerID info during envelope playback

Definition at line 425 of file app_voicemail.c.

Referenced by apply_option(), load_config(), manager_list_voicemail_users(), and play_message().

#define VM_SAYDURATION   (1 << 5)

Play the length of the message during envelope playback

Definition at line 428 of file app_voicemail.c.

Referenced by apply_option(), load_config(), and play_message().

#define VM_SEARCH   (1 << 14)

Search all contexts for a matching mailbox

Definition at line 437 of file app_voicemail.c.

Referenced by find_or_create(), find_user(), find_user_realtime(), and load_config().

#define VM_SKIPAFTERCMD   (1 << 6)

After deletion, assume caller wants to go to the next message

Definition at line 429 of file app_voicemail.c.

Referenced by load_config(), and vm_execmain().

#define VM_SVMAIL   (1 << 3)

Allow the user to compose a new VM from within VoicemailMain

Definition at line 426 of file app_voicemail.c.

Referenced by apply_option(), load_config(), and vm_execmain().

#define VM_TEMPGREETWARN   (1 << 15)

Remind user tempgreeting is set

Definition at line 438 of file app_voicemail.c.

Referenced by apply_option(), load_config(), and vm_intro().

#define VMSTATE_MAX_MSG_ARRAY   256

Definition at line 629 of file app_voicemail.c.

#define VOICEMAIL_CONFIG   "voicemail.conf"

Definition at line 392 of file app_voicemail.c.

#define VOICEMAIL_DIR_MODE   0777

Definition at line 388 of file app_voicemail.c.

#define VOICEMAIL_FILE_MODE   0666

Definition at line 389 of file app_voicemail.c.

Referenced by add_email_attachment(), copy(), leave_voicemail(), and vm_mkftemp().


Enumeration Type Documentation

enum vm_box

Enumerator:
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 

Definition at line 445 of file app_voicemail.c.

00445             {
00446    NEW_FOLDER,
00447    OLD_FOLDER,
00448    WORK_FOLDER,
00449    FAMILY_FOLDER,
00450    FRIENDS_FOLDER,
00451    GREETINGS_FOLDER
00452 };

Enumerator:
OPT_ARG_RECORDGAIN 
OPT_ARG_PLAYFOLDER 
OPT_ARG_DTMFEXIT 
OPT_ARG_ARRAY_SIZE 

Definition at line 466 of file app_voicemail.c.

00466                     {
00467    OPT_ARG_RECORDGAIN = 0,
00468    OPT_ARG_PLAYFOLDER = 1,
00469    OPT_ARG_DTMFEXIT   = 2,
00470    /* This *must* be the last value in this enum! */
00471    OPT_ARG_ARRAY_SIZE = 3,
00472 };

Enumerator:
OPT_SILENT 
OPT_BUSY_GREETING 
OPT_UNAVAIL_GREETING 
OPT_RECORDGAIN 
OPT_PREPEND_MAILBOX 
OPT_AUTOPLAY 
OPT_DTMFEXIT 
OPT_MESSAGE_Urgent 
OPT_MESSAGE_PRIORITY 

Definition at line 454 of file app_voicemail.c.

00454                      {
00455    OPT_SILENT =           (1 << 0),
00456    OPT_BUSY_GREETING =    (1 << 1),
00457    OPT_UNAVAIL_GREETING = (1 << 2),
00458    OPT_RECORDGAIN =       (1 << 3),
00459    OPT_PREPEND_MAILBOX =  (1 << 4),
00460    OPT_AUTOPLAY =         (1 << 6),
00461    OPT_DTMFEXIT =         (1 << 7),
00462    OPT_MESSAGE_Urgent =   (1 << 8),
00463    OPT_MESSAGE_PRIORITY = (1 << 9)
00464 };

Enumerator:
OPT_PWLOC_VOICEMAILCONF 
OPT_PWLOC_SPOOLDIR 
OPT_PWLOC_USERSCONF 

Definition at line 474 of file app_voicemail.c.

00474                          {
00475    OPT_PWLOC_VOICEMAILCONF = 0,
00476    OPT_PWLOC_SPOOLDIR      = 1,
00477    OPT_PWLOC_USERSCONF     = 2,
00478 };


Function Documentation

static void __fini_mwi_subs ( void   )  [static]

Definition at line 793 of file app_voicemail.c.

00811 {0};

static int __has_voicemail ( const char *  context,
const char *  mailbox,
const char *  folder,
int  shortcircuit 
) [static]

Definition at line 4991 of file app_voicemail.c.

References ast_strlen_zero().

Referenced by has_voicemail(), inboxcount2(), and messagecount().

04992 {
04993    DIR *dir;
04994    struct dirent *de;
04995    char fn[256];
04996    int ret = 0;
04997 
04998    /* If no mailbox, return immediately */
04999    if (ast_strlen_zero(mailbox))
05000       return 0;
05001 
05002    if (ast_strlen_zero(folder))
05003       folder = "INBOX";
05004    if (ast_strlen_zero(context))
05005       context = "default";
05006 
05007    snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05008 
05009    if (!(dir = opendir(fn)))
05010       return 0;
05011 
05012    while ((de = readdir(dir))) {
05013       if (!strncasecmp(de->d_name, "msg", 3)) {
05014          if (shortcircuit) {
05015             ret = 1;
05016             break;
05017          } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05018             if (shortcircuit) return 1;
05019             ret++;
05020          }
05021       }
05022    }
05023 
05024    closedir(dir);
05025 
05026    /* If we are checking INBOX, we should check Urgent as well */
05027    if (strcmp(folder, "INBOX") == 0) {
05028       return (ret + __has_voicemail(context, mailbox, "Urgent", shortcircuit));
05029    } else {
05030       return ret;
05031    }
05032 }

static void __init_mwi_subs ( void   )  [static]

Definition at line 793 of file app_voicemail.c.

00811 {0};

static void __reg_module ( void   )  [static]

Definition at line 11897 of file app_voicemail.c.

static void __unreg_module ( void   )  [static]

Definition at line 11897 of file app_voicemail.c.

static int acf_mailbox_exists ( struct ast_channel chan,
const char *  cmd,
char *  args,
char *  buf,
size_t  len 
) [static]

Definition at line 9992 of file app_voicemail.c.

References AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), find_user(), LOG_ERROR, and mbox().

09993 {
09994    struct ast_vm_user svm;
09995    AST_DECLARE_APP_ARGS(arg,
09996       AST_APP_ARG(mbox);
09997       AST_APP_ARG(context);
09998    );
09999 
10000    AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10001 
10002    if (ast_strlen_zero(arg.mbox)) {
10003       ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10004       return -1;
10005    }
10006 
10007    ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10008    return 0;
10009 }

static int add_email_attachment ( FILE *  p,
struct ast_vm_user vmu,
char *  format,
char *  attach,
char *  greeting_attachment,
char *  mailbox,
char *  bound,
char *  filename,
int  last,
int  msgnum 
) [static]

Definition at line 4424 of file app_voicemail.c.

References ast_debug, ast_log(), ast_safe_system(), base_encode(), ast_vm_user::context, create_dirpath(), ENDL, LOG_WARNING, ast_vm_user::mailbox, VOICEMAIL_FILE_MODE, and ast_vm_user::volgain.

Referenced by make_email_file().

04425 {
04426    char tmpdir[256], newtmp[256];
04427    char fname[256];
04428    char tmpcmd[256];
04429    int tmpfd = -1;
04430 
04431    /* Eww. We want formats to tell us their own MIME type */
04432    char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04433 
04434    if (vmu->volgain < -.001 || vmu->volgain > .001) {
04435       create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04436       snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04437       tmpfd = mkstemp(newtmp);
04438       chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04439       ast_debug(3, "newtmp: %s\n", newtmp);
04440       if (tmpfd > -1) {
04441          int soxstatus;
04442          snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04443          if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04444             attach = newtmp;
04445             ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04446          } else {
04447             ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04448                soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04449             ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04450          }
04451       }
04452    }
04453    fprintf(p, "--%s" ENDL, bound);
04454    if (msgnum > -1)
04455       fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04456    else
04457       fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04458    fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04459    fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04460    if (msgnum > -1)
04461       fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04462    else
04463       fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04464    snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04465    base_encode(fname, p);
04466    if (last)
04467       fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04468    if (tmpfd > -1) {
04469       unlink(fname);
04470       close(tmpfd);
04471       unlink(newtmp);
04472    }
04473    return 0;
04474 }

static void adsi_begin ( struct ast_channel chan,
int *  useadsi 
) [static]

Definition at line 5910 of file app_voicemail.c.

References adsi_load_vmail(), adsifdn, adsiver, ast_adsi_available, ast_adsi_load_session, ast_log(), and AST_LOG_WARNING.

Referenced by vm_authenticate(), and vm_execmain().

05911 {
05912    int x;
05913    if (!ast_adsi_available(chan))
05914       return;
05915    x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
05916    if (x < 0)
05917       return;
05918    if (!x) {
05919       if (adsi_load_vmail(chan, useadsi)) {
05920          ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
05921          return;
05922       }
05923    } else
05924       *useadsi = 1;
05925 }

static void adsi_delete ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 6099 of file app_voicemail.c.

References ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_set_keys, ast_adsi_transmit_message, ast_adsi_voice_mode, vm_state::curmsg, vm_state::deleted, and vm_state::lastmsg.

Referenced by vm_execmain().

06100 {
06101    int bytes = 0;
06102    unsigned char buf[256];
06103    unsigned char keys[8];
06104 
06105    int x;
06106 
06107    if (!ast_adsi_available(chan))
06108       return;
06109 
06110    /* New meaning for keys */
06111    for (x = 0; x < 5; x++)
06112       keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06113 
06114    keys[6] = 0x0;
06115    keys[7] = 0x0;
06116 
06117    if (!vms->curmsg) {
06118       /* No prev key, provide "Folder" instead */
06119       keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06120    }
06121    if (vms->curmsg >= vms->lastmsg) {
06122       /* If last message ... */
06123       if (vms->curmsg) {
06124          /* but not only message, provide "Folder" instead */
06125          keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06126       } else {
06127          /* Otherwise if only message, leave blank */
06128          keys[3] = 1;
06129       }
06130    }
06131 
06132    /* If deleted, show "undeleted" */
06133    if (vms->deleted[vms->curmsg]) 
06134       keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06135 
06136    /* Except "Exit" */
06137    keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06138    bytes += ast_adsi_set_keys(buf + bytes, keys);
06139    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06140 
06141    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06142 }

static void adsi_folders ( struct ast_channel chan,
int  start,
char *  label 
) [static]

Definition at line 5975 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, and ast_adsi_voice_mode.

Referenced by vm_execmain().

05976 {
05977    unsigned char buf[256];
05978    int bytes = 0;
05979    unsigned char keys[8];
05980    int x, y;
05981 
05982    if (!ast_adsi_available(chan))
05983       return;
05984 
05985    for (x = 0; x < 5; x++) {
05986       y = ADSI_KEY_APPS + 12 + start + x;
05987       if (y > ADSI_KEY_APPS + 12 + 4)
05988          y = 0;
05989       keys[x] = ADSI_KEY_SKT | y;
05990    }
05991    keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
05992    keys[6] = 0;
05993    keys[7] = 0;
05994 
05995    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
05996    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
05997    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05998    bytes += ast_adsi_set_keys(buf + bytes, keys);
05999    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06000 
06001    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06002 }

static void adsi_goodbye ( struct ast_channel chan  )  [static]

Definition at line 6247 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, ADSI_JUST_LEFT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_set_line, ast_adsi_transmit_message, and ast_adsi_voice_mode.

Referenced by vm_execmain().

06248 {
06249    unsigned char buf[256];
06250    int bytes = 0;
06251 
06252    if (!ast_adsi_available(chan))
06253       return;
06254    bytes += adsi_logo(buf + bytes);
06255    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06256    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06257    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06258    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06259 
06260    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06261 }

static int adsi_load_vmail ( struct ast_channel chan,
int *  useadsi 
) [static]

Definition at line 5781 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, ADSI_JUST_LEFT, ADSI_KEY_APPS, adsi_logo(), ADSI_MSG_DISPLAY, ADSI_MSG_DOWNLOAD, adsifdn, adsisec, adsiver, ast_adsi_begin_download, ast_adsi_data_mode, ast_adsi_display, ast_adsi_download_disconnect, ast_adsi_end_download, ast_adsi_load_session, ast_adsi_load_soft_key, ast_adsi_set_line, ast_adsi_transmit_message, ast_adsi_voice_mode, ast_debug, mbox(), and num.

Referenced by adsi_begin().

05782 {
05783    unsigned char buf[256];
05784    int bytes = 0;
05785    int x;
05786    char num[5];
05787 
05788    *useadsi = 0;
05789    bytes += ast_adsi_data_mode(buf + bytes);
05790    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05791 
05792    bytes = 0;
05793    bytes += adsi_logo(buf);
05794    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05795 #ifdef DISPLAY
05796    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
05797 #endif
05798    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05799    bytes += ast_adsi_data_mode(buf + bytes);
05800    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05801 
05802    if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
05803       bytes = 0;
05804       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
05805       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05806       bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05807       bytes += ast_adsi_voice_mode(buf + bytes, 0);
05808       ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05809       return 0;
05810    }
05811 
05812 #ifdef DISPLAY
05813    /* Add a dot */
05814    bytes = 0;
05815    bytes += ast_adsi_logo(buf);
05816    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05817    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
05818    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05819    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05820 #endif
05821    bytes = 0;
05822    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
05823    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
05824    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
05825    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
05826    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
05827    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
05828    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05829 
05830 #ifdef DISPLAY
05831    /* Add another dot */
05832    bytes = 0;
05833    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
05834    bytes += ast_adsi_voice_mode(buf + bytes, 0);
05835 
05836    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05837    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05838 #endif
05839 
05840    bytes = 0;
05841    /* These buttons we load but don't use yet */
05842    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
05843    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
05844    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
05845    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
05846    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
05847    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
05848    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05849 
05850 #ifdef DISPLAY
05851    /* Add another dot */
05852    bytes = 0;
05853    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
05854    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05855    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05856 #endif
05857 
05858    bytes = 0;
05859    for (x = 0; x < 5; x++) {
05860       snprintf(num, sizeof(num), "%d", x);
05861       bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
05862    }
05863    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
05864    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05865 
05866 #ifdef DISPLAY
05867    /* Add another dot */
05868    bytes = 0;
05869    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
05870    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05871    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05872 #endif
05873 
05874    if (ast_adsi_end_download(chan)) {
05875       bytes = 0;
05876       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
05877       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05878       bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05879       bytes += ast_adsi_voice_mode(buf + bytes, 0);
05880       ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05881       return 0;
05882    }
05883    bytes = 0;
05884    bytes += ast_adsi_download_disconnect(buf + bytes);
05885    bytes += ast_adsi_voice_mode(buf + bytes, 0);
05886    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05887 
05888    ast_debug(1, "Done downloading scripts...\n");
05889 
05890 #ifdef DISPLAY
05891    /* Add last dot */
05892    bytes = 0;
05893    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
05894    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05895 #endif
05896    ast_debug(1, "Restarting session...\n");
05897 
05898    bytes = 0;
05899    /* Load the session now */
05900    if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
05901       *useadsi = 1;
05902       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
05903    } else
05904       bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
05905 
05906    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05907    return 0;
05908 }

static void adsi_login ( struct ast_channel chan  )  [static]

Definition at line 5927 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_DIR_FROM_LEFT, ADSI_JUST_CENT, ADSI_JUST_LEFT, ADSI_KEY_APPS, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_input_control, ast_adsi_input_format, ast_adsi_load_soft_key, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, and ast_adsi_voice_mode.

Referenced by vm_authenticate().

05928 {
05929    unsigned char buf[256];
05930    int bytes = 0;
05931    unsigned char keys[8];
05932    int x;
05933    if (!ast_adsi_available(chan))
05934       return;
05935 
05936    for (x = 0; x < 8; x++)
05937       keys[x] = 0;
05938    /* Set one key for next */
05939    keys[3] = ADSI_KEY_APPS + 3;
05940 
05941    bytes += adsi_logo(buf + bytes);
05942    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
05943    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
05944    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05945    bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
05946    bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
05947    bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
05948    bytes += ast_adsi_set_keys(buf + bytes, keys);
05949    bytes += ast_adsi_voice_mode(buf + bytes, 0);
05950    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05951 }

static int adsi_logo ( unsigned char *  buf  )  [static]

Definition at line 5773 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, and ast_adsi_display.

Referenced by adsi_goodbye(), adsi_load_vmail(), adsi_login(), vm_newuser(), vm_options(), and vm_tempgreeting().

05774 {
05775    int bytes = 0;
05776    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
05777    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
05778    return bytes;
05779 }

static void adsi_message ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 6004 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, ast_adsi_voice_mode, ast_callerid_parse(), ast_copy_string(), ast_strlen_zero(), buf1, buf2, vm_state::curbox, vm_state::curmsg, vm_state::deleted, vm_state::fn, vm_state::lastmsg, num, and strsep().

Referenced by play_message(), and vm_execmain().

06005 {
06006    int bytes = 0;
06007    unsigned char buf[256]; 
06008    char buf1[256], buf2[256];
06009    char fn2[PATH_MAX];
06010 
06011    char cid[256] = "";
06012    char *val;
06013    char *name, *num;
06014    char datetime[21] = "";
06015    FILE *f;
06016 
06017    unsigned char keys[8];
06018 
06019    int x;
06020 
06021    if (!ast_adsi_available(chan))
06022       return;
06023 
06024    /* Retrieve important info */
06025    snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06026    f = fopen(fn2, "r");
06027    if (f) {
06028       while (!feof(f)) {   
06029          if (!fgets((char *) buf, sizeof(buf), f)) {
06030             continue;
06031          }
06032          if (!feof(f)) {
06033             char *stringp = NULL;
06034             stringp = (char *) buf;
06035             strsep(&stringp, "=");
06036             val = strsep(&stringp, "=");
06037             if (!ast_strlen_zero(val)) {
06038                if (!strcmp((char *) buf, "callerid"))
06039                   ast_copy_string(cid, val, sizeof(cid));
06040                if (!strcmp((char *) buf, "origdate"))
06041                   ast_copy_string(datetime, val, sizeof(datetime));
06042             }
06043          }
06044       }
06045       fclose(f);
06046    }
06047    /* New meaning for keys */
06048    for (x = 0; x < 5; x++)
06049       keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06050    keys[6] = 0x0;
06051    keys[7] = 0x0;
06052 
06053    if (!vms->curmsg) {
06054       /* No prev key, provide "Folder" instead */
06055       keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06056    }
06057    if (vms->curmsg >= vms->lastmsg) {
06058       /* If last message ... */
06059       if (vms->curmsg) {
06060          /* but not only message, provide "Folder" instead */
06061          keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06062          bytes += ast_adsi_voice_mode(buf + bytes, 0);
06063 
06064       } else {
06065          /* Otherwise if only message, leave blank */
06066          keys[3] = 1;
06067       }
06068    }
06069 
06070    if (!ast_strlen_zero(cid)) {
06071       ast_callerid_parse(cid, &name, &num);
06072       if (!name)
06073          name = num;
06074    } else
06075       name = "Unknown Caller";
06076 
06077    /* If deleted, show "undeleted" */
06078 
06079    if (vms->deleted[vms->curmsg])
06080       keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06081 
06082    /* Except "Exit" */
06083    keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06084    snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06085       strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06086    snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06087 
06088    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06089    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06090    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06091    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06092    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06093    bytes += ast_adsi_set_keys(buf + bytes, keys);
06094    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06095 
06096    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06097 }

static void adsi_password ( struct ast_channel chan  )  [static]

Definition at line 5953 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_DIR_FROM_LEFT, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_input_control, ast_adsi_input_format, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, and ast_adsi_voice_mode.

Referenced by vm_authenticate().

05954 {
05955    unsigned char buf[256];
05956    int bytes = 0;
05957    unsigned char keys[8];
05958    int x;
05959    if (!ast_adsi_available(chan))
05960       return;
05961 
05962    for (x = 0; x < 8; x++)
05963       keys[x] = 0;
05964    /* Set one key for next */
05965    keys[3] = ADSI_KEY_APPS + 3;
05966 
05967    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05968    bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
05969    bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
05970    bytes += ast_adsi_set_keys(buf + bytes, keys);
05971    bytes += ast_adsi_voice_mode(buf + bytes, 0);
05972    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05973 }

static void adsi_status ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 6144 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, ast_adsi_voice_mode, buf1, buf2, vm_state::lastmsg, vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_execmain().

06145 {
06146    unsigned char buf[256] = "";
06147    char buf1[256] = "", buf2[256] = "";
06148    int bytes = 0;
06149    unsigned char keys[8];
06150    int x;
06151 
06152    char *newm = (vms->newmessages == 1) ? "message" : "messages";
06153    char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06154    if (!ast_adsi_available(chan))
06155       return;
06156    if (vms->newmessages) {
06157       snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06158       if (vms->oldmessages) {
06159          strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06160          snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06161       } else {
06162          snprintf(buf2, sizeof(buf2), "%s.", newm);
06163       }
06164    } else if (vms->oldmessages) {
06165       snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06166       snprintf(buf2, sizeof(buf2), "%s.", oldm);
06167    } else {
06168       strcpy(buf1, "You have no messages.");
06169       buf2[0] = ' ';
06170       buf2[1] = '\0';
06171    }
06172    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06173    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06174    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06175 
06176    for (x = 0; x < 6; x++)
06177       keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06178    keys[6] = 0;
06179    keys[7] = 0;
06180 
06181    /* Don't let them listen if there are none */
06182    if (vms->lastmsg < 0)
06183       keys[0] = 1;
06184    bytes += ast_adsi_set_keys(buf + bytes, keys);
06185 
06186    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06187 
06188    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06189 }

static void adsi_status2 ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 6191 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available, ast_adsi_display, ast_adsi_set_keys, ast_adsi_set_line, ast_adsi_transmit_message, ast_adsi_voice_mode, buf1, buf2, vm_state::curbox, and vm_state::lastmsg.

Referenced by vm_execmain().

06192 {
06193    unsigned char buf[256] = "";
06194    char buf1[256] = "", buf2[256] = "";
06195    int bytes = 0;
06196    unsigned char keys[8];
06197    int x;
06198 
06199    char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06200 
06201    if (!ast_adsi_available(chan))
06202       return;
06203 
06204    /* Original command keys */
06205    for (x = 0; x < 6; x++)
06206       keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06207 
06208    keys[6] = 0;
06209    keys[7] = 0;
06210 
06211    if ((vms->lastmsg + 1) < 1)
06212       keys[0] = 0;
06213 
06214    snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06215       strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06216 
06217    if (vms->lastmsg + 1)
06218       snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06219    else
06220       strcpy(buf2, "no messages.");
06221    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06222    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06223    bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06224    bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06225    bytes += ast_adsi_set_keys(buf + bytes, keys);
06226 
06227    bytes += ast_adsi_voice_mode(buf + bytes, 0);
06228 
06229    ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06230    
06231 }

static int advanced_options ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
int  msg,
int  option,
signed char  record_gain 
) [static]

The advanced options within a message.

Parameters:
chan 
vmu 
vms 
msg 
option 
record_gain Provides handling for the play message envelope, call the person back, or reply to message.
Returns:
zero on success, -1 on error.

Definition at line 11473 of file app_voicemail.c.

References ast_callerid_parse(), ast_config_destroy(), ast_config_load, ast_log(), AST_LOG_WARNING, AST_MAX_EXTENSION, ast_play_and_wait(), ast_strdupa, ast_strlen_zero(), ast_variable_retrieve(), ast_verb, ast_waitfordigit(), ast_vm_user::callback, CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, ast_vm_user::dialout, dialout(), DISPOSE, find_user(), vm_state::fn, vm_state::heard, leave_voicemail(), ast_vm_user::mailbox, make_file(), num, play_message_callerid(), play_message_datetime(), leave_vm_options::record_gain, RETRIEVE, vm_state::starting, and wait_file().

Referenced by vm_execmain().

11474 {
11475    int res = 0;
11476    char filename[PATH_MAX];
11477    struct ast_config *msg_cfg = NULL;
11478    const char *origtime, *context;
11479    char *name, *num;
11480    int retries = 0;
11481    char *cid;
11482    struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
11483 
11484    vms->starting = 0; 
11485 
11486    make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11487 
11488    /* Retrieve info from VM attribute file */
11489    snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
11490    RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
11491    msg_cfg = ast_config_load(filename, config_flags);
11492    DISPOSE(vms->curdir, vms->curmsg);
11493    if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
11494       ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
11495       return 0;
11496    }
11497 
11498    if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
11499       ast_config_destroy(msg_cfg);
11500       return 0;
11501    }
11502 
11503    cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
11504 
11505    context = ast_variable_retrieve(msg_cfg, "message", "context");
11506    if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
11507       context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
11508    switch (option) {
11509    case 3: /* Play message envelope */
11510       if (!res)
11511          res = play_message_datetime(chan, vmu, origtime, filename);
11512       if (!res)
11513          res = play_message_callerid(chan, vms, cid, context, 0);
11514 
11515       res = 't';
11516       break;
11517 
11518    case 2:  /* Call back */
11519 
11520       if (ast_strlen_zero(cid))
11521          break;
11522 
11523       ast_callerid_parse(cid, &name, &num);
11524       while ((res > -1) && (res != 't')) {
11525          switch (res) {
11526          case '1':
11527             if (num) {
11528                /* Dial the CID number */
11529                res = dialout(chan, vmu, num, vmu->callback);
11530                if (res) {
11531                   ast_config_destroy(msg_cfg);
11532                   return 9;
11533                }
11534             } else {
11535                res = '2';
11536             }
11537             break;
11538 
11539          case '2':
11540             /* Want to enter a different number, can only do this if there's a dialout context for this user */
11541             if (!ast_strlen_zero(vmu->dialout)) {
11542                res = dialout(chan, vmu, NULL, vmu->dialout);
11543                if (res) {
11544                   ast_config_destroy(msg_cfg);
11545                   return 9;
11546                }
11547             } else {
11548                ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
11549                res = ast_play_and_wait(chan, "vm-sorry");
11550             }
11551             ast_config_destroy(msg_cfg);
11552             return res;
11553          case '*':
11554             res = 't';
11555             break;
11556          case '3':
11557          case '4':
11558          case '5':
11559          case '6':
11560          case '7':
11561          case '8':
11562          case '9':
11563          case '0':
11564 
11565             res = ast_play_and_wait(chan, "vm-sorry");
11566             retries++;
11567             break;
11568          default:
11569             if (num) {
11570                ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
11571                res = ast_play_and_wait(chan, "vm-num-i-have");
11572                if (!res)
11573                   res = play_message_callerid(chan, vms, num, vmu->context, 1);
11574                if (!res)
11575                   res = ast_play_and_wait(chan, "vm-tocallnum");
11576                /* Only prompt for a caller-specified number if there is a dialout context specified */
11577                if (!ast_strlen_zero(vmu->dialout)) {
11578                   if (!res)
11579                      res = ast_play_and_wait(chan, "vm-calldiffnum");
11580                }
11581             } else {
11582                res = ast_play_and_wait(chan, "vm-nonumber");
11583                if (!ast_strlen_zero(vmu->dialout)) {
11584                   if (!res)
11585                      res = ast_play_and_wait(chan, "vm-toenternumber");
11586                }
11587             }
11588             if (!res)
11589                res = ast_play_and_wait(chan, "vm-star-cancel");
11590             if (!res)
11591                res = ast_waitfordigit(chan, 6000);
11592             if (!res) {
11593                retries++;
11594                if (retries > 3)
11595                   res = 't';
11596             }
11597             break; 
11598             
11599          }
11600          if (res == 't')
11601             res = 0;
11602          else if (res == '*')
11603             res = -1;
11604       }
11605       break;
11606       
11607    case 1:  /* Reply */
11608       /* Send reply directly to sender */
11609       if (ast_strlen_zero(cid))
11610          break;
11611 
11612       ast_callerid_parse(cid, &name, &num);
11613       if (!num) {
11614          ast_verb(3, "No CID number available, no reply sent\n");
11615          if (!res)
11616             res = ast_play_and_wait(chan, "vm-nonumber");
11617          ast_config_destroy(msg_cfg);
11618          return res;
11619       } else {
11620          struct ast_vm_user vmu2;
11621          if (find_user(&vmu2, vmu->context, num)) {
11622             struct leave_vm_options leave_options;
11623             char mailbox[AST_MAX_EXTENSION * 2 + 2];
11624             snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
11625 
11626             ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
11627             
11628             memset(&leave_options, 0, sizeof(leave_options));
11629             leave_options.record_gain = record_gain;
11630             res = leave_voicemail(chan, mailbox, &leave_options);
11631             if (!res)
11632                res = 't';
11633             ast_config_destroy(msg_cfg);
11634             return res;
11635          } else {
11636             /* Sender has no mailbox, can't reply */
11637             ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
11638             ast_play_and_wait(chan, "vm-nobox");
11639             res = 't';
11640             ast_config_destroy(msg_cfg);
11641             return res;
11642          }
11643       } 
11644       res = 0;
11645 
11646       break;
11647    }
11648 
11649 #ifndef IMAP_STORAGE
11650    ast_config_destroy(msg_cfg);
11651 
11652    if (!res) {
11653       make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11654       vms->heard[msg] = 1;
11655       res = wait_file(chan, vms, vms->fn);
11656    }
11657 #endif
11658    return res;
11659 }

static int append_mailbox ( const char *  context,
const char *  box,
const char *  data 
) [static]

Definition at line 9900 of file app_voicemail.c.

References apply_options(), ast_copy_string(), ast_strdupa, ast_vm_user::context, ast_vm_user::email, find_or_create(), ast_vm_user::fullname, inboxcount2(), ast_vm_user::mailbox, OPT_PWLOC_SPOOLDIR, ast_vm_user::pager, ast_vm_user::password, ast_vm_user::passwordlocation, populate_defaults(), queue_mwi_event(), read_password_from_file(), s, and strsep().

Referenced by load_config().

09901 {
09902    /* Assumes lock is already held */
09903    char *tmp;
09904    char *stringp;
09905    char *s;
09906    struct ast_vm_user *vmu;
09907    char *mailbox_full;
09908    int new = 0, old = 0, urgent = 0;
09909    char secretfn[PATH_MAX] = "";
09910 
09911    tmp = ast_strdupa(data);
09912 
09913    if (!(vmu = find_or_create(context, box)))
09914       return -1;
09915 
09916    populate_defaults(vmu);
09917 
09918    stringp = tmp;
09919    if ((s = strsep(&stringp, ","))) {
09920       ast_copy_string(vmu->password, s, sizeof(vmu->password));
09921    }
09922    if (stringp && (s = strsep(&stringp, ","))) {
09923       ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
09924    }
09925    if (stringp && (s = strsep(&stringp, ","))) {
09926       ast_copy_string(vmu->email, s, sizeof(vmu->email));
09927    }
09928    if (stringp && (s = strsep(&stringp, ","))) {
09929       ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
09930    }
09931    if (stringp && (s = strsep(&stringp, ","))) {
09932       apply_options(vmu, s);
09933    }
09934 
09935    switch (vmu->passwordlocation) {
09936    case OPT_PWLOC_SPOOLDIR:
09937       snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
09938       read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
09939    }
09940 
09941    mailbox_full = alloca(strlen(box) + strlen(context) + 1);
09942    strcpy(mailbox_full, box);
09943    strcat(mailbox_full, "@");
09944    strcat(mailbox_full, context);
09945 
09946    inboxcount2(mailbox_full, &urgent, &new, &old);
09947    queue_mwi_event(mailbox_full, urgent, new, old);
09948 
09949    return 0;
09950 }

static void apply_option ( struct ast_vm_user vmu,
const char *  var,
const char *  value 
) [static]

Sets a a specific property value.

Parameters:
vmu The voicemail user object to work with.
var The name of the property to be set.
value The value to be set to the property.
The property name must be one of the understood properties. See the source for details.

Definition at line 914 of file app_voicemail.c.

References apply_options(), ast_copy_string(), ast_log(), AST_LOG_WARNING, ast_set2_flag, ast_true(), ast_vm_user::attachfmt, ast_vm_user::callback, ast_vm_user::dialout, ast_vm_user::exit, ast_vm_user::language, ast_vm_user::maxdeletedmsg, MAXMSG, ast_vm_user::maxmsg, MAXMSGLIMIT, ast_vm_user::maxsecs, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_VOICEMAILCONF, ast_vm_user::passwordlocation, ast_vm_user::saydurationm, ast_vm_user::serveremail, VM_ATTACH, VM_DELETE, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_MESSAGEWRAP, VM_MOVEHEARD, VM_OPERATOR, VM_REVIEW, VM_SAYCID, VM_SAYDURATION, VM_SVMAIL, VM_TEMPGREETWARN, ast_vm_user::volgain, and ast_vm_user::zonetag.

Referenced by apply_options(), and apply_options_full().

00915 {
00916    int x;
00917    if (!strcasecmp(var, "attach")) {
00918       ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00919    } else if (!strcasecmp(var, "attachfmt")) {
00920       ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00921    } else if (!strcasecmp(var, "serveremail")) {
00922       ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00923    } else if (!strcasecmp(var, "language")) {
00924       ast_copy_string(vmu->language, value, sizeof(vmu->language));
00925    } else if (!strcasecmp(var, "tz")) {
00926       ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00927 #ifdef IMAP_STORAGE
00928    } else if (!strcasecmp(var, "imapuser")) {
00929       ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00930       vmu->imapversion = imapversion;
00931    } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00932       ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00933       vmu->imapversion = imapversion;
00934    } else if (!strcasecmp(var, "imapvmshareid")) {
00935       ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00936       vmu->imapversion = imapversion;
00937 #endif
00938    } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00939       ast_set2_flag(vmu, ast_true(value), VM_DELETE); 
00940    } else if (!strcasecmp(var, "saycid")){
00941       ast_set2_flag(vmu, ast_true(value), VM_SAYCID); 
00942    } else if (!strcasecmp(var, "sendvoicemail")){
00943       ast_set2_flag(vmu, ast_true(value), VM_SVMAIL); 
00944    } else if (!strcasecmp(var, "review")){
00945       ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00946    } else if (!strcasecmp(var, "tempgreetwarn")){
00947       ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);   
00948    } else if (!strcasecmp(var, "messagewrap")){
00949       ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);  
00950    } else if (!strcasecmp(var, "operator")) {
00951       ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);  
00952    } else if (!strcasecmp(var, "envelope")){
00953       ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);  
00954    } else if (!strcasecmp(var, "moveheard")){
00955       ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
00956    } else if (!strcasecmp(var, "sayduration")){
00957       ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);  
00958    } else if (!strcasecmp(var, "saydurationm")){
00959       if (sscanf(value, "%30d", &x) == 1) {
00960          vmu->saydurationm = x;
00961       } else {
00962          ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
00963       }
00964    } else if (!strcasecmp(var, "forcename")){
00965       ast_set2_flag(vmu, ast_true(value), VM_FORCENAME); 
00966    } else if (!strcasecmp(var, "forcegreetings")){
00967       ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);   
00968    } else if (!strcasecmp(var, "callback")) {
00969       ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00970    } else if (!strcasecmp(var, "dialout")) {
00971       ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00972    } else if (!strcasecmp(var, "exitcontext")) {
00973       ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00974    } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
00975       vmu->maxsecs = atoi(value);
00976       if (vmu->maxsecs <= 0) {
00977          ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
00978          vmu->maxsecs = vmmaxsecs;
00979       } else {
00980          vmu->maxsecs = atoi(value);
00981       }
00982       if (!strcasecmp(var, "maxmessage"))
00983          ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'.  Please make that change in your voicemail config.\n");
00984    } else if (!strcasecmp(var, "maxmsg")) {
00985       vmu->maxmsg = atoi(value);
00986       if (vmu->maxmsg <= 0) {
00987          ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
00988          vmu->maxmsg = MAXMSG;
00989       } else if (vmu->maxmsg > MAXMSGLIMIT) {
00990          ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00991          vmu->maxmsg = MAXMSGLIMIT;
00992       }
00993    } else if (!strcasecmp(var, "backupdeleted")) {
00994       if (sscanf(value, "%30d", &x) == 1)
00995          vmu->maxdeletedmsg = x;
00996       else if (ast_true(value))
00997          vmu->maxdeletedmsg = MAXMSG;
00998       else
00999          vmu->maxdeletedmsg = 0;
01000 
01001       if (vmu->maxdeletedmsg < 0) {
01002          ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01003          vmu->maxdeletedmsg = MAXMSG;
01004       } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01005          ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01006          vmu->maxdeletedmsg = MAXMSGLIMIT;
01007       }
01008    } else if (!strcasecmp(var, "volgain")) {
01009       sscanf(value, "%30lf", &vmu->volgain);
01010    } else if (!strcasecmp(var, "passwordlocation")) {
01011       if (!strcasecmp(value, "spooldir")) {
01012          vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01013       } else {
01014          vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01015       }
01016    } else if (!strcasecmp(var, "options")) {
01017       apply_options(vmu, value);
01018    }
01019 }

static void apply_options ( struct ast_vm_user vmu,
const char *  options 
) [static]

Destructively Parse options and apply.

Definition at line 1133 of file app_voicemail.c.

References apply_option(), ast_strdupa, s, strsep(), value, and var.

Referenced by append_mailbox(), and apply_option().

01134 {  
01135    char *stringp;
01136    char *s;
01137    char *var, *value;
01138    stringp = ast_strdupa(options);
01139    while ((s = strsep(&stringp, "|"))) {
01140       value = s;
01141       if ((var = strsep(&value, "=")) && value) {
01142          apply_option(vmu, var, value);
01143       }
01144    }  
01145 }

static void apply_options_full ( struct ast_vm_user retval,
struct ast_variable var 
) [static]

Loads the options specific to a voicemail user.

This is called when a vm_user structure is being set up, such as from load_options.

Definition at line 1152 of file app_voicemail.c.

References apply_option(), ast_copy_string(), ast_strdup, ast_strlen_zero(), ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::fullname, ast_variable::name, ast_variable::next, ast_vm_user::pager, ast_vm_user::password, ast_vm_user::uniqueid, and ast_variable::value.

Referenced by find_user_realtime(), and load_config().

01153 {
01154    for (; var; var = var->next) {
01155       if (!strcasecmp(var->name, "vmsecret")) {
01156          ast_copy_string(retval->password, var->value, sizeof(retval->password));
01157       } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
01158          if (ast_strlen_zero(retval->password))
01159             ast_copy_string(retval->password, var->value, sizeof(retval->password));
01160       } else if (!strcasecmp(var->name, "uniqueid")) {
01161          ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01162       } else if (!strcasecmp(var->name, "pager")) {
01163          ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01164       } else if (!strcasecmp(var->name, "email")) {
01165          ast_copy_string(retval->email, var->value, sizeof(retval->email));
01166       } else if (!strcasecmp(var->name, "fullname")) {
01167          ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01168       } else if (!strcasecmp(var->name, "context")) {
01169          ast_copy_string(retval->context, var->value, sizeof(retval->context));
01170       } else if (!strcasecmp(var->name, "emailsubject")) {
01171          retval->emailsubject = ast_strdup(var->value);
01172       } else if (!strcasecmp(var->name, "emailbody")) {
01173          retval->emailbody = ast_strdup(var->value);
01174 #ifdef IMAP_STORAGE
01175       } else if (!strcasecmp(var->name, "imapuser")) {
01176          ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01177          retval->imapversion = imapversion;
01178       } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01179          ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01180          retval->imapversion = imapversion;
01181       } else if (!strcasecmp(var->name, "imapvmshareid")) {
01182          ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01183          retval->imapversion = imapversion;
01184 #endif
01185       } else
01186          apply_option(retval, var->name, var->value);
01187    }
01188 }

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

Encode a string according to the MIME rules for encoding strings that are not 7-bit clean or contain control characters.

Additionally, if the encoded string would exceed the MIME limit of 76 characters per line, then the encoding will be broken up into multiple sections, separated by a space character, in order to facilitate breaking up the associated header across multiple lines.

Parameters:
end An expandable buffer for holding the result
maxlen Always zero, but see
See also:
ast_str
Parameters:
start A string to be encoded
preamble The length of the first line already used for this string, to ensure that each line maintains a maximum length of 76 chars.
postamble the length of any additional characters appended to the line, used to ensure proper field wrapping.
Return values:
The encoded string.

Definition at line 4112 of file app_voicemail.c.

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

04113 {
04114    struct ast_str *tmp = ast_str_alloca(80);
04115    int first_section = 1;
04116 
04117    ast_str_reset(*end);
04118    ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04119    for (; *start; start++) {
04120       int need_encoding = 0;
04121       if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04122          need_encoding = 1;
04123       }
04124       if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04125          (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04126          (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04127          (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04128          /* Start new line */
04129          ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04130          ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04131          first_section = 0;
04132       }
04133       if (need_encoding && *start == ' ') {
04134          ast_str_append(&tmp, -1, "_");
04135       } else if (need_encoding) {
04136          ast_str_append(&tmp, -1, "=%hhX", *start);
04137       } else {
04138          ast_str_append(&tmp, -1, "%c", *start);
04139       }
04140    }
04141    ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04142    return ast_str_buffer(*end);
04143 }

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

Wraps a character sequence in double quotes, escaping occurences of quotes within the string.

Parameters:
from The string to work with.
buf The buffer into which to write the modified quoted string.
maxlen Always zero, but see
See also:
ast_str
Returns:
The destination string with quotes wrapped on it (the to field).

Definition at line 4040 of file app_voicemail.c.

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

04041 {
04042    const char *ptr;
04043 
04044    /* We're only ever passing 0 to maxlen, so short output isn't possible */
04045    ast_str_set(buf, maxlen, "\"");
04046    for (ptr = from; *ptr; ptr++) {
04047       if (*ptr == '"' || *ptr == '\\') {
04048          ast_str_append(buf, maxlen, "\\%c", *ptr);
04049       } else {
04050          ast_str_append(buf, maxlen, "%c", *ptr);
04051       }
04052    }
04053    ast_str_append(buf, maxlen, "\"");
04054 
04055    return ast_str_buffer(*buf);
04056 }

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

Performs a base 64 encode algorithm on the contents of a File.

Parameters:
filename The path to the file to be encoded. Must be readable, file is opened in read mode.
so A FILE handle to the output file to receive the base 64 encoded contents of the input file, identified by filename.
TODO: shouldn't this (and the above 3 support functions) be put into some kind of external utility location, such as funcs/func_base64.c ?

Returns:
zero on success, -1 on error.

Definition at line 3917 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, BASEMAXINLINE, eol, errno, inchar(), baseio::iocp, and ochar().

03918 {
03919    static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
03920       'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
03921       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
03922       '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
03923    int i, hiteof = 0;
03924    FILE *fi;
03925    struct baseio bio;
03926 
03927    memset(&bio, 0, sizeof(bio));
03928    bio.iocp = BASEMAXINLINE;
03929 
03930    if (!(fi = fopen(filename, "rb"))) {
03931       ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03932       return -1;
03933    }
03934 
03935    while (!hiteof){
03936       unsigned char igroup[3], ogroup[4];
03937       int c, n;
03938 
03939       memset(igroup, 0, sizeof(igroup));
03940 
03941       for (n = 0; n < 3; n++) {
03942          if ((c = inchar(&bio, fi)) == EOF) {
03943             hiteof = 1;
03944             break;
03945          }
03946 
03947          igroup[n] = (unsigned char) c;
03948       }
03949 
03950       if (n > 0) {
03951          ogroup[0]= dtable[igroup[0] >> 2];
03952          ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
03953          ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
03954          ogroup[3]= dtable[igroup[2] & 0x3F];
03955 
03956          if (n < 3) {
03957             ogroup[3] = '=';
03958 
03959             if (n < 2)
03960                ogroup[2] = '=';
03961          }
03962 
03963          for (i = 0; i < 4; i++)
03964             ochar(&bio, ogroup[i], so);
03965       }
03966    }
03967 
03968    fclose(fi);
03969    
03970    if (fputs(eol, so) == EOF)
03971       return 0;
03972 
03973    return 1;
03974 }

static int change_password_realtime ( struct ast_vm_user vmu,
const char *  password 
) [static]

Performs a change of the voicemail passowrd in the realtime engine.

Parameters:
vmu The voicemail user to change the password for.
password The new value to be set to the password for this user.
This only works if there is a realtime engine configured. This is called from the (top level) vm_change_password.

Returns:
zero on success, -1 on error.

Definition at line 1112 of file app_voicemail.c.

References ast_copy_string(), ast_realtime_require_field(), ast_update2_realtime(), ast_vm_user::context, ast_vm_user::mailbox, ast_vm_user::password, RQ_CHAR, and SENTINEL.

Referenced by vm_change_password().

01113 {
01114    int res = -1;
01115    if (!strcmp(vmu->password, password)) {
01116       /* No change (but an update would return 0 rows updated, so we opt out here) */
01117       return 0;
01118    }
01119 
01120    if (strlen(password) > 10) {
01121       ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01122    }
01123    if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01124       ast_copy_string(vmu->password, password, sizeof(vmu->password));
01125       res = 0;
01126    }
01127    return res;
01128 }

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

Check if the string would need encoding within the MIME standard, to avoid confusing certain mail software that expects messages to be 7-bit clean.

Definition at line 4085 of file app_voicemail.c.

04086 {
04087    for (; *str; str++) {
04088       if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04089          return 1;
04090       }
04091    }
04092    return 0;
04093 }

static int check_password ( struct ast_vm_user vmu,
char *  password 
) [static]

Check that password meets minimum required length.

Parameters:
vmu The voicemail user to change the password for.
password The password string to check
Returns:
zero on ok, 1 on not ok.

Definition at line 1074 of file app_voicemail.c.

References ast_debug, ast_log(), AST_LOG_DEBUG, AST_LOG_NOTICE, AST_LOG_WARNING, ast_strlen_zero(), buf, ast_vm_user::context, ast_vm_user::mailbox, ast_vm_user::password, and vm_check_password_shell().

Referenced by network_thread(), vm_newuser(), and vm_options().

01075 {
01076    /* check minimum length */
01077    if (strlen(password) < minpassword)
01078       return 1;
01079    if (!ast_strlen_zero(ext_pass_check_cmd)) {
01080       char cmd[255], buf[255];
01081 
01082       ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01083 
01084       snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01085       if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01086          ast_debug(5, "Result: %s\n", buf);
01087          if (!strncasecmp(buf, "VALID", 5)) {
01088             ast_debug(3, "Passed password check: '%s'\n", buf);
01089             return 0;
01090          } else if (!strncasecmp(buf, "FAILURE", 7)) {
01091             ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01092             return 0;
01093          } else {
01094             ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01095             return 1;
01096          }
01097       }
01098    }
01099    return 0;
01100 }

static int close_mailbox ( struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Definition at line 7300 of file app_voicemail.c.

References ast_check_realtime(), ast_debug, ast_log(), AST_LOG_WARNING, ast_test_flag, ast_unlock_path(), ast_vm_user::context, vm_state::curbox, vm_state::curdir, vm_state::curmsg, DELETE, vm_state::deleted, ERROR_LOCK_PATH, EXISTS, vm_state::fn, vm_state::heard, vm_state::lastmsg, ast_vm_user::mailbox, make_file(), ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, RENAME, save_to_folder(), vm_lock_path(), and VM_MOVEHEARD.

Referenced by vm_execmain().

07301 {
07302    int x = 0;
07303 #ifndef IMAP_STORAGE
07304    int res = 0, nummsg;
07305    char fn2[PATH_MAX];
07306 #endif
07307 
07308    if (vms->lastmsg <= -1)
07309       goto done;
07310 
07311    vms->curmsg = -1; 
07312 #ifndef IMAP_STORAGE
07313    /* Get the deleted messages fixed */ 
07314    if (vm_lock_path(vms->curdir))
07315       return ERROR_LOCK_PATH;
07316 
07317    for (x = 0; x < vmu->maxmsg; x++) { 
07318       if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) { 
07319          /* Save this message.  It's not in INBOX or hasn't been heard */ 
07320          make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); 
07321          if (!EXISTS(vms->curdir, x, vms->fn, NULL)) 
07322             break;
07323          vms->curmsg++; 
07324          make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg); 
07325          if (strcmp(vms->fn, fn2)) { 
07326             RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07327          } 
07328       } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) { 
07329          /* Move to old folder before deleting */ 
07330          res = save_to_folder(vmu, vms, x, 1);
07331          if (res == ERROR_LOCK_PATH) {
07332             /* If save failed do not delete the message */
07333             ast_log(AST_LOG_WARNING, "Save failed.  Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07334             vms->deleted[x] = 0;
07335             vms->heard[x] = 0;
07336             --x;
07337          }
07338       } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07339          /* Move to deleted folder */ 
07340          res = save_to_folder(vmu, vms, x, 10);
07341          if (res == ERROR_LOCK_PATH) {
07342             /* If save failed do not delete the message */
07343             vms->deleted[x] = 0;
07344             vms->heard[x] = 0;
07345             --x;
07346          }
07347       } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07348          /* If realtime storage enabled - we should explicitly delete this message,
07349          cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */
07350          make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07351          if (EXISTS(vms->curdir, x, vms->fn, NULL))
07352             DELETE(vms->curdir, x, vms->fn, vmu);
07353       }
07354    } 
07355 
07356    /* Delete ALL remaining messages */
07357    nummsg = x - 1;
07358    for (x = vms->curmsg + 1; x <= nummsg; x++) {
07359       make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07360       if (EXISTS(vms->curdir, x, vms->fn, NULL))
07361          DELETE(vms->curdir, x, vms->fn, vmu);
07362    }
07363    ast_unlock_path(vms->curdir);
07364 #else
07365    if (vms->deleted) {
07366       for (x = 0; x < vmu->maxmsg; x++) { 
07367          if (vms->deleted[x]) { 
07368             ast_debug(3, "IMAP delete of %d\n", x);
07369             DELETE(vms->curdir, x, vms->fn, vmu);
07370          }
07371       }
07372    }
07373 #endif
07374 
07375 done:
07376    if (vms->deleted)
07377       memset(vms->deleted, 0, vmu->maxmsg * sizeof(int)); 
07378    if (vms->heard)
07379       memset(vms->heard, 0, vmu->maxmsg * sizeof(int)); 
07380 
07381    return 0;
07382 }

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

Definition at line 10091 of file app_voicemail.c.

References AST_LIST_TRAVERSE, ast_strdup, and ast_vm_user::context.

Referenced by handle_voicemail_show_users().

10092 {
10093    int which = 0;
10094    int wordlen;
10095    struct ast_vm_user *vmu;
10096    const char *context = "";
10097 
10098    /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
10099    if (pos > 4)
10100       return NULL;
10101    if (pos == 3)
10102       return (state == 0) ? ast_strdup("for") : NULL;
10103    wordlen = strlen(word);
10104    AST_LIST_TRAVERSE(&users, vmu, list) {
10105       if (!strncasecmp(word, vmu->context, wordlen)) {
10106          if (context && strcmp(context, vmu->context) && ++which > state)
10107             return ast_strdup(vmu->context);
10108          /* ignore repeated contexts ? */
10109          context = vmu->context;
10110       }
10111    }
10112    return NULL;
10113 }

static int copy ( char *  infile,
char *  outfile 
) [static]

Utility function to copy a file.

Parameters:
infile The path to the file to be copied. The file must be readable, it is opened in read only mode.
outfile The path for which to copy the file to. The directory permissions must allow the creation (or truncation) of the file, and allow for opening the file in write only mode.
When the compiler option HARDLINK_WHEN_POSSIBLE is set, the copy operation will attempt to use the hard link facility instead of copy the file (to save disk space). If the link operation fails, it falls back to the copy operation. The copy operation copies up to 4096 bytes at once.

Returns:
zero on success, -1 on error.

Definition at line 3723 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, errno, and VOICEMAIL_FILE_MODE.

Referenced by ast_filehelper(), ast_func_read(), ast_func_read2(), ast_func_write(), copy_plain_file(), and iax2_register().

03724 {
03725    int ifd;
03726    int ofd;
03727    int res;
03728    int len;
03729    char buf[4096];
03730 
03731 #ifdef HARDLINK_WHEN_POSSIBLE
03732    /* Hard link if possible; saves disk space & is faster */
03733    if (link(infile, outfile)) {
03734 #endif
03735       if ((ifd = open(infile, O_RDONLY)) < 0) {
03736          ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03737          return -1;
03738       }
03739       if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03740          ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03741          close(ifd);
03742          return -1;
03743       }
03744       do {
03745          len = read(ifd, buf, sizeof(buf));
03746          if (len < 0) {
03747             ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03748             close(ifd);
03749             close(ofd);
03750             unlink(outfile);
03751          }
03752          if (len) {
03753             res = write(ofd, buf, len);
03754             if (errno == ENOMEM || errno == ENOSPC || res != len) {
03755                ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03756                close(ifd);
03757                close(ofd);
03758                unlink(outfile);
03759             }
03760          }
03761       } while (len);
03762       close(ifd);
03763       close(ofd);
03764       return 0;
03765 #ifdef HARDLINK_WHEN_POSSIBLE
03766    } else {
03767       /* Hard link succeeded */
03768       return 0;
03769    }
03770 #endif
03771 }

static int copy_message ( struct ast_channel chan,
struct ast_vm_user vmu,
int  imbox,
int  msgnum,
long  duration,
struct ast_vm_user recip,
char *  fmt,
char *  dir,
const char *  flag 
) [static]

Copies a message from one mailbox to another.

Parameters:
chan 
vmu 
imbox 
msgnum 
duration 
recip 
fmt 
dir This is only used by file storage based mailboxes.
Returns:
zero on success, -1 on error.

Definition at line 4935 of file app_voicemail.c.

References ast_copy_string(), ast_log(), AST_LOG_ERROR, AST_LOG_NOTICE, ast_strlen_zero(), ast_unlock_path(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_vm_user::context, COPY, copy_plain_file(), create_dirpath(), ERROR_LOCK_PATH, EXISTS, ast_channel::language, last_message_index(), ast_vm_user::mailbox, make_dir(), make_file(), mbox(), notify_new_message(), S_OR, STORE, vm_delete(), and vm_lock_path().

Referenced by forward_message(), and leave_voicemail().

04936 {
04937    char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04938    const char *frombox = mbox(imbox);
04939    int recipmsgnum;
04940 
04941    ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04942 
04943    if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
04944       create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
04945    } else {
04946       create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04947    }
04948    
04949    if (!dir)
04950       make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04951    else
04952       ast_copy_string(fromdir, dir, sizeof(fromdir));
04953 
04954    make_file(frompath, sizeof(frompath), fromdir, msgnum);
04955    make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04956 
04957    if (vm_lock_path(todir))
04958       return ERROR_LOCK_PATH;
04959 
04960    recipmsgnum = last_message_index(recip, todir) + 1;
04961    if (recipmsgnum < recip->maxmsg) {
04962       make_file(topath, sizeof(topath), todir, recipmsgnum);
04963       if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04964          COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04965       } else {
04966          /* For ODBC storage, if the file we want to copy isn't yet in the database, then the SQL
04967           * copy will fail. Instead, we need to create a local copy, store it, and delete the local
04968           * copy. We don't have to #ifdef this because if file storage reaches this point, there's a
04969           * much worse problem happening and IMAP storage doesn't call this function
04970           */
04971          copy_plain_file(frompath, topath);
04972          STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
04973          vm_delete(topath);
04974       }
04975    } else {
04976       ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04977    }
04978    ast_unlock_path(todir);
04979    notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
04980    
04981    return 0;
04982 }

static void copy_plain_file ( char *  frompath,
char *  topath 
) [static]

Copies a voicemail information (envelope) file.

Parameters:
frompath 
topath 
Every voicemail has the data (.wav) file, and the information file. This function performs the file system copying of the information file for a voicemail, handling the internal fields and their values. This is used by the COPY macro when not using IMAP storage.

Definition at line 3782 of file app_voicemail.c.

References ast_check_realtime(), ast_filecopy(), ast_load_realtime(), ast_store_realtime(), ast_variables_destroy(), copy(), exten, ast_variable::name, ast_variable::next, SENTINEL, and ast_variable::value.

Referenced by copy_message().

03783 {
03784    char frompath2[PATH_MAX], topath2[PATH_MAX];
03785    struct ast_variable *tmp,*var = NULL;
03786    const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
03787    ast_filecopy(frompath, topath, NULL);
03788    snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03789    snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03790    if (ast_check_realtime("voicemail_data")) {
03791       var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
03792       /* This cycle converts ast_variable linked list, to va_list list of arguments, may be there is a better way to do it? */
03793       for (tmp = var; tmp; tmp = tmp->next) {
03794          if (!strcasecmp(tmp->name, "origmailbox")) {
03795             origmailbox = tmp->value;
03796          } else if (!strcasecmp(tmp->name, "context")) {
03797             context = tmp->value;
03798          } else if (!strcasecmp(tmp->name, "macrocontext")) {
03799             macrocontext = tmp->value;
03800          } else if (!strcasecmp(tmp->name, "exten")) {
03801             exten = tmp->value;
03802          } else if (!strcasecmp(tmp->name, "priority")) {
03803             priority = tmp->value;
03804          } else if (!strcasecmp(tmp->name, "callerchan")) {
03805             callerchan = tmp->value;
03806          } else if (!strcasecmp(tmp->name, "callerid")) {
03807             callerid = tmp->value;
03808          } else if (!strcasecmp(tmp->name, "origdate")) {
03809             origdate = tmp->value;
03810          } else if (!strcasecmp(tmp->name, "origtime")) {
03811             origtime = tmp->value;
03812          } else if (!strcasecmp(tmp->name, "category")) {
03813             category = tmp->value;
03814          } else if (!strcasecmp(tmp->name, "duration")) {
03815             duration = tmp->value;
03816          }
03817       }
03818       ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
03819    }
03820    copy(frompath2, topath2);
03821    ast_variables_destroy(var);
03822 }

static int count_messages ( struct ast_vm_user vmu,
char *  dir 
) [static]

Find all .txt files - even if they are not in sequence from 0000.

Parameters:
vmu 
dir This method is used when mailboxes are stored on the filesystem. (not ODBC and not IMAP).
Returns:
the count of messages, zero or more.

Definition at line 3626 of file app_voicemail.c.

References ast_unlock_path(), ERROR_LOCK_PATH, and vm_lock_path().

Referenced by leave_voicemail(), manager_list_voicemail_users(), and open_mailbox().

03627 {
03628 
03629    int vmcount = 0;
03630    DIR *vmdir = NULL;
03631    struct dirent *vment = NULL;
03632 
03633    if (vm_lock_path(dir))
03634       return ERROR_LOCK_PATH;
03635 
03636    if ((vmdir = opendir(dir))) {
03637       while ((vment = readdir(vmdir))) {
03638          if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03639             vmcount++;
03640          }
03641       }
03642       closedir(vmdir);
03643    }
03644    ast_unlock_path(dir);
03645    
03646    return vmcount;
03647 }

static int create_dirpath ( char *  dest,
int  len,
const char *  context,
const char *  ext,
const char *  folder 
) [static]

basically mkdir -p $dest/$context/$ext/$folder

Parameters:
dest String. base directory.
len Length of dest.
context String. Ignored if is null or empty string.
ext String. Ignored if is null or empty string.
folder String. Ignored if is null or empty string.
Returns:
-1 on failure, 0 on success.

Definition at line 1492 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, ast_mkdir(), make_dir(), and VOICEMAIL_DIR_MODE.

01493 {
01494    mode_t   mode = VOICEMAIL_DIR_MODE;
01495    int res;
01496 
01497    make_dir(dest, len, context, ext, folder);
01498    if ((res = ast_mkdir(dest, mode))) {
01499       ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01500       return -1;
01501    }
01502    return 0;
01503 }

static int dialout ( struct ast_channel chan,
struct ast_vm_user vmu,
char *  num,
char *  outgoing_context 
) [static]

Definition at line 11401 of file app_voicemail.c.

References ast_copy_string(), ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_verb, ast_verbose, ast_waitfordigit(), ast_channel::context, ast_channel::exten, option_verbose, ast_channel::priority, and VERBOSE_PREFIX_3.

Referenced by advanced_options(), and vm_execmain().

11402 {
11403    int cmd = 0;
11404    char destination[80] = "";
11405    int retries = 0;
11406 
11407    if (!num) {
11408       ast_verb(3, "Destination number will be entered manually\n");
11409       while (retries < 3 && cmd != 't') {
11410          destination[1] = '\0';
11411          destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
11412          if (!cmd)
11413             destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
11414          if (!cmd)
11415             destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
11416          if (!cmd) {
11417             cmd = ast_waitfordigit(chan, 6000);
11418             if (cmd)
11419                destination[0] = cmd;
11420          }
11421          if (!cmd) {
11422             retries++;
11423          } else {
11424 
11425             if (cmd < 0)
11426                return 0;
11427             if (cmd == '*') {
11428                ast_verb(3, "User hit '*' to cancel outgoing call\n");
11429                return 0;
11430             }
11431             if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0) 
11432                retries++;
11433             else
11434                cmd = 't';
11435          }
11436       }
11437       if (retries >= 3) {
11438          return 0;
11439       }
11440       
11441    } else {
11442       if (option_verbose > 2)
11443          ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
11444       ast_copy_string(destination, num, sizeof(destination));
11445    }
11446 
11447    if (!ast_strlen_zero(destination)) {
11448       if (destination[strlen(destination) -1 ] == '*')
11449          return 0; 
11450       if (option_verbose > 2)
11451          ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
11452       ast_copy_string(chan->exten, destination, sizeof(chan->exten));
11453       ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
11454       chan->priority = 0;
11455       return 9;
11456    }
11457    return 0;
11458 }

static struct ast_vm_user* find_or_create ( const char *  context,
const char *  box 
) [static, read]

Definition at line 9868 of file app_voicemail.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_test_flag, ast_vm_user::context, globalflags, LOG_WARNING, ast_vm_user::mailbox, and VM_SEARCH.

Referenced by append_mailbox(), and load_config().

09869 {
09870    struct ast_vm_user *vmu;
09871 
09872    AST_LIST_TRAVERSE(&users, vmu, list) {
09873       if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
09874          if (strcasecmp(vmu->context, context)) {
09875             ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
09876                   \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
09877                   \n\tconfiguration creates an ambiguity that you likely do not want. Please\
09878                   \n\tamend your voicemail.conf file to avoid this situation.\n", box);
09879          }
09880          ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
09881          return NULL;
09882       }
09883       if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
09884          ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
09885          return NULL;
09886       }
09887    }
09888    
09889    if (!(vmu = ast_calloc(1, sizeof(*vmu))))
09890       return NULL;
09891    
09892    ast_copy_string(vmu->context, context, sizeof(vmu->context));
09893    ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
09894 
09895    AST_LIST_INSERT_TAIL(&users, vmu, list);
09896    
09897    return vmu;
09898 }

static struct ast_vm_user* find_user ( struct ast_vm_user ivm,
const char *  context,
const char *  mailbox 
) [static, read]

Finds a voicemail user from the users file or the realtime engine.

Parameters:
ivm 
context 
mailbox 
Returns:
The ast_vm_user structure for the user that was found.

Definition at line 1259 of file app_voicemail.c.

References AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_malloc, ast_set2_flag, ast_test_flag, find_user_realtime(), globalflags, VM_ALLOCED, and VM_SEARCH.

01260 {
01261    /* This function could be made to generate one from a database, too */
01262    struct ast_vm_user *vmu = NULL, *cur;
01263    AST_LIST_LOCK(&users);
01264 
01265    if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01266       context = "default";
01267 
01268    AST_LIST_TRAVERSE(&users, cur, list) {
01269 #ifdef IMAP_STORAGE
01270       if (cur->imapversion != imapversion) {
01271          continue;
01272       }
01273 #endif
01274       if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01275          break;
01276       if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01277          break;
01278    }
01279    if (cur) {
01280       /* Make a copy, so that on a reload, we have no race */
01281       if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01282          memcpy(vmu, cur, sizeof(*vmu));
01283          ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01284          AST_LIST_NEXT(vmu, list) = NULL;
01285       }
01286    } else
01287       vmu = find_user_realtime(ivm, context, mailbox);
01288    AST_LIST_UNLOCK(&users);
01289    return vmu;
01290 }

static struct ast_vm_user* find_user_realtime ( struct ast_vm_user ivm,
const char *  context,
const char *  mailbox 
) [static, read]

Finds a voicemail user from the realtime engine.

Parameters:
ivm 
context 
mailbox This is called as a fall through case when the normal find_user() was not able to find a user. That is, the default it so look in the usual voicemail users file first.
Returns:
The ast_vm_user structure for the user that was found.

Definition at line 1222 of file app_voicemail.c.

References apply_options_full(), ast_calloc, ast_copy_string(), ast_free, ast_load_realtime(), ast_set_flag, ast_test_flag, ast_variables_destroy(), globalflags, ast_vm_user::mailbox, populate_defaults(), SENTINEL, var, VM_ALLOCED, and VM_SEARCH.

01223 {
01224    struct ast_variable *var;
01225    struct ast_vm_user *retval;
01226 
01227    if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01228       if (!ivm)
01229          ast_set_flag(retval, VM_ALLOCED);   
01230       else
01231          memset(retval, 0, sizeof(*retval));
01232       if (mailbox) 
01233          ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01234       populate_defaults(retval);
01235       if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01236          var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01237       else
01238          var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01239       if (var) {
01240          apply_options_full(retval, var);
01241          ast_variables_destroy(var);
01242       } else { 
01243          if (!ivm) 
01244             ast_free(retval);
01245          retval = NULL;
01246       }  
01247    } 
01248    return retval;
01249 }

static int forward_message ( struct ast_channel chan,
char *  context,
struct vm_state vms,
struct ast_vm_user sender,
char *  fmt,
int  is_new_message,
signed char  record_gain,
int  urgent 
) [static]

Sends a voicemail message to a mailbox recipient.

Parameters:
ast_channel 
context 
vms 
sender 
fmt 
is_new_message Used to indicate the mode for which this method was invoked. Will be 0 when called to forward an existing message (option 8) Will be 1 when called to leave a message (option 3->5)
record_gain 
Reads the destination mailbox(es) from keypad input for CID, or if use_directory feature is enabled, the Directory.

When in the leave message mode (is_new_message == 1):

  • allow the leaving of a message for ourselves. (Will not allow us to forward a message to ourselves, when is_new_message == 0).
  • attempt to determine the context and and mailbox, and then invoke leave_message() function to record and store the message.

When in the forward message mode (is_new_message == 0):

  • retreives the current message to be forwarded
  • copies the original message to a temporary file, so updates to the envelope can be done.
  • determines the target mailbox and folders
  • copies the message into the target mailbox, using copy_message() or by generating the message into an email attachment if using imap folders.

Returns:
zero on success, -1 on error.

Definition at line 6601 of file app_voicemail.c.

References ast_clear_flag, ast_copy_string(), ast_fileexists(), AST_LIST_EMPTY, AST_LIST_HEAD_NOLOCK_STATIC, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, AST_MAX_EXTENSION, ast_play_and_wait(), ast_readstring(), ast_say_digit_str(), ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_vm_user::context, ast_channel::context, copy_message(), vm_state::curbox, vm_state::curdir, vm_state::curmsg, DISPOSE, ast_channel::exten, find_user(), vm_state::fn, free_user(), globalflags, ast_channel::language, leave_voicemail(), LOG_NOTICE, ast_vm_user::mailbox, pbx_exec(), pbx_findapp(), ast_channel::priority, leave_vm_options::record_gain, RETRIEVE, run_externnotify(), s, S_OR, sendmail(), STORE, strsep(), vm_state::username, VM_ATTACH, VM_DIRECFORWARD, vm_forwardoptions(), and VM_FWDURGAUTO.

Referenced by vm_execmain().

06602 {
06603 #ifdef IMAP_STORAGE
06604    int todircount = 0;
06605    struct vm_state *dstvms;
06606 #endif
06607    char username[70]="";
06608    char fn[PATH_MAX]; /* for playback of name greeting */
06609    char ecodes[16] = "#";
06610    int res = 0, cmd = 0;
06611    struct ast_vm_user *receiver = NULL, *vmtmp;
06612    AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06613    char *stringp;
06614    const char *s;
06615    int saved_messages = 0, found = 0;
06616    int valid_extensions = 0;
06617    char *dir;
06618    int curmsg;
06619    char urgent_str[7] = "";
06620    char tmptxtfile[PATH_MAX];
06621 
06622    if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06623       ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06624    }
06625 
06626    if (vms == NULL) return -1;
06627    dir = vms->curdir;
06628    curmsg = vms->curmsg;
06629 
06630    tmptxtfile[0] = '\0';
06631    while (!res && !valid_extensions) {
06632       int use_directory = 0;
06633       if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06634          int done = 0;
06635          int retries = 0;
06636          cmd = 0;
06637          while ((cmd >= 0) && !done ){
06638             if (cmd)
06639                retries = 0;
06640             switch (cmd) {
06641             case '1': 
06642                use_directory = 0;
06643                done = 1;
06644                break;
06645             case '2': 
06646                use_directory = 1;
06647                done = 1;
06648                break;
06649             case '*': 
06650                cmd = 't';
06651                done = 1;
06652                break;
06653             default: 
06654                /* Press 1 to enter an extension press 2 to use the directory */
06655                cmd = ast_play_and_wait(chan, "vm-forward");
06656                if (!cmd)
06657                   cmd = ast_waitfordigit(chan, 3000);
06658                if (!cmd)
06659                   retries++;
06660                if (retries > 3) {
06661                   cmd = 't';
06662                   done = 1;
06663                }
06664                
06665             }
06666          }
06667          if (cmd < 0 || cmd == 't')
06668             break;
06669       }
06670       
06671       if (use_directory) {
06672          /* use app_directory */
06673          
06674          char old_context[sizeof(chan->context)];
06675          char old_exten[sizeof(chan->exten)];
06676          int old_priority;
06677          struct ast_app* directory_app;
06678 
06679          directory_app = pbx_findapp("Directory");
06680          if (directory_app) {
06681             char vmcontext[256];
06682             /* make backup copies */
06683             memcpy(old_context, chan->context, sizeof(chan->context));
06684             memcpy(old_exten, chan->exten, sizeof(chan->exten));
06685             old_priority = chan->priority;
06686             
06687             /* call the the Directory, changes the channel */
06688             snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
06689             res = pbx_exec(chan, directory_app, vmcontext);
06690             
06691             ast_copy_string(username, chan->exten, sizeof(username));
06692             
06693             /* restore the old context, exten, and priority */
06694             memcpy(chan->context, old_context, sizeof(chan->context));
06695             memcpy(chan->exten, old_exten, sizeof(chan->exten));
06696             chan->priority = old_priority;
06697          } else {
06698             ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
06699             ast_clear_flag((&globalflags), VM_DIRECFORWARD);
06700          }
06701       } else {
06702          /* Ask for an extension */
06703          res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */
06704          if (res)
06705             break;
06706          if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
06707             break;
06708       }
06709       
06710       /* start all over if no username */
06711       if (ast_strlen_zero(username))
06712          continue;
06713       stringp = username;
06714       s = strsep(&stringp, "*");
06715       /* start optimistic */
06716       valid_extensions = 1;
06717       while (s) {
06718          if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
06719             AST_LIST_INSERT_HEAD(&extensions, receiver, list);
06720             found++;
06721          } else {
06722             /* XXX Optimization for the future.  When we encounter a single bad extension,
06723              * bailing out on all of the extensions may not be the way to go.  We should
06724              * probably just bail on that single extension, then allow the user to enter
06725              * several more. XXX
06726              */
06727             while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
06728                free_user(receiver);
06729             }
06730             ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
06731             valid_extensions = 0;
06732             break;
06733          }
06734 
06735          /* play name if available, else play extension number */
06736          snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
06737          RETRIEVE(fn, -1, s, receiver->context);
06738          if (ast_fileexists(fn, NULL, NULL) > 0) {
06739             res = ast_stream_and_wait(chan, fn, ecodes);
06740             if (res) {
06741                DISPOSE(fn, -1);
06742                return res;
06743             }
06744          } else {
06745             res = ast_say_digit_str(chan, s, ecodes, chan->language);
06746          }
06747          DISPOSE(fn, -1);
06748 
06749          s = strsep(&stringp, "*");
06750       }
06751       /* break from the loop of reading the extensions */
06752       if (valid_extensions)
06753          break;
06754       /* "I am sorry, that's not a valid extension.  Please try again." */
06755       res = ast_play_and_wait(chan, "pbx-invalid");
06756    }
06757    /* check if we're clear to proceed */
06758    if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
06759       return res;
06760    if (is_new_message == 1) {
06761       struct leave_vm_options leave_options;
06762       char mailbox[AST_MAX_EXTENSION * 2 + 2];
06763       snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
06764 
06765       /* Send VoiceMail */
06766       memset(&leave_options, 0, sizeof(leave_options));
06767       leave_options.record_gain = record_gain;
06768       cmd = leave_voicemail(chan, mailbox, &leave_options);
06769    } else {
06770       /* Forward VoiceMail */
06771       long duration = 0;
06772       struct vm_state vmstmp;
06773       memcpy(&vmstmp, vms, sizeof(vmstmp));
06774 
06775       RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
06776 
06777       cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
06778       if (!cmd) {
06779          AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
06780 #ifdef IMAP_STORAGE
06781             int attach_user_voicemail;
06782             char *myserveremail = serveremail;
06783             
06784             /* get destination mailbox */
06785             dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
06786             if (!dstvms) {
06787                dstvms = create_vm_state_from_user(vmtmp);
06788             }
06789             if (dstvms) {
06790                init_mailstream(dstvms, 0);
06791                if (!dstvms->mailstream) {
06792                   ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
06793                } else {
06794                   STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
06795                   run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str); 
06796                }
06797             } else {
06798                ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
06799             }
06800             if (!ast_strlen_zero(vmtmp->serveremail))
06801                myserveremail = vmtmp->serveremail;
06802             attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
06803             /* NULL category for IMAP storage */
06804             sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
06805 #else
06806             copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
06807 #endif
06808             saved_messages++;
06809             AST_LIST_REMOVE_CURRENT(list);
06810             free_user(vmtmp);
06811             if (res)
06812                break;
06813          }
06814          AST_LIST_TRAVERSE_SAFE_END;
06815          if (saved_messages > 0) {
06816             /* give confirmation that the message was saved */
06817             /* commented out since we can't forward batches yet
06818             if (saved_messages == 1)
06819                res = ast_play_and_wait(chan, "vm-message");
06820             else
06821                res = ast_play_and_wait(chan, "vm-messages");
06822             if (!res)
06823                res = ast_play_and_wait(chan, "vm-saved"); */
06824 #ifdef IMAP_STORAGE
06825             /* If forwarded with intro, DON'T PLAY THIS MESSAGE AGAIN! */
06826             if (ast_strlen_zero(vmstmp.introfn))
06827 #endif
06828             res = ast_play_and_wait(chan, "vm-msgsaved");
06829          }  
06830       }
06831       DISPOSE(dir, curmsg);
06832    }
06833 
06834    /* If anything failed above, we still have this list to free */
06835    while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
06836       free_user(vmtmp);
06837    return res ? res : cmd;
06838 }

static void free_user ( struct ast_vm_user vmu  )  [static]

Definition at line 1542 of file app_voicemail.c.

References ast_free, ast_test_flag, ast_vm_user::emailbody, ast_vm_user::emailsubject, and VM_ALLOCED.

01543 {
01544    if (ast_test_flag(vmu, VM_ALLOCED)) {
01545       if (vmu->emailbody != NULL) {
01546          ast_free(vmu->emailbody);
01547          vmu->emailbody = NULL;
01548       }
01549       if (vmu->emailsubject != NULL) {
01550          ast_free(vmu->emailsubject);
01551          vmu->emailsubject = NULL;
01552       }
01553       ast_free(vmu);
01554    }
01555 }

static void free_vm_users ( void   )  [static]

Free the users structure.

Definition at line 10548 of file app_voicemail.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_set_flag, free_user(), and VM_ALLOCED.

Referenced by load_config(), and unload_module().

10549 {
10550    struct ast_vm_user *current;
10551    AST_LIST_LOCK(&users);
10552    while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
10553       ast_set_flag(current, VM_ALLOCED);
10554       free_user(current);
10555    }
10556    AST_LIST_UNLOCK(&users);
10557 }

static void free_vm_zones ( void   )  [static]

Free the zones structure.

Definition at line 10560 of file app_voicemail.c.

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

Referenced by load_config(), and unload_module().

10561 {
10562    struct vm_zone *zcur;
10563    AST_LIST_LOCK(&zones);
10564    while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
10565       free_zone(zcur);
10566    AST_LIST_UNLOCK(&zones);
10567 }

static void free_zone ( struct vm_zone z  )  [static]

Definition at line 4702 of file app_voicemail.c.

References ast_free.

04703 {
04704    ast_free(z);
04705 }

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

Gets the current date and time, as formatted string.

Parameters:
s The buffer to hold the output formatted date.
len the length of the buffer. Used to prevent buffer overflow in ast_strftime.
The date format string used is "%a %b %e %r UTC %Y".

Returns:
zero on success, -1 on error.

Definition at line 4658 of file app_voicemail.c.

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

04659 {
04660    struct ast_tm tm;
04661    struct timeval t = ast_tvnow();
04662    
04663    ast_localtime(&t, &tm, "UTC");
04664 
04665    return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04666 }

static int get_folder ( struct ast_channel chan,
int  start 
) [static]

get_folder: Folder menu Plays "press 1 for INBOX messages" etc. Should possibly be internationalized

Definition at line 6267 of file app_voicemail.c.

References AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), ast_waitfordigit(), ast_channel::language, mbox(), and vm_play_folder_name().

Referenced by get_folder2().

06268 {
06269    int x;
06270    int d;
06271    char fn[PATH_MAX];
06272    d = ast_play_and_wait(chan, "vm-press");  /* "Press" */
06273    if (d)
06274       return d;
06275    for (x = start; x < 5; x++) { /* For all folders */
06276       if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06277          return d;
06278       d = ast_play_and_wait(chan, "vm-for"); /* "for" */
06279       if (d)
06280          return d;
06281       snprintf(fn, sizeof(fn), "vm-%s", mbox(x));  /* Folder name */
06282       d = vm_play_folder_name(chan, fn);
06283       if (d)
06284          return d;
06285       d = ast_waitfordigit(chan, 500);
06286       if (d)
06287          return d;
06288    }
06289    d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
06290    if (d)
06291       return d;
06292    d = ast_waitfordigit(chan, 4000);
06293    return d;
06294 }

static int get_folder2 ( struct ast_channel chan,
char *  fn,
int  start 
) [static]

plays a prompt and waits for a keypress.

Parameters:
chan 
fn the name of the voice prompt file to be played. For example, 'vm-changeto', 'vm-savefolder'
start Does not appear to be used at this time.
This is used by the main menu option to move a message to a folder or to save a message into a folder. After playing the message identified by the fn parameter value, it calls get_folder(), which plays the prompting for the number inputs that correspond to the available folders.

Returns:
zero on success, or -1 on error.

Definition at line 6308 of file app_voicemail.c.

References ast_play_and_wait(), and get_folder().

Referenced by vm_execmain().

06309 {
06310    int res = 0;
06311    res = ast_play_and_wait(chan, fn);  /* Folder name */
06312    while (((res < '0') || (res > '9')) &&
06313          (res != '#') && (res >= 0)) {
06314       res = get_folder(chan, 0);
06315    }
06316    return res;
06317 }

static int get_folder_by_name ( const char *  name  )  [static]

Definition at line 1529 of file app_voicemail.c.

References ARRAY_LEN, and mailbox_folders.

Referenced by vm_execmain().

01530 {
01531    size_t i;
01532 
01533    for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01534       if (strcasecmp(name, mailbox_folders[i]) == 0) {
01535          return i;
01536       }
01537    }
01538 
01539    return -1;
01540 }

static int handle_subscribe ( void *  datap  )  [static]

Definition at line 10331 of file app_voicemail.c.

References ast_calloc, ast_free, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strlen_zero(), mwi_sub_task::context, mwi_sub::mailbox, mwi_sub_task::mailbox, poll_subscribed_mailbox(), mwi_sub_task::uniqueid, and mwi_sub::uniqueid.

Referenced by mwi_sub_event_cb().

10332 {
10333    unsigned int len;
10334    struct mwi_sub *mwi_sub;
10335    struct mwi_sub_task *p = datap;
10336 
10337    len = sizeof(*mwi_sub);
10338    if (!ast_strlen_zero(p->mailbox))
10339       len += strlen(p->mailbox);
10340 
10341    if (!ast_strlen_zero(p->context))
10342       len += strlen(p->context) + 1; /* Allow for seperator */
10343 
10344    if (!(mwi_sub = ast_calloc(1, len)))
10345       return -1;
10346 
10347    mwi_sub->uniqueid = p->uniqueid;
10348    if (!ast_strlen_zero(p->mailbox))
10349       strcpy(mwi_sub->mailbox, p->mailbox);
10350 
10351    if (!ast_strlen_zero(p->context)) {
10352       strcat(mwi_sub->mailbox, "@");
10353       strcat(mwi_sub->mailbox, p->context);
10354    }
10355 
10356    AST_RWLIST_WRLOCK(&mwi_subs);
10357    AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
10358    AST_RWLIST_UNLOCK(&mwi_subs);
10359    ast_free((void *) p->mailbox);
10360    ast_free((void *) p->context);
10361    ast_free(p);
10362    poll_subscribed_mailbox(mwi_sub);
10363    return 0;
10364 }

static int handle_unsubscribe ( void *  datap  )  [static]

Definition at line 10309 of file app_voicemail.c.

References ast_free, AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, mwi_sub::entry, mwi_sub_destroy(), and mwi_sub::uniqueid.

Referenced by mwi_unsub_event_cb().

10310 {
10311    struct mwi_sub *mwi_sub;
10312    uint32_t *uniqueid = datap;
10313    
10314    AST_RWLIST_WRLOCK(&mwi_subs);
10315    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
10316       if (mwi_sub->uniqueid == *uniqueid) {
10317          AST_LIST_REMOVE_CURRENT(entry);
10318          break;
10319       }
10320    }
10321    AST_RWLIST_TRAVERSE_SAFE_END
10322    AST_RWLIST_UNLOCK(&mwi_subs);
10323 
10324    if (mwi_sub)
10325       mwi_sub_destroy(mwi_sub);
10326 
10327    ast_free(uniqueid);  
10328    return 0;
10329 }

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

Reload voicemail configuration from the CLI.

Definition at line 10226 of file app_voicemail.c.

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

10227 {
10228    switch (cmd) {
10229    case CLI_INIT:
10230       e->command = "voicemail reload";
10231       e->usage =
10232          "Usage: voicemail reload\n"
10233          "       Reload voicemail configuration\n";
10234       return NULL;
10235    case CLI_GENERATE:
10236       return NULL;
10237    }
10238 
10239    if (a->argc != 2)
10240       return CLI_SHOWUSAGE;
10241 
10242    ast_cli(a->fd, "Reloading voicemail configuration...\n");   
10243    load_config(1);
10244    
10245    return CLI_SUCCESS;
10246 }

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

Show a list of voicemail users in the CLI.

Definition at line 10116 of file app_voicemail.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_check_realtime(), ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_show_users(), ast_vm_user::context, ast_cli_args::fd, ast_vm_user::fullname, HVSU_OUTPUT_FORMAT, inboxcount(), ast_cli_args::line, ast_vm_user::mailbox, ast_cli_args::n, ast_cli_args::pos, show_users_realtime(), ast_cli_entry::usage, ast_cli_args::word, and ast_vm_user::zonetag.

10117 {
10118    struct ast_vm_user *vmu;
10119 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10120    const char *context = NULL;
10121    int users_counter = 0;
10122 
10123    switch (cmd) {
10124    case CLI_INIT:
10125       e->command = "voicemail show users";
10126       e->usage =
10127          "Usage: voicemail show users [for <context>]\n"
10128          "       Lists all mailboxes currently set up\n";
10129       return NULL;
10130    case CLI_GENERATE:
10131       return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10132    }  
10133 
10134    if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10135       return CLI_SHOWUSAGE;
10136    if (a->argc == 5) {
10137       if (strcmp(a->argv[3],"for"))
10138          return CLI_SHOWUSAGE;
10139       context = a->argv[4];
10140    }
10141 
10142    if (ast_check_realtime("voicemail")) {
10143       if (!context) {
10144          ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10145          return CLI_SHOWUSAGE;
10146       }
10147       return show_users_realtime(a->fd, context);
10148    }
10149 
10150    AST_LIST_LOCK(&users);
10151    if (AST_LIST_EMPTY(&users)) {
10152       ast_cli(a->fd, "There are no voicemail users currently defined\n");
10153       AST_LIST_UNLOCK(&users);
10154       return CLI_FAILURE;
10155    }
10156    if (a->argc == 3)
10157       ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10158    else {
10159       int count = 0;
10160       AST_LIST_TRAVERSE(&users, vmu, list) {
10161          if (!strcmp(context, vmu->context))
10162             count++;
10163       }
10164       if (count) {
10165          ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10166       } else {
10167          ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10168          AST_LIST_UNLOCK(&users);
10169          return CLI_FAILURE;
10170       }
10171    }
10172    AST_LIST_TRAVERSE(&users, vmu, list) {
10173       int newmsgs = 0, oldmsgs = 0;
10174       char count[12], tmp[256] = "";
10175 
10176       if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10177          snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10178          inboxcount(tmp, &newmsgs, &oldmsgs);
10179          snprintf(count, sizeof(count), "%d", newmsgs);
10180          ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10181          users_counter++;
10182       }
10183    }
10184    AST_LIST_UNLOCK(&users);
10185    ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10186    return CLI_SUCCESS;
10187 }

static char* handle_voicemail_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 10190 of file app_voicemail.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, HVSZ_OUTPUT_FORMAT, vm_zone::msg_format, vm_zone::name, vm_zone::timezone, and ast_cli_entry::usage.

10191 {
10192    struct vm_zone *zone;
10193 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10194    char *res = CLI_SUCCESS;
10195 
10196    switch (cmd) {
10197    case CLI_INIT:
10198       e->command = "voicemail show zones";
10199       e->usage =
10200          "Usage: voicemail show zones\n"
10201          "       Lists zone message formats\n";
10202       return NULL;
10203    case CLI_GENERATE:
10204       return NULL;
10205    }
10206 
10207    if (a->argc != 3)
10208       return CLI_SHOWUSAGE;
10209 
10210    AST_LIST_LOCK(&zones);
10211    if (!AST_LIST_EMPTY(&zones)) {
10212       ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10213       AST_LIST_TRAVERSE(&zones, zone, list) {
10214          ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10215       }
10216    } else {
10217       ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10218       res = CLI_FAILURE;
10219    }
10220    AST_LIST_UNLOCK(&zones);
10221 
10222    return res;
10223 }

static int has_voicemail ( const char *  mailbox,
const char *  folder 
) [static]

Determines if the given folder has messages.

Parameters:
mailbox The @ delimited string for user. If no context is found, uses 'default' for the context.
folder the folder to look in
This function is used when the mailbox is stored in a filesystem back end. This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
Returns:
1 if the folder has one or more messages. zero otherwise.

Definition at line 5043 of file app_voicemail.c.

References __has_voicemail(), ast_copy_string(), and strsep().

Referenced by dahdi_handle_event(), do_monitor(), handle_hd_hf(), handle_init_event(), handle_request(), load_module(), mgcp_hangup(), mgcp_request(), mwi_send_init(), my_has_voicemail(), and vm_execmain().

05044 {
05045    char tmp[256], *tmp2 = tmp, *box, *context;
05046    ast_copy_string(tmp, mailbox, sizeof(tmp));
05047    while ((box = strsep(&tmp2, ","))) {
05048       if ((context = strchr(box, '@')))
05049          *context++ = '\0';
05050       else
05051          context = "default";
05052       if (__has_voicemail(context, box, folder, 1))
05053          return 1;
05054    }
05055    return 0;
05056 }

static int inboxcount ( const char *  mailbox,
int *  newmsgs,
int *  oldmsgs 
) [static]

Definition at line 5115 of file app_voicemail.c.

References inboxcount2().

Referenced by handle_voicemail_show_users(), leave_voicemail(), load_module(), and manager_list_voicemail_users().

05116 {
05117    return inboxcount2(mailbox, NULL, newmsgs, oldmsgs);
05118 }

static int inboxcount2 ( const char *  mailbox,
int *  urgentmsgs,
int *  newmsgs,
int *  oldmsgs 
) [static]

Definition at line 5059 of file app_voicemail.c.

References __has_voicemail(), ast_copy_string(), ast_strlen_zero(), and strsep().

Referenced by append_mailbox(), inboxcount(), load_module(), poll_subscribed_mailbox(), and run_externnotify().

05060 {
05061    char tmp[256];
05062    char *context;
05063 
05064    /* If no mailbox, return immediately */
05065    if (ast_strlen_zero(mailbox))
05066       return 0;
05067 
05068    if (newmsgs)
05069       *newmsgs = 0;
05070    if (oldmsgs)
05071       *oldmsgs = 0;
05072    if (urgentmsgs)
05073       *urgentmsgs = 0;
05074 
05075    if (strchr(mailbox, ',')) {
05076       int tmpnew, tmpold, tmpurgent;
05077       char *mb, *cur;
05078 
05079       ast_copy_string(tmp, mailbox, sizeof(tmp));
05080       mb = tmp;
05081       while ((cur = strsep(&mb, ", "))) {
05082          if (!ast_strlen_zero(cur)) {
05083             if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05084                return -1;
05085             else {
05086                if (newmsgs)
05087                   *newmsgs += tmpnew; 
05088                if (oldmsgs)
05089                   *oldmsgs += tmpold;
05090                if (urgentmsgs)
05091                   *urgentmsgs += tmpurgent;
05092             }
05093          }
05094       }
05095       return 0;
05096    }
05097 
05098    ast_copy_string(tmp, mailbox, sizeof(tmp));
05099    
05100    if ((context = strchr(tmp, '@')))
05101       *context++ = '\0';
05102    else
05103       context = "default";
05104 
05105    if (newmsgs)
05106       *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05107    if (oldmsgs)
05108       *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05109    if (urgentmsgs)
05110       *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05111 
05112    return 0;
05113 }

static int inbuf ( struct baseio bio,
FILE *  fi 
) [static]

utility used by inchar(), for base_encode()

Definition at line 3854 of file app_voicemail.c.

References baseio::ateof, BASEMAXINLINE, baseio::iobuf, baseio::iocp, and baseio::iolen.

Referenced by ast_eivr_getvariable(), ast_eivr_setvariable(), inchar(), sip_addheader(), and sip_removeheader().

03855 {
03856    int l;
03857 
03858    if (bio->ateof)
03859       return 0;
03860 
03861    if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
03862       if (ferror(fi))
03863          return -1;
03864 
03865       bio->ateof = 1;
03866       return 0;
03867    }
03868 
03869    bio->iolen = l;
03870    bio->iocp = 0;
03871 
03872    return 1;
03873 }

static int inchar ( struct baseio bio,
FILE *  fi 
) [static]

utility used by base_encode()

Definition at line 3878 of file app_voicemail.c.

References inbuf(), baseio::iobuf, baseio::iocp, and baseio::iolen.

Referenced by base_encode().

03879 {
03880    if (bio->iocp>=bio->iolen) {
03881       if (!inbuf(bio, fi))
03882          return EOF;
03883    }
03884 
03885    return bio->iobuf[bio->iocp++];
03886 }

static int invent_message ( struct ast_channel chan,
char *  context,
char *  ext,
int  busy,
char *  ecodes 
) [static]

Definition at line 4668 of file app_voicemail.c.

References ast_fileexists(), ast_log(), AST_LOG_WARNING, ast_say_digit_str(), ast_stream_and_wait(), create_dirpath(), DISPOSE, ast_channel::language, and RETRIEVE.

04669 {
04670    int res;
04671    char fn[PATH_MAX];
04672    char dest[PATH_MAX];
04673 
04674    snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04675 
04676    if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04677       ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04678       return -1;
04679    }
04680 
04681    RETRIEVE(fn, -1, ext, context);
04682    if (ast_fileexists(fn, NULL, NULL) > 0) {
04683       res = ast_stream_and_wait(chan, fn, ecodes);
04684       if (res) {
04685          DISPOSE(fn, -1);
04686          return res;
04687       }
04688    } else {
04689       /* Dispose just in case */
04690       DISPOSE(fn, -1);
04691       res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04692       if (res)
04693          return res;
04694       res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04695       if (res)
04696          return res;
04697    }
04698    res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04699    return res;
04700 }

static int is_valid_dtmf ( const char *  key  )  [static]

Determines if a DTMF key entered is valid.

Parameters:
key The character to be compared. expects a single character. Though is capable of handling a string, this is internally copies using ast_strdupa.
Tests the character entered against the set of valid DTMF characters.
Returns:
1 if the character entered is a valid DTMF digit, 0 if the character is invalid.

Definition at line 1197 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, ast_strdupa, and VALID_DTMF.

Referenced by load_config().

01198 {
01199    int i;
01200    char *local_key = ast_strdupa(key);
01201 
01202    for (i = 0; i < strlen(key); ++i) {
01203       if (!strchr(VALID_DTMF, *local_key)) {
01204          ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01205          return 0;
01206       }
01207       local_key++;
01208    }
01209    return 1;
01210 }

static int last_message_index ( struct ast_vm_user vmu,
char *  dir 
) [static]

Determines the highest message number in use for a given user and mailbox folder.

Parameters:
vmu 
dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause.
This method is used when mailboxes are stored on the filesystem. (not ODBC and not IMAP). Typical use to set the msgnum would be to take the value returned from this method and add one to it.

Note:
Should always be called with a lock already set on dir.
Returns:
the value of zero or greaterto indicate the last message index in use, -1 to indicate none.

Definition at line 3680 of file app_voicemail.c.

References map, ast_vm_user::maxmsg, and MAXMSGLIMIT.

Referenced by copy_message(), leave_voicemail(), open_mailbox(), and save_to_folder().

03681 {
03682    int x;
03683    unsigned char map[MAXMSGLIMIT] = "";
03684    DIR *msgdir;
03685    struct dirent *msgdirent;
03686    int msgdirint;
03687 
03688    /* Reading the entire directory into a file map scales better than
03689     * doing a stat repeatedly on a predicted sequence.  I suspect this
03690     * is partially due to stat(2) internally doing a readdir(2) itself to
03691     * find each file. */
03692    if (!(msgdir = opendir(dir))) {
03693       return -1;
03694    }
03695 
03696    while ((msgdirent = readdir(msgdir))) {
03697       if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03698          map[msgdirint] = 1;
03699    }
03700    closedir(msgdir);
03701 
03702    for (x = 0; x < vmu->maxmsg; x++) {
03703       if (map[x] == 0)
03704          break;
03705    }
03706 
03707    return x - 1;
03708 }

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

Prompts the user and records a voicemail to a mailbox.

Parameters:
chan 
ext 
options OPT_BUSY_GREETING, OPT_UNAVAIL_GREETING
Returns:
zero on success, -1 on error.

Definition at line 5185 of file app_voicemail.c.

References ast_callerid_merge(), ast_canmatch_extension(), ast_channel_lock, ast_channel_unlock, ast_check_realtime(), ast_copy_string(), ast_debug, ast_destroy_realtime(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), AST_LOG_ERROR, AST_LOG_NOTICE, AST_LOG_WARNING, ast_mutex_lock(), ast_mutex_unlock(), ast_play_and_wait(), ast_set_flag, ast_stopstream(), ast_store_realtime(), ast_str_create(), ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_unlock_path(), ast_update_realtime(), ast_verbose, ast_waitstream(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_vm_user::context, copy_message(), count_messages(), create_dirpath(), DISPOSE, errno, ast_vm_user::exit, leave_vm_options::exitcontext, exten, ast_channel::exten, find_user(), free_user(), get_date(), inboxcount(), INTRO, invent_message(), ast_channel::language, last_message_index(), ast_channel::macrocontext, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_channel::name, vm_state::newmessages, notify_new_message(), OPT_BUSY_GREETING, OPT_DTMFEXIT, OPT_MESSAGE_PRIORITY, OPT_MESSAGE_Urgent, OPT_SILENT, OPT_UNAVAIL_GREETING, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), play_record_review(), ast_channel::priority, leave_vm_options::record_gain, RENAME, RETRIEVE, S_OR, SENTINEL, STORE, strsep(), transfer, VERBOSE_PREFIX_3, vm_lock_path(), VM_OPERATOR, and VOICEMAIL_FILE_MODE.

05186 {
05187 #ifdef IMAP_STORAGE
05188    int newmsgs, oldmsgs;
05189 #else
05190    char urgdir[PATH_MAX];
05191 #endif
05192    char txtfile[PATH_MAX];
05193    char tmptxtfile[PATH_MAX];
05194    struct vm_state *vms = NULL;
05195    char callerid[256];
05196    FILE *txt;
05197    char date[256];
05198    int txtdes;
05199    int res = 0;
05200    int msgnum;
05201    int duration = 0;
05202    int ausemacro = 0;
05203    int ousemacro = 0;
05204    int ouseexten = 0;
05205    char tmpdur[16];
05206    char priority[16];
05207    char origtime[16];
05208    char dir[PATH_MAX];
05209    char tmpdir[PATH_MAX];
05210    char fn[PATH_MAX];
05211    char prefile[PATH_MAX] = "";
05212    char tempfile[PATH_MAX] = "";
05213    char ext_context[256] = "";
05214    char fmt[80];
05215    char *context;
05216    char ecodes[17] = "#";
05217    struct ast_str *tmp = ast_str_create(16);
05218    char *tmpptr;
05219    struct ast_vm_user *vmu;
05220    struct ast_vm_user svm;
05221    const char *category = NULL;
05222    const char *code;
05223    const char *alldtmf = "0123456789ABCD*#";
05224    char flag[80];
05225 
05226    if (!tmp) {
05227       return -1;
05228    }
05229 
05230    ext = ast_strdupa(ext);
05231    if ((context = strchr(ext, '@'))) {
05232       *context++ = '\0';
05233       tmpptr = strchr(context, '&');
05234    } else {
05235       tmpptr = strchr(ext, '&');
05236    }
05237 
05238    if (tmpptr)
05239       *tmpptr++ = '\0';
05240 
05241    ast_channel_lock(chan);
05242    if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05243       category = ast_strdupa(category);
05244    }
05245    ast_channel_unlock(chan);
05246 
05247    if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05248       ast_copy_string(flag, "Urgent", sizeof(flag));
05249    } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05250       ast_copy_string(flag, "PRIORITY", sizeof(flag));
05251    } else {
05252       flag[0] = '\0';
05253    }
05254 
05255    ast_debug(3, "Before find_user\n");
05256    if (!(vmu = find_user(&svm, context, ext))) {
05257       ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05258       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05259       ast_free(tmp);
05260       return res;
05261    }
05262    /* Setup pre-file if appropriate */
05263    if (strcmp(vmu->context, "default"))
05264       snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05265    else
05266       ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05267 
05268    /* Set the path to the prefile. Will be one of 
05269       VM_SPOOL_DIRcontext/ext/busy
05270       VM_SPOOL_DIRcontext/ext/unavail
05271       Depending on the flag set in options.
05272    */
05273    if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05274       snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05275    } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05276       snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05277    }
05278    /* Set the path to the tmpfile as
05279       VM_SPOOL_DIR/context/ext/temp
05280       and attempt to create the folder structure.
05281    */
05282    snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05283    if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05284       ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05285       ast_free(tmp);
05286       return -1;
05287    }
05288    RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05289    if (ast_fileexists(tempfile, NULL, NULL) > 0)
05290       ast_copy_string(prefile, tempfile, sizeof(prefile));
05291 
05292    DISPOSE(tempfile, -1);
05293    /* It's easier just to try to make it than to check for its existence */
05294    create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05295 
05296    /* Check current or macro-calling context for special extensions */
05297    if (ast_test_flag(vmu, VM_OPERATOR)) {
05298       if (!ast_strlen_zero(vmu->exit)) {
05299          if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
05300             strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05301             ouseexten = 1;
05302          }
05303       } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
05304          strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05305          ouseexten = 1;
05306       } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
05307          strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05308          ousemacro = 1;
05309       }
05310    }
05311 
05312    if (!ast_strlen_zero(vmu->exit)) {
05313       if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
05314          strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05315    } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
05316       strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05317    else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
05318       strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05319       ausemacro = 1;
05320    }
05321 
05322    if (ast_test_flag(options, OPT_DTMFEXIT)) {
05323       for (code = alldtmf; *code; code++) {
05324          char e[2] = "";
05325          e[0] = *code;
05326          if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num))
05327             strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05328       }
05329    }
05330 
05331    /* Play the beginning intro if desired */
05332    if (!ast_strlen_zero(prefile)) {
05333 #ifdef ODBC_STORAGE
05334       int success = 
05335 #endif
05336          RETRIEVE(prefile, -1, ext, context);
05337       if (ast_fileexists(prefile, NULL, NULL) > 0) {
05338          if (ast_streamfile(chan, prefile, chan->language) > -1) 
05339             res = ast_waitstream(chan, ecodes);
05340 #ifdef ODBC_STORAGE
05341          if (success == -1) {
05342             /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
05343             ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05344             store_file(prefile, vmu->mailbox, vmu->context, -1);
05345          }
05346 #endif
05347       } else {
05348          ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05349          res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05350       }
05351       DISPOSE(prefile, -1);
05352       if (res < 0) {
05353          ast_debug(1, "Hang up during prefile playback\n");
05354          free_user(vmu);
05355          pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05356          ast_free(tmp);
05357          return -1;
05358       }
05359    }
05360    if (res == '#') {
05361       /* On a '#' we skip the instructions */
05362       ast_set_flag(options, OPT_SILENT);
05363       res = 0;
05364    }
05365    if (!res && !ast_test_flag(options, OPT_SILENT)) {
05366       res = ast_stream_and_wait(chan, INTRO, ecodes);
05367       if (res == '#') {
05368          ast_set_flag(options, OPT_SILENT);
05369          res = 0;
05370       }
05371    }
05372    if (res > 0)
05373       ast_stopstream(chan);
05374    /* Check for a '*' here in case the caller wants to escape from voicemail to something
05375     other than the operator -- an automated attendant or mailbox login for example */
05376    if (res == '*') {
05377       chan->exten[0] = 'a';
05378       chan->exten[1] = '\0';
05379       if (!ast_strlen_zero(vmu->exit)) {
05380          ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05381       } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05382          ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05383       }
05384       chan->priority = 0;
05385       free_user(vmu);
05386       pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05387       ast_free(tmp);
05388       return 0;
05389    }
05390 
05391    /* Check for a '0' here */
05392    if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05393    transfer:
05394       if (ouseexten || ousemacro) {
05395          chan->exten[0] = 'o';
05396          chan->exten[1] = '\0';
05397          if (!ast_strlen_zero(vmu->exit)) {
05398             ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05399          } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05400             ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05401          }
05402          ast_play_and_wait(chan, "transfer");
05403          chan->priority = 0;
05404          free_user(vmu);
05405          pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05406       }
05407       ast_free(tmp);
05408       return 0;
05409    }
05410 
05411    /* Allow all other digits to exit Voicemail and return to the dialplan */
05412    if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05413       if (!ast_strlen_zero(options->exitcontext))
05414          ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05415       free_user(vmu);
05416       pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05417       ast_free(tmp);
05418       return res;
05419    }
05420 
05421    if (res < 0) {
05422       free_user(vmu);
05423       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05424       ast_free(tmp);
05425       return -1;
05426    }
05427    /* The meat of recording the message...  All the announcements and beeps have been played*/
05428    ast_copy_string(fmt, vmfmts, sizeof(fmt));
05429    if (!ast_strlen_zero(fmt)) {
05430       msgnum = 0;
05431 
05432 #ifdef IMAP_STORAGE
05433       /* Is ext a mailbox? */
05434       /* must open stream for this user to get info! */
05435       res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05436       if (res < 0) {
05437          ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05438          ast_free(tmp);
05439          return -1;
05440       }
05441       if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05442       /* It is possible under certain circumstances that inboxcount did not
05443        * create a vm_state when it was needed. This is a catchall which will
05444        * rarely be used.
05445        */
05446          if (!(vms = create_vm_state_from_user(vmu))) {
05447             ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05448             ast_free(tmp);
05449             return -1;
05450          }
05451       }
05452       vms->newmessages++;
05453       
05454       /* here is a big difference! We add one to it later */
05455       msgnum = newmsgs + oldmsgs;
05456       ast_debug(3, "Messagecount set to %d\n", msgnum);
05457       snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05458       /* set variable for compatibility */
05459       pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05460 
05461       /* Check if mailbox is full */
05462       check_quota(vms, imapfolder);
05463       if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
05464          ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
05465          ast_play_and_wait(chan, "vm-mailboxfull");
05466          ast_free(tmp);
05467          return -1;
05468       }
05469       
05470       /* Check if we have exceeded maxmsg */
05471       if (msgnum >= vmu->maxmsg) {
05472          ast_log(AST_LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
05473          ast_play_and_wait(chan, "vm-mailboxfull");
05474          ast_free(tmp);
05475          return -1;
05476       }
05477 #else
05478       if (count_messages(vmu, dir) >= vmu->maxmsg) {
05479          res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05480          if (!res)
05481             res = ast_waitstream(chan, "");
05482          ast_log(AST_LOG_WARNING, "No more messages possible\n");
05483          pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05484          goto leave_vm_out;
05485       }
05486 
05487 #endif
05488       snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05489       txtdes = mkstemp(tmptxtfile);
05490       chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05491       if (txtdes < 0) {
05492          res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05493          if (!res)
05494             res = ast_waitstream(chan, "");
05495          ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05496          pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05497          goto leave_vm_out;
05498       }
05499 
05500       /* Now play the beep once we have the message number for our next message. */
05501       if (res >= 0) {
05502          /* Unless we're *really* silent, try to send the beep */
05503          res = ast_stream_and_wait(chan, "beep", "");
05504       }
05505             
05506       /* Store information in real-time storage */
05507       if (ast_check_realtime("voicemail_data")) {
05508          snprintf(priority, sizeof(priority), "%d", chan->priority);
05509          snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05510          get_date(date, sizeof(date));
05511          ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category, ""), "filename", tmptxtfile, SENTINEL);
05512       }
05513 
05514       /* Store information */
05515       txt = fdopen(txtdes, "w+");
05516       if (txt) {
05517          get_date(date, sizeof(date));
05518          fprintf(txt, 
05519             ";\n"
05520             "; Message Information file\n"
05521             ";\n"
05522             "[message]\n"
05523             "origmailbox=%s\n"
05524             "context=%s\n"
05525             "macrocontext=%s\n"
05526             "exten=%s\n"
05527             "priority=%d\n"
05528             "callerchan=%s\n"
05529             "callerid=%s\n"
05530             "origdate=%s\n"
05531             "origtime=%ld\n"
05532             "category=%s\n",
05533             ext,
05534             chan->context,
05535             chan->macrocontext, 
05536             chan->exten,
05537             chan->priority,
05538             chan->name,
05539             ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
05540             date, (long) time(NULL),
05541             category ? category : "");
05542       } else
05543          ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05544       res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05545 
05546       if (txt) {
05547          fprintf(txt, "flag=%s\n", flag);
05548          if (duration < vmminsecs) {
05549             fclose(txt);
05550             if (option_verbose > 2) 
05551                ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
05552             ast_filedelete(tmptxtfile, NULL);
05553             unlink(tmptxtfile);
05554             if (ast_check_realtime("voicemail_data")) {
05555                ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05556             }
05557          } else {
05558             fprintf(txt, "duration=%d\n", duration);
05559             fclose(txt);
05560             if (vm_lock_path(dir)) {
05561                ast_log(AST_LOG_ERROR, "Couldn't lock directory %s.  Voicemail will be lost.\n", dir);
05562                /* Delete files */
05563                ast_filedelete(tmptxtfile, NULL);
05564                unlink(tmptxtfile);
05565             } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05566                ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05567                unlink(tmptxtfile);
05568                ast_unlock_path(dir);
05569                if (ast_check_realtime("voicemail_data")) {
05570                   ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05571                }
05572             } else {
05573 #ifndef IMAP_STORAGE
05574                msgnum = last_message_index(vmu, dir) + 1;
05575 #endif
05576                make_file(fn, sizeof(fn), dir, msgnum);
05577 
05578                /* assign a variable with the name of the voicemail file */ 
05579 #ifndef IMAP_STORAGE
05580                pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05581 #else
05582                pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05583 #endif
05584 
05585                snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05586                ast_filerename(tmptxtfile, fn, NULL);
05587                rename(tmptxtfile, txtfile);
05588 
05589                /* Properly set permissions on voicemail text descriptor file.
05590                   Unfortunately mkstemp() makes this file 0600 on most unix systems. */
05591                if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05592                   ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05593 
05594                ast_unlock_path(dir);
05595                if (ast_check_realtime("voicemail_data")) {
05596                   snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05597                   ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
05598                }
05599                /* We must store the file first, before copying the message, because
05600                 * ODBC storage does the entire copy with SQL.
05601                 */
05602                if (ast_fileexists(fn, NULL, NULL) > 0) {
05603                   STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05604                }
05605 
05606                /* Are there to be more recipients of this message? */
05607                while (tmpptr) {
05608                   struct ast_vm_user recipu, *recip;
05609                   char *exten, *cntx;
05610                
05611                   exten = strsep(&tmpptr, "&");
05612                   cntx = strchr(exten, '@');
05613                   if (cntx) {
05614                      *cntx = '\0';
05615                      cntx++;
05616                   }
05617                   if ((recip = find_user(&recipu, cntx, exten))) {
05618                      copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05619                      free_user(recip);
05620                   }
05621                }
05622 #ifndef IMAP_STORAGE
05623                if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If this is an Urgent message */
05624                   /* Move the message from INBOX to Urgent folder if this is urgent! */
05625                   char sfn[PATH_MAX];
05626                   char dfn[PATH_MAX];
05627                   int x;
05628                   /* It's easier just to try to make it than to check for its existence */
05629                   create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05630                   ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05631                   x = last_message_index(vmu, urgdir) + 1;
05632                   make_file(sfn, sizeof(sfn), dir, msgnum);
05633                   make_file(dfn, sizeof(dfn), urgdir, x);
05634                   RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05635                }
05636 #endif
05637                /* Notification needs to happen after the copy, though. */
05638                if (ast_fileexists(fn, NULL, NULL)) {
05639 #ifdef IMAP_STORAGE
05640                   notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05641 #else
05642                   notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05643 #endif
05644                }
05645 
05646                /* Disposal needs to happen after the optional move and copy */
05647                if (ast_fileexists(fn, NULL, NULL)) {
05648                   DISPOSE(dir, msgnum);
05649                }
05650             }
05651          }
05652       }
05653       if (res == '0') {
05654          goto transfer;
05655       } else if (res > 0)
05656          res = 0;
05657 
05658       if (duration < vmminsecs)
05659          /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
05660          pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05661       else
05662          pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05663    } else
05664       ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05665 leave_vm_out:
05666    free_user(vmu);
05667 
05668 #ifdef IMAP_STORAGE
05669    /* expunge message - use UID Expunge if supported on IMAP server*/
05670    ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
05671    if (expungeonhangup == 1) {
05672       ast_mutex_lock(&vms->lock);
05673 #ifdef HAVE_IMAP_TK2006
05674       if (LEVELUIDPLUS (vms->mailstream)) {
05675          mail_expunge_full(vms->mailstream, NIL, EX_UID);
05676       } else 
05677 #endif
05678          mail_expunge(vms->mailstream);
05679       ast_mutex_unlock(&vms->lock);
05680    }
05681 #endif
05682 
05683    ast_free(tmp);
05684    return res;
05685 }

static int load_config ( int  reload  )  [static]

Definition at line 10613 of file app_voicemail.c.

References adsifdn, adsisec, adsiver, append_mailbox(), apply_options_full(), ast_category_browse(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_config_option(), ast_copy_string(), ast_debug, ast_dsp_get_threshold_from_settings(), ast_false(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_LOG_DEBUG, AST_LOG_ERROR, AST_LOG_WARNING, ast_malloc, AST_PTHREADT_NULL, ast_set2_flag, ast_smdi_interface_find(), ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unload_realtime(), ast_variable_browse(), ast_variable_retrieve(), ASTERISK_USERNAME, callcontext, charset, cidinternalcontexts, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, ast_vm_user::context, DEFAULT_LISTEN_CONTROL_FORWARD_KEY, DEFAULT_LISTEN_CONTROL_PAUSE_KEY, DEFAULT_LISTEN_CONTROL_RESTART_KEY, DEFAULT_LISTEN_CONTROL_REVERSE_KEY, DEFAULT_LISTEN_CONTROL_STOP_KEY, DEFAULT_POLL_FREQ, dialcontext, emailbody, emaildateformat, emailsubject, exitcontext, find_or_create(), free_vm_users(), free_vm_zones(), fromstring, globalflags, is_valid_dtmf(), ast_variable::lineno, listen_control_forward_key, listen_control_pause_key, listen_control_restart_key, listen_control_reverse_key, listen_control_stop_key, LOG_ERROR, ast_vm_user::mailbox, MAX_NUM_CID_CONTEXTS, MAXMSG, MAXMSGLIMIT, MINPASSWORD, vm_zone::msg_format, vm_zone::name, ast_variable::name, ast_variable::next, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_USERSCONF, OPT_PWLOC_VOICEMAILCONF, pagerbody, pagerfromstring, pagersubject, ast_vm_user::password, ast_vm_user::passwordlocation, populate_defaults(), PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, read_password_from_file(), saydurationminfo, SENDMAIL, start_poll_thread(), stop_poll_thread(), strsep(), substitute_escapes(), THRESHOLD_SILENCE, vm_zone::timezone, ast_variable::value, VM_ATTACH, VM_DIRECFORWARD, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_FWDURGAUTO, vm_invalid_password, VM_MESSAGEWRAP, vm_mismatch, VM_MOVEHEARD, vm_newpassword, VM_OPERATOR, vm_passchanged, vm_password, VM_PBXSKIP, vm_pls_try_again, vm_reenterpassword, VM_REVIEW, VM_SAYCID, VM_SAYDURATION, VM_SEARCH, VM_SKIPAFTERCMD, VM_SVMAIL, VM_TEMPGREETWARN, and VOICEMAIL_CONFIG.

10614 {
10615    struct ast_vm_user *current;
10616    struct ast_config *cfg, *ucfg;
10617    char *cat;
10618    struct ast_variable *var;
10619    const char *val;
10620    char *q, *stringp;
10621    int x;
10622    int tmpadsi[4];
10623    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10624    char secretfn[PATH_MAX] = "";
10625 
10626    ast_unload_realtime("voicemail");
10627    ast_unload_realtime("voicemail_data");
10628 
10629    if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
10630       if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
10631          return 0;
10632       } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
10633          ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Avoiding.\n");
10634          ucfg = NULL;
10635       }
10636       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10637       if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
10638          ast_config_destroy(ucfg);
10639          ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
10640          return 0;
10641       }
10642    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10643       ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
10644       return 0;
10645    } else {
10646       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10647       if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
10648          ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Avoiding.\n");
10649          ucfg = NULL;
10650       }
10651    }
10652 #ifdef IMAP_STORAGE
10653    ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
10654 #endif
10655    /* set audio control prompts */
10656    strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
10657    strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
10658    strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
10659    strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
10660    strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
10661 
10662    /* Free all the users structure */  
10663    free_vm_users();
10664 
10665    /* Free all the zones structure */
10666    free_vm_zones();
10667 
10668    AST_LIST_LOCK(&users);  
10669 
10670    memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
10671    memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
10672 
10673    if (cfg) {
10674       /* General settings */
10675 
10676       if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
10677          val = "default";
10678       ast_copy_string(userscontext, val, sizeof(userscontext));
10679       /* Attach voice message to mail message ? */
10680       if (!(val = ast_variable_retrieve(cfg, "general", "attach"))) 
10681          val = "yes";
10682       ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH); 
10683 
10684       if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
10685          val = "no";
10686       ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
10687 
10688       volgain = 0.0;
10689       if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
10690          sscanf(val, "%30lf", &volgain);
10691 
10692 #ifdef ODBC_STORAGE
10693       strcpy(odbc_database, "asterisk");
10694       if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
10695          ast_copy_string(odbc_database, val, sizeof(odbc_database));
10696       }
10697       strcpy(odbc_table, "voicemessages");
10698       if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
10699          ast_copy_string(odbc_table, val, sizeof(odbc_table));
10700       }
10701 #endif      
10702       /* Mail command */
10703       strcpy(mailcmd, SENDMAIL);
10704       if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
10705          ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */
10706 
10707       maxsilence = 0;
10708       if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
10709          maxsilence = atoi(val);
10710          if (maxsilence > 0)
10711             maxsilence *= 1000;
10712       }
10713       
10714       if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
10715          maxmsg = MAXMSG;
10716       } else {
10717          maxmsg = atoi(val);
10718          if (maxmsg <= 0) {
10719             ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
10720             maxmsg = MAXMSG;
10721          } else if (maxmsg > MAXMSGLIMIT) {
10722             ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10723             maxmsg = MAXMSGLIMIT;
10724          }
10725       }
10726 
10727       if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
10728          maxdeletedmsg = 0;
10729       } else {
10730          if (sscanf(val, "%30d", &x) == 1)
10731             maxdeletedmsg = x;
10732          else if (ast_true(val))
10733             maxdeletedmsg = MAXMSG;
10734          else
10735             maxdeletedmsg = 0;
10736 
10737          if (maxdeletedmsg < 0) {
10738             ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
10739             maxdeletedmsg = MAXMSG;
10740          } else if (maxdeletedmsg > MAXMSGLIMIT) {
10741             ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10742             maxdeletedmsg = MAXMSGLIMIT;
10743          }
10744       }
10745 
10746       /* Load date format config for voicemail mail */
10747       if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
10748          ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
10749       }
10750 
10751       /* External password changing command */
10752       if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
10753          ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
10754          pwdchange = PWDCHANGE_EXTERNAL;
10755       } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
10756          ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
10757          pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
10758       }
10759  
10760       /* External password validation command */
10761       if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
10762          ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
10763          ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
10764       }
10765 
10766 #ifdef IMAP_STORAGE
10767       /* IMAP server address */
10768       if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
10769          ast_copy_string(imapserver, val, sizeof(imapserver));
10770       } else {
10771          ast_copy_string(imapserver, "localhost", sizeof(imapserver));
10772       }
10773       /* IMAP server port */
10774       if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
10775          ast_copy_string(imapport, val, sizeof(imapport));
10776       } else {
10777          ast_copy_string(imapport, "143", sizeof(imapport));
10778       }
10779       /* IMAP server flags */
10780       if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
10781          ast_copy_string(imapflags, val, sizeof(imapflags));
10782       }
10783       /* IMAP server master username */
10784       if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
10785          ast_copy_string(authuser, val, sizeof(authuser));
10786       }
10787       /* IMAP server master password */
10788       if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
10789          ast_copy_string(authpassword, val, sizeof(authpassword));
10790       }
10791       /* Expunge on exit */
10792       if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
10793          if (ast_false(val))
10794             expungeonhangup = 0;
10795          else
10796             expungeonhangup = 1;
10797       } else {
10798          expungeonhangup = 1;
10799       }
10800       /* IMAP voicemail folder */
10801       if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
10802          ast_copy_string(imapfolder, val, sizeof(imapfolder));
10803       } else {
10804          ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
10805       }
10806       if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
10807          ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
10808       }
10809       if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
10810          imapgreetings = ast_true(val);
10811       } else {
10812          imapgreetings = 0;
10813       }
10814       if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
10815          ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
10816       } else {
10817          ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
10818       }
10819 
10820       /* There is some very unorthodox casting done here. This is due
10821        * to the way c-client handles the argument passed in. It expects a 
10822        * void pointer and casts the pointer directly to a long without
10823        * first dereferencing it. */
10824       if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
10825          mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
10826       } else {
10827          mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
10828       }
10829 
10830       if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
10831          mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
10832       } else {
10833          mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
10834       }
10835 
10836       if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
10837          mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
10838       } else {
10839          mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
10840       }
10841 
10842       if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
10843          mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
10844       } else {
10845          mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
10846       }
10847 
10848       /* Increment configuration version */
10849       imapversion++;
10850 #endif
10851       /* External voicemail notify application */
10852       if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
10853          ast_copy_string(externnotify, val, sizeof(externnotify));
10854          ast_debug(1, "found externnotify: %s\n", externnotify);
10855       } else {
10856          externnotify[0] = '\0';
10857       }
10858 
10859       /* SMDI voicemail notification */
10860       if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
10861          ast_debug(1, "Enabled SMDI voicemail notification\n");
10862          if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
10863             smdi_iface = ast_smdi_interface_find(val);
10864          } else {
10865             ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
10866             smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
10867          }
10868          if (!smdi_iface) {
10869             ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
10870          } 
10871       }
10872 
10873       /* Silence treshold */
10874       silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
10875       if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
10876          silencethreshold = atoi(val);
10877       
10878       if (!(val = ast_variable_retrieve(cfg, "general", "serveremail"))) 
10879          val = ASTERISK_USERNAME;
10880       ast_copy_string(serveremail, val, sizeof(serveremail));
10881       
10882       vmmaxsecs = 0;
10883       if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
10884          if (sscanf(val, "%30d", &x) == 1) {
10885             vmmaxsecs = x;
10886          } else {
10887             ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10888          }
10889       } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
10890          static int maxmessage_deprecate = 0;
10891          if (maxmessage_deprecate == 0) {
10892             maxmessage_deprecate = 1;
10893             ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
10894          }
10895          if (sscanf(val, "%30d", &x) == 1) {
10896             vmmaxsecs = x;
10897          } else {
10898             ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10899          }
10900       }
10901 
10902       vmminsecs = 0;
10903       if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
10904          if (sscanf(val, "%30d", &x) == 1) {
10905             vmminsecs = x;
10906             if (maxsilence / 1000 >= vmminsecs) {
10907                ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10908             }
10909          } else {
10910             ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10911          }
10912       } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
10913          static int maxmessage_deprecate = 0;
10914          if (maxmessage_deprecate == 0) {
10915             maxmessage_deprecate = 1;
10916             ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
10917          }
10918          if (sscanf(val, "%30d", &x) == 1) {
10919             vmminsecs = x;
10920             if (maxsilence / 1000 >= vmminsecs) {
10921                ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10922             }
10923          } else {
10924             ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10925          }
10926       }
10927 
10928       val = ast_variable_retrieve(cfg, "general", "format");
10929       if (!val)
10930          val = "wav";   
10931       ast_copy_string(vmfmts, val, sizeof(vmfmts));
10932 
10933       skipms = 3000;
10934       if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
10935          if (sscanf(val, "%30d", &x) == 1) {
10936             maxgreet = x;
10937          } else {
10938             ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
10939          }
10940       }
10941 
10942       if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
10943          if (sscanf(val, "%30d", &x) == 1) {
10944             skipms = x;
10945          } else {
10946             ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
10947          }
10948       }
10949 
10950       maxlogins = 3;
10951       if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
10952          if (sscanf(val, "%30d", &x) == 1) {
10953             maxlogins = x;
10954          } else {
10955             ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
10956          }
10957       }
10958 
10959       minpassword = MINPASSWORD;
10960       if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
10961          if (sscanf(val, "%30d", &x) == 1) {
10962             minpassword = x;
10963          } else {
10964             ast_log(AST_LOG_WARNING, "Invalid minimum password length.  Default to %d\n", minpassword);
10965          }
10966       }
10967 
10968       /* Force new user to record name ? */
10969       if (!(val = ast_variable_retrieve(cfg, "general", "forcename"))) 
10970          val = "no";
10971       ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
10972 
10973       /* Force new user to record greetings ? */
10974       if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings"))) 
10975          val = "no";
10976       ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
10977 
10978       if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
10979          ast_debug(1, "VM_CID Internal context string: %s\n", val);
10980          stringp = ast_strdupa(val);
10981          for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
10982             if (!ast_strlen_zero(stringp)) {
10983                q = strsep(&stringp, ",");
10984                while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
10985                   q++;
10986                ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
10987                ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
10988             } else {
10989                cidinternalcontexts[x][0] = '\0';
10990             }
10991          }
10992       }
10993       if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
10994          ast_debug(1, "VM Review Option disabled globally\n");
10995          val = "no";
10996       }
10997       ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW); 
10998 
10999       /* Temporary greeting reminder */
11000       if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
11001          ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
11002          val = "no";
11003       } else {
11004          ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
11005       }
11006       ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
11007       if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
11008          ast_debug(1, "VM next message wrap disabled globally\n");
11009          val = "no";
11010       }
11011       ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);  
11012 
11013       if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
11014          ast_debug(1, "VM Operator break disabled globally\n");
11015          val = "no";
11016       }
11017       ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);  
11018 
11019       if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
11020          ast_debug(1, "VM CID Info before msg disabled globally\n");
11021          val = "no";
11022       } 
11023       ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID); 
11024 
11025       if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
11026          ast_debug(1, "Send Voicemail msg disabled globally\n");
11027          val = "no";
11028       }
11029       ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
11030    
11031       if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
11032          ast_debug(1, "ENVELOPE before msg enabled globally\n");
11033          val = "yes";
11034       }
11035       ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);  
11036 
11037       if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
11038          ast_debug(1, "Move Heard enabled globally\n");
11039          val = "yes";
11040       }
11041       ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD); 
11042 
11043       if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
11044          ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
11045          val = "no";
11046       }
11047       ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);   
11048 
11049       if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
11050          ast_debug(1, "Duration info before msg enabled globally\n");
11051          val = "yes";
11052       }
11053       ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);  
11054 
11055       saydurationminfo = 2;
11056       if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
11057          if (sscanf(val, "%30d", &x) == 1) {
11058             saydurationminfo = x;
11059          } else {
11060             ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
11061          }
11062       }
11063 
11064       if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
11065          ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
11066          val = "no";
11067       }
11068       ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
11069 
11070       if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
11071          ast_copy_string(dialcontext, val, sizeof(dialcontext));
11072          ast_debug(1, "found dialout context: %s\n", dialcontext);
11073       } else {
11074          dialcontext[0] = '\0';  
11075       }
11076       
11077       if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
11078          ast_copy_string(callcontext, val, sizeof(callcontext));
11079          ast_debug(1, "found callback context: %s\n", callcontext);
11080       } else {
11081          callcontext[0] = '\0';
11082       }
11083 
11084       if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
11085          ast_copy_string(exitcontext, val, sizeof(exitcontext));
11086          ast_debug(1, "found operator context: %s\n", exitcontext);
11087       } else {
11088          exitcontext[0] = '\0';
11089       }
11090       
11091       /* load password sounds configuration */
11092       if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
11093          ast_copy_string(vm_password, val, sizeof(vm_password));
11094       if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
11095          ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
11096       if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
11097          ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
11098       if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
11099          ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
11100       if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
11101          ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
11102       if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
11103          ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
11104       if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
11105          ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
11106       }
11107       /* load configurable audio prompts */
11108       if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
11109          ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
11110       if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
11111          ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
11112       if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
11113          ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
11114       if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
11115          ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
11116       if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
11117          ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
11118 
11119       if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
11120          val = "no";
11121       ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD); 
11122 
11123       if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
11124          val = "voicemail.conf";
11125       }
11126       if (!(strcmp(val, "spooldir"))) {
11127          passwordlocation = OPT_PWLOC_SPOOLDIR;
11128       } else {
11129          passwordlocation = OPT_PWLOC_VOICEMAILCONF;
11130       }
11131 
11132       poll_freq = DEFAULT_POLL_FREQ;
11133       if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
11134          if (sscanf(val, "%30u", &poll_freq) != 1) {
11135             poll_freq = DEFAULT_POLL_FREQ;
11136             ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
11137          }
11138       }
11139 
11140       poll_mailboxes = 0;
11141       if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
11142          poll_mailboxes = ast_true(val);
11143 
11144       if (ucfg) { 
11145          for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
11146             if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
11147                continue;
11148             if ((current = find_or_create(userscontext, cat))) {
11149                populate_defaults(current);
11150                apply_options_full(current, ast_variable_browse(ucfg, cat));
11151                ast_copy_string(current->context, userscontext, sizeof(current->context));
11152                if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
11153                   current->passwordlocation = OPT_PWLOC_USERSCONF;
11154                }
11155 
11156                switch (current->passwordlocation) {
11157                case OPT_PWLOC_SPOOLDIR:
11158                   snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
11159                   read_password_from_file(secretfn, current->password, sizeof(current->password));
11160                }
11161             }
11162          }
11163          ast_config_destroy(ucfg);
11164       }
11165       cat = ast_category_browse(cfg, NULL);
11166       while (cat) {
11167          if (strcasecmp(cat, "general")) {
11168             var = ast_variable_browse(cfg, cat);
11169             if (strcasecmp(cat, "zonemessages")) {
11170                /* Process mailboxes in this context */
11171                while (var) {
11172                   append_mailbox(cat, var->name, var->value);
11173                   var = var->next;
11174                }
11175             } else {
11176                /* Timezones in this context */
11177                while (var) {
11178                   struct vm_zone *z;
11179                   if ((z = ast_malloc(sizeof(*z)))) {
11180                      char *msg_format, *tzone;
11181                      msg_format = ast_strdupa(var->value);
11182                      tzone = strsep(&msg_format, "|");
11183                      if (msg_format) {
11184                         ast_copy_string(z->name, var->name, sizeof(z->name));
11185                         ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
11186                         ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
11187                         AST_LIST_LOCK(&zones);
11188                         AST_LIST_INSERT_HEAD(&zones, z, list);
11189                         AST_LIST_UNLOCK(&zones);
11190                      } else {
11191                         ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
11192                         ast_free(z);
11193                      }
11194                   } else {
11195                      AST_LIST_UNLOCK(&users);
11196                      ast_config_destroy(cfg);
11197                      return -1;
11198                   }
11199                   var = var->next;
11200                }
11201             }
11202          }
11203          cat = ast_category_browse(cfg, cat);
11204       }
11205       memset(fromstring, 0, sizeof(fromstring));
11206       memset(pagerfromstring, 0, sizeof(pagerfromstring));
11207       strcpy(charset, "ISO-8859-1");
11208       if (emailbody) {
11209          ast_free(emailbody);
11210          emailbody = NULL;
11211       }
11212       if (emailsubject) {
11213          ast_free(emailsubject);
11214          emailsubject = NULL;
11215       }
11216       if (pagerbody) {
11217          ast_free(pagerbody);
11218          pagerbody = NULL;
11219       }
11220       if (pagersubject) {
11221          ast_free(pagersubject);
11222          pagersubject = NULL;
11223       }
11224       if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
11225          ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
11226       if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
11227          ast_copy_string(fromstring, val, sizeof(fromstring));
11228       if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
11229          ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
11230       if ((val = ast_variable_retrieve(cfg, "general", "charset")))
11231          ast_copy_string(charset, val, sizeof(charset));
11232       if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
11233          sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11234          for (x = 0; x < 4; x++) {
11235             memcpy(&adsifdn[x], &tmpadsi[x], 1);
11236          }
11237       }
11238       if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
11239          sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11240          for (x = 0; x < 4; x++) {
11241             memcpy(&adsisec[x], &tmpadsi[x], 1);
11242          }
11243       }
11244       if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
11245          if (atoi(val)) {
11246             adsiver = atoi(val);
11247          }
11248       }
11249       if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
11250          ast_copy_string(zonetag, val, sizeof(zonetag));
11251       }
11252       if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
11253          emailsubject = ast_strdup(val);
11254       }
11255       if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
11256          emailbody = ast_strdup(substitute_escapes(val));
11257       }
11258       if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
11259          pagersubject = ast_strdup(val);
11260       }
11261       if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
11262          pagerbody = ast_strdup(substitute_escapes(val));
11263       }
11264       AST_LIST_UNLOCK(&users);
11265       ast_config_destroy(cfg);
11266 
11267       if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
11268          start_poll_thread();
11269       if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
11270          stop_poll_thread();;
11271 
11272       return 0;
11273    } else {
11274       AST_LIST_UNLOCK(&users);
11275       ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
11276       if (ucfg)
11277          ast_config_destroy(ucfg);
11278       return 0;
11279    }
11280 }

static int load_module ( void   )  [static]

Definition at line 11367 of file app_voicemail.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_config_AST_SPOOL_DIR, ast_custom_function_register, ast_install_vm_functions(), ast_log(), AST_LOG_WARNING, ast_manager_register_xml, ast_realtime_require_field(), ast_register_application_xml, ast_taskprocessor_get(), cli_voicemail, EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, has_voicemail(), inboxcount(), inboxcount2(), load_config(), mailbox_exists_acf, manager_list_voicemail_users(), messagecount(), mwi_subscription_tps, RQ_CHAR, RQ_UINTEGER3, sayname(), SENTINEL, vm_box_exists(), vm_exec(), vm_execmain(), and vmauthenticate().

11368 {
11369    int res;
11370    my_umask = umask(0);
11371    umask(my_umask);
11372 
11373    /* compute the location of the voicemail spool directory */
11374    snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
11375    
11376    if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
11377       ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor.  MWI will not work\n");
11378    }
11379 
11380    if ((res = load_config(0)))
11381       return res;
11382 
11383    res = ast_register_application_xml(app, vm_exec);
11384    res |= ast_register_application_xml(app2, vm_execmain);
11385    res |= ast_register_application_xml(app3, vm_box_exists);
11386    res |= ast_register_application_xml(app4, vmauthenticate);
11387    res |= ast_custom_function_register(&mailbox_exists_acf);
11388    res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
11389    if (res)
11390       return res;
11391 
11392    ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
11393 
11394    ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
11395    ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
11396    ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
11397 
11398    return res;
11399 }

static int make_dir ( char *  dest,
int  len,
const char *  context,
const char *  ext,
const char *  folder 
) [static]

Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.

Parameters:
dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
len The length of the path string that was written out.
The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns:
zero on success, -1 on error.

Definition at line 1448 of file app_voicemail.c.

01449 {
01450    return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01451 }

static void make_email_file ( FILE *  p,
char *  srcemail,
struct ast_vm_user vmu,
int  msgnum,
char *  context,
char *  mailbox,
const char *  fromfolder,
char *  cidnum,
char *  cidname,
char *  attach,
char *  attach2,
char *  format,
int  duration,
int  attach_user_voicemail,
struct ast_channel chan,
const char *  category,
int  imap,
const char *  flag 
) [static]

Creates the email file to be sent to indicate a new voicemail exists for a user.

Parameters:
p The output file to generate the email contents into.
srcemail The email address to send the email to, presumably the email address for the owner of the mailbox.
vmu The voicemail user who is sending the voicemail.
msgnum The message index in the mailbox folder.
context 
mailbox The voicemail box to read the voicemail to be notified in this email.
cidnum The caller ID number.
cidname The caller ID name.
attach the name of the sound file to be attached to the email, if attach_user_voicemail == 1.
format The message sound file format. i.e. .wav
duration The time of the message content, in seconds.
attach_user_voicemail if 1, the sound file is attached to the email.
chan 
category 
imap if == 1, indicates the target folder for the email notification to be sent to will be an IMAP mailstore. This causes additional mailbox headers to be set, which would facilitate searching for the email in the destination IMAP folder.
The email body, and base 64 encoded attachement (if any) are stored to the file identified by *p. This method does not actually send the email. That is done by invoking the configure 'mailcmd' and piping this generated file into it, or with the sendemail() function.

Definition at line 4165 of file app_voicemail.c.

References add_email_attachment(), ast_channel_release(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_dummy_channel_alloc(), ast_free, ast_localtime(), ast_log(), AST_LOG_WARNING, ast_random(), 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_test_flag, ast_variable_retrieve(), charset, check_mime(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, emailbody, emaildateformat, ast_vm_user::emailsubject, emailsubject, ENDL, fromstring, ast_vm_user::fullname, globalflags, ast_vm_user::mailbox, make_dir(), make_file(), MAXHOSTNAMELEN, ast_channel::name, prep_email_sub_vars(), ast_channel::priority, strip_control(), VM_PBXSKIP, and vmu_tm().

Referenced by sendmail().

04166 {
04167    char date[256];
04168    char host[MAXHOSTNAMELEN] = "";
04169    char who[256];
04170    char bound[256];
04171    char dur[256];
04172    struct ast_tm tm;
04173    char enc_cidnum[256] = "", enc_cidname[256] = "";
04174    struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04175    char *greeting_attachment; 
04176    char filename[256];
04177 
04178    if (!str1 || !str2) {
04179       ast_free(str1);
04180       ast_free(str2);
04181       return;
04182    }
04183 #ifdef IMAP_STORAGE
04184 #define ENDL "\r\n"
04185 #else
04186 #define ENDL "\n"
04187 #endif
04188 
04189    if (cidnum) {
04190       strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
04191    }
04192    if (cidname) {
04193       strip_control(cidname, enc_cidname, sizeof(enc_cidname));
04194    }
04195    gethostname(host, sizeof(host) - 1);
04196 
04197    if (strchr(srcemail, '@')) {
04198       ast_copy_string(who, srcemail, sizeof(who));
04199    } else {
04200       snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04201    }
04202    
04203    greeting_attachment = strrchr(ast_strdupa(attach), '/');
04204    if (greeting_attachment) {
04205       *greeting_attachment++ = '\0';
04206    }
04207 
04208    snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04209    ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04210    fprintf(p, "Date: %s" ENDL, date);
04211 
04212    /* Set date format for voicemail mail */
04213    ast_strftime(date, sizeof(date), emaildateformat, &tm);
04214 
04215    if (!ast_strlen_zero(fromstring)) {
04216       struct ast_channel *ast;
04217       if ((ast = ast_dummy_channel_alloc())) {
04218          char *ptr;
04219          prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04220          ast_str_substitute_variables(&str1, 0, ast, fromstring);
04221 
04222          if (check_mime(ast_str_buffer(str1))) {
04223             int first_line = 1;
04224             ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04225             while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04226                *ptr = '\0';
04227                fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04228                first_line = 0;
04229                /* Substring is smaller, so this will never grow */
04230                ast_str_set(&str2, 0, "%s", ptr + 1);
04231             }
04232             fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04233          } else {
04234             fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04235          }
04236          ast = ast_channel_release(ast);
04237       } else {
04238          ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04239       }
04240    } else {
04241       fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04242    }
04243 
04244    if (check_mime(vmu->fullname)) {
04245       int first_line = 1;
04246       char *ptr;
04247       ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04248       while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04249          *ptr = '\0';
04250          fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04251          first_line = 0;
04252          /* Substring is smaller, so this will never grow */
04253          ast_str_set(&str2, 0, "%s", ptr + 1);
04254       }
04255       fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04256    } else {
04257       fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04258    }
04259 
04260    if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04261       char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04262       struct ast_channel *ast;
04263       if ((ast = ast_dummy_channel_alloc())) {
04264          prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04265          ast_str_substitute_variables(&str1, 0, ast, e_subj);
04266          if (check_mime(ast_str_buffer(str1))) {
04267             int first_line = 1;
04268             char *ptr;
04269             ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04270             while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04271                *ptr = '\0';
04272                fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04273                first_line = 0;
04274                /* Substring is smaller, so this will never grow */
04275                ast_str_set(&str2, 0, "%s", ptr + 1);
04276             }
04277             fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04278          } else {
04279             fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04280          }
04281          ast = ast_channel_release(ast);
04282       } else {
04283          ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04284       }
04285    } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04286       if (ast_strlen_zero(flag)) {
04287          fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04288       } else {
04289          fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04290       }
04291    } else {
04292       if (ast_strlen_zero(flag)) {
04293          fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04294       } else {
04295          fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04296       }
04297    }
04298 
04299    fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04300       (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04301    if (imap) {
04302       /* additional information needed for IMAP searching */
04303       fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04304       /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
04305       fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04306       fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04307 #ifdef IMAP_STORAGE
04308       fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04309 #else
04310       fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04311 #endif
04312       /* flag added for Urgent */
04313       fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04314       fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04315       fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04316       fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04317       fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04318       fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04319       if (!ast_strlen_zero(category)) {
04320          fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04321       } else {
04322          fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04323       }
04324       fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04325       fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04326       fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04327    }
04328    if (!ast_strlen_zero(cidnum)) {
04329       fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04330    }
04331    if (!ast_strlen_zero(cidname)) {
04332       fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04333    }
04334    fprintf(p, "MIME-Version: 1.0" ENDL);
04335    if (attach_user_voicemail) {
04336       /* Something unique. */
04337       snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04338          (int) getpid(), (unsigned int) ast_random());
04339 
04340       fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04341       fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04342       fprintf(p, "--%s" ENDL, bound);
04343    }
04344    fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04345    if (emailbody || vmu->emailbody) {
04346       char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04347       struct ast_channel *ast;
04348       if ((ast = ast_dummy_channel_alloc())) {
04349          prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04350          ast_str_substitute_variables(&str1, 0, ast, e_body);
04351          fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04352          ast = ast_channel_release(ast);
04353       } else {
04354          ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04355       }
04356    } else if (msgnum > -1) {
04357       if (strcmp(vmu->mailbox, mailbox)) {
04358          /* Forwarded type */
04359          struct ast_config *msg_cfg;
04360          const char *v;
04361          int inttime;
04362          char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04363          struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04364          /* Retrieve info from VM attribute file */
04365          make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04366          make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04367          if (strlen(fromfile) < sizeof(fromfile) - 5) {
04368             strcat(fromfile, ".txt");
04369          }
04370          if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04371             if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04372                ast_copy_string(origcallerid, v, sizeof(origcallerid));
04373             }
04374 
04375             /* You might be tempted to do origdate, except that a) it's in the wrong
04376              * format, and b) it's missing for IMAP recordings. */
04377             if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04378                struct timeval tv = { inttime, };
04379                struct ast_tm tm;
04380                ast_localtime(&tv, &tm, NULL);
04381                ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
04382             }
04383             fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04384                " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04385                "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04386                " chance.  Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04387                msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04388                date, origcallerid, origdate);
04389             ast_config_destroy(msg_cfg);
04390          } else {
04391             goto plain_message;
04392          }
04393       } else {
04394 plain_message:
04395          fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04396             "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04397             "want to check it when you get a chance.  Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04398             ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04399             (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04400       }
04401    } else {
04402       fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04403             "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04404    }
04405 
04406    if (imap || attach_user_voicemail) {
04407       if (!ast_strlen_zero(attach2)) {
04408          snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04409          ast_debug(5, "creating second attachment filename %s\n", filename);
04410          add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04411          snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04412          ast_debug(5, "creating attachment filename %s\n", filename);
04413          add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04414       } else {
04415          snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04416          ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04417          add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04418       }
04419    }
04420    ast_free(str1);
04421    ast_free(str2);
04422 }

static int make_file ( char *  dest,
const int  len,
const char *  dir,
const int  num 
) [static]

Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.

Parameters:
dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
len The length of the path string that was written out.
The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns:
zero on success, -1 on error.

Definition at line 1463 of file app_voicemail.c.

Referenced by advanced_options(), close_mailbox(), copy_message(), leave_voicemail(), make_email_file(), notify_new_message(), play_message(), prep_email_sub_vars(), save_to_folder(), vm_execmain(), and vm_forwardoptions().

01464 {
01465    return snprintf(dest, len, "%s/msg%04d", dir, num);
01466 }

static int manager_list_voicemail_users ( struct mansession s,
const struct message m 
) [static]

Manager list voicemail users command.

Definition at line 10447 of file app_voicemail.c.

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, astman_append(), astman_get_header(), astman_send_ack(), ast_vm_user::attachfmt, ast_vm_user::callback, ast_vm_user::context, count_messages(), ast_vm_user::dialout, ast_vm_user::email, ast_vm_user::exit, ast_vm_user::fullname, inboxcount(), ast_vm_user::language, ast_vm_user::mailbox, ast_vm_user::mailcmd, make_dir(), ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::pager, RESULT_SUCCESS, ast_vm_user::saydurationm, ast_vm_user::serveremail, ast_vm_user::uniqueid, VM_ATTACH, VM_DELETE, VM_ENVELOPE, VM_OPERATOR, VM_REVIEW, VM_SAYCID, ast_vm_user::volgain, and ast_vm_user::zonetag.

Referenced by load_module().

10448 {
10449    struct ast_vm_user *vmu = NULL;
10450    const char *id = astman_get_header(m, "ActionID");
10451    char actionid[128] = "";
10452 
10453    if (!ast_strlen_zero(id))
10454       snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
10455 
10456    AST_LIST_LOCK(&users);
10457 
10458    if (AST_LIST_EMPTY(&users)) {
10459       astman_send_ack(s, m, "There are no voicemail users currently defined.");
10460       AST_LIST_UNLOCK(&users);
10461       return RESULT_SUCCESS;
10462    }
10463    
10464    astman_send_ack(s, m, "Voicemail user list will follow");
10465    
10466    AST_LIST_TRAVERSE(&users, vmu, list) {
10467       char dirname[256];
10468 
10469 #ifdef IMAP_STORAGE
10470       int new, old;
10471       inboxcount(vmu->mailbox, &new, &old);
10472 #endif
10473       
10474       make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
10475       astman_append(s,
10476          "%s"
10477          "Event: VoicemailUserEntry\r\n"
10478          "VMContext: %s\r\n"
10479          "VoiceMailbox: %s\r\n"
10480          "Fullname: %s\r\n"
10481          "Email: %s\r\n"
10482          "Pager: %s\r\n"
10483          "ServerEmail: %s\r\n"
10484          "MailCommand: %s\r\n"
10485          "Language: %s\r\n"
10486          "TimeZone: %s\r\n"
10487          "Callback: %s\r\n"
10488          "Dialout: %s\r\n"
10489          "UniqueID: %s\r\n"
10490          "ExitContext: %s\r\n"
10491          "SayDurationMinimum: %d\r\n"
10492          "SayEnvelope: %s\r\n"
10493          "SayCID: %s\r\n"
10494          "AttachMessage: %s\r\n"
10495          "AttachmentFormat: %s\r\n"
10496          "DeleteMessage: %s\r\n"
10497          "VolumeGain: %.2f\r\n"
10498          "CanReview: %s\r\n"
10499          "CallOperator: %s\r\n"
10500          "MaxMessageCount: %d\r\n"
10501          "MaxMessageLength: %d\r\n"
10502          "NewMessageCount: %d\r\n"
10503 #ifdef IMAP_STORAGE
10504          "OldMessageCount: %d\r\n"
10505          "IMAPUser: %s\r\n"
10506 #endif
10507          "\r\n",
10508          actionid,
10509          vmu->context,
10510          vmu->mailbox,
10511          vmu->fullname,
10512          vmu->email,
10513          vmu->pager,
10514          vmu->serveremail,
10515          vmu->mailcmd,
10516          vmu->language,
10517          vmu->zonetag,
10518          vmu->callback,
10519          vmu->dialout,
10520          vmu->uniqueid,
10521          vmu->exit,
10522          vmu->saydurationm,
10523          ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
10524          ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
10525          ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
10526          vmu->attachfmt,
10527          ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
10528          vmu->volgain,
10529          ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
10530          ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
10531          vmu->maxmsg,
10532          vmu->maxsecs,
10533 #ifdef IMAP_STORAGE
10534          new, old, vmu->imapuser
10535 #else
10536          count_messages(vmu, dirname)
10537 #endif
10538          );
10539    }     
10540    astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
10541 
10542    AST_LIST_UNLOCK(&users);
10543 
10544    return RESULT_SUCCESS;
10545 }

static void* mb_poll_thread ( void *  data  )  [static]

Definition at line 10281 of file app_voicemail.c.

References ast_cond_timedwait(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_tvadd(), ast_tvnow(), poll_lock, and poll_subscribed_mailboxes().

Referenced by start_poll_thread().

10282 {
10283    while (poll_thread_run) {
10284       struct timespec ts = { 0, };
10285       struct timeval wait;
10286 
10287       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
10288       ts.tv_sec = wait.tv_sec;
10289       ts.tv_nsec = wait.tv_usec * 1000;
10290 
10291       ast_mutex_lock(&poll_lock);
10292       ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
10293       ast_mutex_unlock(&poll_lock);
10294 
10295       if (!poll_thread_run)
10296          break;
10297 
10298       poll_subscribed_mailboxes();
10299    }
10300 
10301    return NULL;
10302 }

static const char* mbox ( int  id  )  [static]

static int messagecount ( const char *  context,
const char *  mailbox,
const char *  folder 
) [static]

Definition at line 4986 of file app_voicemail.c.

References __has_voicemail().

Referenced by load_module().

04987 {
04988    return __has_voicemail(context, mailbox, folder, 0);
04989 }

static void mwi_sub_destroy ( struct mwi_sub mwi_sub  )  [static]

Definition at line 10304 of file app_voicemail.c.

References ast_free.

Referenced by handle_unsubscribe().

10305 {
10306    ast_free(mwi_sub);
10307 }

static void mwi_sub_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 10382 of file app_voicemail.c.

References ast_calloc, ast_event_get_ie_str(), ast_event_get_ie_uint(), ast_event_get_type(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_UNIQUEID, AST_EVENT_MWI, AST_EVENT_SUB, ast_free, ast_log(), ast_strdup, ast_taskprocessor_push(), mwi_sub_task::context, handle_subscribe(), LOG_ERROR, mwi_sub_task::mailbox, mwi_subscription_tps, and mwi_sub_task::uniqueid.

Referenced by start_poll_thread().

10383 {
10384    struct mwi_sub_task *mwist;
10385    
10386    if (ast_event_get_type(event) != AST_EVENT_SUB)
10387       return;
10388 
10389    if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10390       return;
10391 
10392    if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
10393       ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
10394       return;
10395    }
10396    mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
10397    mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
10398    mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10399    
10400    if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
10401       ast_free(mwist);
10402    }
10403 }

static void mwi_unsub_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 10366 of file app_voicemail.c.

References ast_calloc, ast_event_get_ie_uint(), ast_event_get_type(), AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_UNIQUEID, AST_EVENT_MWI, AST_EVENT_UNSUB, ast_free, ast_taskprocessor_push(), handle_unsubscribe(), mwi_subscription_tps, and mwi_sub_task::uniqueid.

Referenced by start_poll_thread().

10367 {
10368    uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
10369    if (ast_event_get_type(event) != AST_EVENT_UNSUB)
10370       return;
10371 
10372    if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10373       return;
10374 
10375    u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10376    *uniqueid = u;
10377    if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
10378       ast_free(uniqueid);
10379    }
10380 }

static int notify_new_message ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
int  msgnum,
long  duration,
char *  fmt,
char *  cidnum,
char *  cidname,
const char *  flag 
) [static]

Sends email notification that a user has a new voicemail waiting for them.

Parameters:
chan 
vmu 
vms 
msgnum 
duration 
fmt 
cidnum The Caller ID phone number value.
cidname The Caller ID name value.
Returns:
zero on success, -1 on error.

Definition at line 6501 of file app_voicemail.c.

References ast_app_has_voicemail(), ast_app_inboxcount2(), ast_channel_lock, ast_channel_unlock, ast_log(), AST_LOG_WARNING, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_vm_user::attachfmt, ast_vm_user::context, vm_state::curmsg, DELETE, DISPOSE, ast_vm_user::email, EVENT_FLAG_CALL, globalflags, ast_vm_user::mailbox, make_dir(), make_file(), manager_event, mbox(), vm_state::newmessages, ast_vm_user::pager, pbx_builtin_getvar_helper(), queue_mwi_event(), RETRIEVE, run_externnotify(), sendmail(), sendpage(), ast_vm_user::serveremail, strsep(), VM_ATTACH, vm_delete(), and VM_DELETE.

06502 {
06503    char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06504    int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06505    const char *category;
06506    char *myserveremail = serveremail;
06507 
06508    ast_channel_lock(chan);
06509    if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06510       category = ast_strdupa(category);
06511    }
06512    ast_channel_unlock(chan);
06513 
06514    make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
06515    make_file(fn, sizeof(fn), todir, msgnum);
06516    snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06517 
06518    if (!ast_strlen_zero(vmu->attachfmt)) {
06519       if (strstr(fmt, vmu->attachfmt))
06520          fmt = vmu->attachfmt;
06521       else
06522          ast_log(AST_LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'.  Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
06523    }
06524 
06525    /* Attach only the first format */
06526    fmt = ast_strdupa(fmt);
06527    stringp = fmt;
06528    strsep(&stringp, "|");
06529 
06530    if (!