Sat Apr 26 2014 22:01:52

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/strings.h"
#include "asterisk/smdi.h"
#include "asterisk/astobj2.h"
#include "asterisk/event.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/test.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  inprocess
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 DATA_EXPORT_VM_USERS(USER)
#define DATA_EXPORT_VM_ZONES(ZONE)
#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 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 MSG_ID_LEN   256
#define OPERATOR_EXIT   300
#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 /* 1 second */
#define STORE(a, b, c, d, e, f, g, h, i, j, k)
#define tdesc   "Comedian Mail (Voicemail System)"
#define UPDATE_MSG_ID(a, b, c, d, e, f)
#define VALID_DTMF   "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
#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 int __has_voicemail (const char *context, const char *mailbox, const char *folder, int shortcircuit)
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 acf_vm_info (struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
static int actual_load_config (int reload, struct ast_config *cfg, struct ast_config *ucfg)
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 int add_message_id (struct ast_config *msg_cfg, char *dir, int msg, char *filename, char *id, size_t id_size, struct ast_vm_user *vmu, int folder)
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.
 AST_DATA_STRUCTURE (ast_vm_user, DATA_EXPORT_VM_USERS)
 AST_DATA_STRUCTURE (vm_zone, DATA_EXPORT_VM_ZONES)
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.
 AST_TEST_DEFINE (test_voicemail_vmuser)
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, const char *dest_folder)
 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 void generate_msg_id (char *dst)
 Sets the destination string to a uniquely identifying msg_id string.
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 inprocess_cmp_fn (void *obj, void *arg, int flags)
static int inprocess_count (const char *context, const char *mailbox, int delta)
static int inprocess_hash_fn (const void *obj, const int flags)
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, const char *msg_id)
 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 (struct ast_vm_user *vmu, int id)
static int message_range_and_existence_check (struct vm_state *vms, const char *msg_ids[], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu)
 common bounds checking and existence check for Voicemail API functions.
static int messagecount (const char *context, const char *mailbox, const char *folder)
static int msg_create_from_file (struct ast_vm_recording_data *recdata)
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 void notify_new_state (struct ast_vm_user *vmu)
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_by_id (struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
 Finds a message in a specific mailbox by msg_id and plays it to the channel.
static int play_message_by_id_helper (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, const char *msg_id)
static int play_message_callerid (struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
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, int *sound_duration, const char *unlockdir, signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id)
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 resequence_mailbox (struct ast_vm_user *vmu, char *dir, int stopcount)
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, int *newmsg, int move)
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, const char *msg_id)
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_and_high (const char *input, char *buf, size_t buflen)
 Strips control and non 7-bit clean characters from input string.
static const char * substitute_escapes (const char *value)
static int unload_module (void)
static int valid_config (const struct ast_config *cfg)
 Check if configuration file is valid.
static int vm_allocate_dh (struct vm_state *vms, struct ast_vm_user *vmu, int count_msg)
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_vi (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Vietnamese 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 const char * vm_index_to_foldername (int id)
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_cs (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_vi (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 struct
ast_vm_mailbox_snapshot
vm_mailbox_snapshot_create (const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
static struct
ast_vm_mailbox_snapshot
vm_mailbox_snapshot_destroy (struct ast_vm_mailbox_snapshot *mailbox_snapshot)
static FILE * vm_mkftemp (char *template)
static int vm_msg_forward (const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old)
static int vm_msg_move (const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder)
static int vm_msg_play (struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb)
static int vm_msg_remove (const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[])
static struct ast_vm_msg_snapshotvm_msg_snapshot_alloc (void)
static int vm_msg_snapshot_create (struct ast_vm_user *vmu, struct vm_state *vms, struct ast_vm_mailbox_snapshot *mailbox_snapshot, int snapshot_index, int mailbox_index, int descending, enum ast_vm_snapshot_sort_val sort_val)
 Create and store off all the msgs in an open mailbox.
static struct ast_vm_msg_snapshotvm_msg_snapshot_destroy (struct ast_vm_msg_snapshot *msg_snapshot)
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_playmsgexec (struct ast_channel *chan, const char *data)
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 vm_users_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static int vm_users_data_provider_get_helper (const struct ast_data_search *search, struct ast_data *data_root, struct ast_vm_user *user)
static int vmauthenticate (struct ast_channel *chan, const char *data)
static int vmsayname_exec (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, .nonoptreq = "res_adsi,res_smdi", }
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}
struct ao2_containerinprocess_container
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 char locale [20]
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 int msg_id_incrementor
static struct ast_event_submwi_sub_sub
static struct mwi_subs mwi_subs
static struct ast_taskprocessormwi_subscription_tps
static struct ast_event_submwi_unsub_sub
static int my_umask
static char * pagerbody = NULL
static char pagerdateformat [32] = "%A, %B %d, %Y at %r"
static char pagerfromstring [100]
static char * pagersubject = NULL
static int passwordlocation
static char * playmsg_app = "VoiceMailPlayMsg"
static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER
static unsigned int poll_freq
static ast_mutex_t poll_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
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 * sayname_app = "VMSayName"
static char serveremail [80]
static int silencethreshold = 128
static int skipms
static struct ast_smdi_interfacesmdi_iface = NULL
static struct users users
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 struct ast_data_entry vm_data_providers []
static struct ast_custom_function vm_info_acf
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_prepend_timeout [80] = "vm-then-pound"
static char vm_reenterpassword [80] = "vm-reenterpassword"
static char VM_SPOOL_DIR [PATH_MAX]
static struct ast_data_handler vm_users_data_provider
static char vmfmts [80]
static int vmmaxsecs
static int vmminsecs
static double volgain
static struct zones zones
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, https://wiki.asterisk.org/wiki/display/AST/IMAP+Voicemail+Storage
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 525 of file app_voicemail.c.

Referenced by actual_load_config().

#define BASELINELEN   72

Definition at line 548 of file app_voicemail.c.

Referenced by ochar().

#define BASEMAXINLINE   256

Definition at line 549 of file app_voicemail.c.

Referenced by base_encode(), and inbuf().

#define CHUNKSIZE   65536

Definition at line 522 of file app_voicemail.c.

#define COMMAND_TIMEOUT   5000

Definition at line 518 of file app_voicemail.c.

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

Definition at line 861 of file app_voicemail.c.

Referenced by copy_message(), and save_to_folder().

#define DATA_EXPORT_VM_USERS (   USER)

Definition at line 12355 of file app_voicemail.c.

#define DATA_EXPORT_VM_ZONES (   ZONE)
Value:
ZONE(vm_zone, name, AST_DATA_STRING)      \
   ZONE(vm_zone, timezone, AST_DATA_STRING)  \
   ZONE(vm_zone, msg_format, AST_DATA_STRING)

Definition at line 12382 of file app_voicemail.c.

Definition at line 530 of file app_voicemail.c.

Referenced by actual_load_config().

Definition at line 532 of file app_voicemail.c.

Referenced by actual_load_config().

Definition at line 533 of file app_voicemail.c.

Referenced by actual_load_config().

Definition at line 531 of file app_voicemail.c.

Referenced by actual_load_config().

#define DEFAULT_LISTEN_CONTROL_STOP_KEY   "13456789"

Definition at line 534 of file app_voicemail.c.

Referenced by actual_load_config().

#define DEFAULT_POLL_FREQ   30

By default, poll every 30 seconds

Definition at line 934 of file app_voicemail.c.

Referenced by actual_load_config().

#define DELETE (   a,
  b,
  c,
 
)    (vm_delete(c))
#define ENDL   "\n"

Definition at line 553 of file app_voicemail.c.

Referenced by add_email_attachment(), base_encode(), make_email_file(), ochar(), and sendpage().

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

Definition at line 859 of file app_voicemail.c.

Referenced by close_mailbox(), copy_message(), resequence_mailbox(), 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 541 of file app_voicemail.c.

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

#define MAX_DATETIME_FORMAT   512

Definition at line 556 of file app_voicemail.c.

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 557 of file app_voicemail.c.

Referenced by actual_load_config(), and play_message_callerid().

#define MAXMSG   100

Definition at line 543 of file app_voicemail.c.

Referenced by actual_load_config(), and apply_option().

#define MAXMSGLIMIT   9999

Definition at line 544 of file app_voicemail.c.

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

#define MINPASSWORD   0

Default minimum mailbox password length

Definition at line 546 of file app_voicemail.c.

Referenced by actual_load_config().

#define MSG_ID_LEN   256
#define OPERATOR_EXIT   300

Definition at line 579 of file app_voicemail.c.

Referenced by leave_voicemail(), vm_exec(), and vm_execmain().

#define PWDCHANGE_EXTERNAL   (1 << 2)

Definition at line 875 of file app_voicemail.c.

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

#define PWDCHANGE_INTERNAL   (1 << 1)

Definition at line 874 of file app_voicemail.c.

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

#define RENAME (   a,
  b,
  c,
  d,
  e,
  f,
  g,
 
)    (rename_file(g,h));
#define SENDMAIL   "/usr/sbin/sendmail -t"

Definition at line 539 of file app_voicemail.c.

Referenced by actual_load_config().

#define SMDI_MWI_WAIT_TIMEOUT   1000 /* 1 second */

Definition at line 516 of file app_voicemail.c.

Referenced by run_externnotify().

#define STORE (   a,
  b,
  c,
  d,
  e,
  f,
  g,
  h,
  i,
  j,
 
)
#define tdesc   "Comedian Mail (Voicemail System)"

Definition at line 884 of file app_voicemail.c.

#define UPDATE_MSG_ID (   a,
  b,
  c,
  d,
  e,
  f 
)

Definition at line 863 of file app_voicemail.c.

Referenced by add_message_id().

#define VALID_DTMF   "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */

Definition at line 535 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 572 of file app_voicemail.c.

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

#define VM_ATTACH   (1 << 11)

Attach message to voicemail notifications?

Definition at line 570 of file app_voicemail.c.

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

#define VM_DELETE   (1 << 12)

Delete message after sending notification

Definition at line 571 of file app_voicemail.c.

Referenced by apply_option(), AST_TEST_DEFINE(), 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 569 of file app_voicemail.c.

Referenced by actual_load_config(), and forward_message().

#define VM_ENVELOPE   (1 << 4)

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

Definition at line 563 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), manager_list_voicemail_users(), and play_message().

#define VM_FORCEGREET   (1 << 8)

Have new users record their greetings

Definition at line 567 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), vm_execmain(), and vm_newuser().

#define VM_FORCENAME   (1 << 7)

Have new users record their name

Definition at line 566 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), vm_execmain(), and vm_newuser().

#define VM_FWDURGAUTO   (1 << 18)

Autoset of Urgent flag on forwarded Urgent messages set globally

Definition at line 577 of file app_voicemail.c.

Referenced by actual_load_config(), and forward_message().

#define VM_MESSAGEWRAP   (1 << 17)

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

Definition at line 576 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), vm_execmain(), and vm_instructions_en().

#define VM_MOVEHEARD   (1 << 16)

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

Definition at line 575 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), and close_mailbox().

#define VM_OPERATOR   (1 << 1)

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

Definition at line 560 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), leave_voicemail(), 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 568 of file app_voicemail.c.

Referenced by actual_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 559 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), manager_list_voicemail_users(), and play_record_review().

#define VM_SAYCID   (1 << 2)

Repeat the CallerID info during envelope playback

Definition at line 561 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), manager_list_voicemail_users(), and play_message().

#define VM_SAYDURATION   (1 << 5)

Play the length of the message during envelope playback

Definition at line 564 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), and play_message().

#define VM_SEARCH   (1 << 14)

Search all contexts for a matching mailbox

Definition at line 573 of file app_voicemail.c.

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

#define VM_SKIPAFTERCMD   (1 << 6)

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

Definition at line 565 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), and vm_execmain().

#define VM_SVMAIL   (1 << 3)

Allow the user to compose a new VM from within VoicemailMain

Definition at line 562 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), and vm_execmain().

#define VM_TEMPGREETWARN   (1 << 15)

Remind user tempgreeting is set

Definition at line 574 of file app_voicemail.c.

Referenced by actual_load_config(), apply_option(), AST_TEST_DEFINE(), and vm_intro().

#define VMSTATE_MAX_MSG_ARRAY   256

Definition at line 793 of file app_voicemail.c.

#define VOICEMAIL_CONFIG   "voicemail.conf"

Definition at line 524 of file app_voicemail.c.

Referenced by load_config(), and vm_change_password().

#define VOICEMAIL_DIR_MODE   0777

Definition at line 520 of file app_voicemail.c.

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

#define VOICEMAIL_FILE_MODE   0666

Enumeration Type Documentation

enum vm_box
Enumerator:
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 

Definition at line 581 of file app_voicemail.c.

Enumerator:
OPT_ARG_RECORDGAIN 
OPT_ARG_PLAYFOLDER 
OPT_ARG_DTMFEXIT 
OPT_ARG_ARRAY_SIZE 

Definition at line 602 of file app_voicemail.c.

                    {
   OPT_ARG_RECORDGAIN = 0,
   OPT_ARG_PLAYFOLDER = 1,
   OPT_ARG_DTMFEXIT   = 2,
   /* This *must* be the last value in this enum! */
   OPT_ARG_ARRAY_SIZE = 3,
};
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 590 of file app_voicemail.c.

                     {
   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)
};
Enumerator:
OPT_PWLOC_VOICEMAILCONF 
OPT_PWLOC_SPOOLDIR 
OPT_PWLOC_USERSCONF 

Definition at line 610 of file app_voicemail.c.


Function Documentation

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

Definition at line 5745 of file app_voicemail.c.

References ast_strlen_zero().

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

{
   DIR *dir;
   struct dirent *de;
   char fn[256];
   int ret = 0;

   /* If no mailbox, return immediately */
   if (ast_strlen_zero(mailbox))
      return 0;

   if (ast_strlen_zero(folder))
      folder = "INBOX";
   if (ast_strlen_zero(context))
      context = "default";

   snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);

   if (!(dir = opendir(fn)))
      return 0;

   while ((de = readdir(dir))) {
      if (!strncasecmp(de->d_name, "msg", 3)) {
         if (shortcircuit) {
            ret = 1;
            break;
         } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
            ret++;
         }
      }
   }

   closedir(dir);

   return ret;
}
static void __reg_module ( void  ) [static]

Definition at line 15653 of file app_voicemail.c.

static void __unreg_module ( void  ) [static]

Definition at line 15653 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 11970 of file app_voicemail.c.

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

{
   struct ast_vm_user svm;
   AST_DECLARE_APP_ARGS(arg,
      AST_APP_ARG(mbox);
      AST_APP_ARG(context);
   );
   static int dep_warning = 0;

   AST_NONSTANDARD_APP_ARGS(arg, args, '@');

   if (ast_strlen_zero(arg.mbox)) {
      ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
      return -1;
   }

   if (!dep_warning) {
      dep_warning = 1;
      ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated.  Please use ${VM_INFO(%s,exists)} instead.\n", args);
   }

   ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
   return 0;
}
static int acf_vm_info ( struct ast_channel chan,
const char *  cmd,
char *  args,
char *  buf,
size_t  len 
) [static]

Definition at line 11995 of file app_voicemail.c.

References AST_APP_ARG, ast_channel_language(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_defaultlanguage, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), context, ast_vm_user::email, find_user(), ast_vm_user::fullname, ast_vm_user::language, ast_vm_user::locale, LOG_ERROR, mailbox, messagecount(), ast_vm_user::pager, parse(), ast_vm_user::password, S_OR, and ast_vm_user::zonetag.

{
   struct ast_vm_user svm;
   struct ast_vm_user *vmu = NULL;
   char *tmp, *mailbox, *context, *parse;
   int res = 0;

   AST_DECLARE_APP_ARGS(arg,
      AST_APP_ARG(mailbox_context);
      AST_APP_ARG(attribute);
      AST_APP_ARG(folder);
   );

   buf[0] = '\0';

   if (ast_strlen_zero(args)) {
      ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
      return -1;
   }

   parse = ast_strdupa(args);
   AST_STANDARD_APP_ARGS(arg, parse);

   if (ast_strlen_zero(arg.mailbox_context) || ast_strlen_zero(arg.attribute)) {
      ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
      return -1;
   }

   tmp = ast_strdupa(arg.mailbox_context);
   mailbox = strsep(&tmp, "@");
   context = strsep(&tmp, "");

   if (ast_strlen_zero(context)) {
       context = "default";
   }

   vmu = find_user(&svm, context, mailbox);

   if (!strncasecmp(arg.attribute, "exists", 5)) {
      ast_copy_string(buf, vmu ? "1" : "0", len);
      return 0;
   }

   if (vmu) {
      if (!strncasecmp(arg.attribute, "password", 8)) {
         ast_copy_string(buf, vmu->password, len);
      } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
         ast_copy_string(buf, vmu->fullname, len);
      } else if (!strncasecmp(arg.attribute, "email", 5)) {
         ast_copy_string(buf, vmu->email, len);
      } else if (!strncasecmp(arg.attribute, "pager", 5)) {
         ast_copy_string(buf, vmu->pager, len);
      } else if (!strncasecmp(arg.attribute, "language", 8)) {
         const char *lang = S_OR(vmu->language, chan ?
            ast_channel_language(chan) : ast_defaultlanguage);
         ast_copy_string(buf, lang, len);
      } else if (!strncasecmp(arg.attribute, "locale", 6)) {
         ast_copy_string(buf, vmu->locale, len);
      } else if (!strncasecmp(arg.attribute, "tz", 2)) {
         ast_copy_string(buf, vmu->zonetag, len);
      } else if (!strncasecmp(arg.attribute, "count", 5)) {
         /* If mbxfolder is empty messagecount will default to INBOX */
         res = messagecount(context, mailbox, arg.folder);
         if (res < 0) {
            ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
            return -1;
         }
         snprintf(buf, len, "%d", res);
      } else {
         ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
         return -1;
      }
   }

   return 0;
}
static int actual_load_config ( int  reload,
struct ast_config cfg,
struct ast_config ucfg 
) [static]

Definition at line 12899 of file app_voicemail.c.

References append_mailbox(), apply_options_full(), ast_category_browse(), ast_config_option(), ast_copy_string(), ast_debug, ast_dsp_get_threshold_from_settings(), ast_false(), ast_format_str_reduce(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, ast_malloc, AST_PTHREADT_NULL, ast_set2_flag, ast_smdi_interface_find(), ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ASTERISK_USERNAME, 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, find_or_create(), free_vm_users(), free_vm_zones(), is_valid_dtmf(), ast_variable::lineno, LOG_ERROR, ast_vm_user::mailbox, MAX_NUM_CID_CONTEXTS, MAXMSG, MAXMSGLIMIT, MINPASSWORD, vm_zone::msg_format, ast_variable::name, vm_zone::name, ast_variable::next, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_USERSCONF, OPT_PWLOC_VOICEMAILCONF, ast_vm_user::password, ast_vm_user::passwordlocation, populate_defaults(), PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, read_password_from_file(), SENDMAIL, start_poll_thread(), stop_poll_thread(), substitute_escapes(), THRESHOLD_SILENCE, vm_zone::timezone, ast_variable::value, var, VM_ATTACH, VM_DIRECFORWARD, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_FWDURGAUTO, VM_MESSAGEWRAP, VM_MOVEHEARD, VM_OPERATOR, VM_PBXSKIP, VM_REVIEW, VM_SAYCID, VM_SAYDURATION, VM_SEARCH, VM_SKIPAFTERCMD, VM_SVMAIL, and VM_TEMPGREETWARN.

Referenced by load_config().

{
   struct ast_vm_user *current;
   char *cat;
   struct ast_variable *var;
   const char *val;
   char *q, *stringp, *tmp;
   int x;
   int tmpadsi[4];
   char secretfn[PATH_MAX] = "";

#ifdef IMAP_STORAGE
   ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
#endif
   /* set audio control prompts */
   strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
   strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
   strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
   strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
   strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);

   /* Free all the users structure */  
   free_vm_users();

   /* Free all the zones structure */
   free_vm_zones();

   AST_LIST_LOCK(&users);  

   memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
   memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));

   if (cfg) {
      /* General settings */

      if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
         val = "default";
      ast_copy_string(userscontext, val, sizeof(userscontext));
      /* Attach voice message to mail message ? */
      if (!(val = ast_variable_retrieve(cfg, "general", "attach"))) 
         val = "yes";
      ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH); 

      if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
         val = "no";
      ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);

      volgain = 0.0;
      if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
         sscanf(val, "%30lf", &volgain);

#ifdef ODBC_STORAGE
      strcpy(odbc_database, "asterisk");
      if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
         ast_copy_string(odbc_database, val, sizeof(odbc_database));
      }
      strcpy(odbc_table, "voicemessages");
      if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
         ast_copy_string(odbc_table, val, sizeof(odbc_table));
      }
#endif      
      /* Mail command */
      strcpy(mailcmd, SENDMAIL);
      if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
         ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */

      maxsilence = 0;
      if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
         maxsilence = atoi(val);
         if (maxsilence > 0)
            maxsilence *= 1000;
      }
      
      if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
         maxmsg = MAXMSG;
      } else {
         maxmsg = atoi(val);
         if (maxmsg < 0) {
            ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
            maxmsg = MAXMSG;
         } else if (maxmsg > MAXMSGLIMIT) {
            ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
            maxmsg = MAXMSGLIMIT;
         }
      }

      if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
         maxdeletedmsg = 0;
      } else {
         if (sscanf(val, "%30d", &x) == 1)
            maxdeletedmsg = x;
         else if (ast_true(val))
            maxdeletedmsg = MAXMSG;
         else
            maxdeletedmsg = 0;

         if (maxdeletedmsg < 0) {
            ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
            maxdeletedmsg = MAXMSG;
         } else if (maxdeletedmsg > MAXMSGLIMIT) {
            ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
            maxdeletedmsg = MAXMSGLIMIT;
         }
      }

      /* Load date format config for voicemail mail */
      if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
         ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
      }

      /* Load date format config for voicemail pager mail */
      if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
         ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
      }

      /* External password changing command */
      if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
         ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
         pwdchange = PWDCHANGE_EXTERNAL;
      } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
         ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
         pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
      }

      /* External password validation command */
      if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
         ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
         ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd);
      }

#ifdef IMAP_STORAGE
      /* IMAP server address */
      if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
         ast_copy_string(imapserver, val, sizeof(imapserver));
      } else {
         ast_copy_string(imapserver, "localhost", sizeof(imapserver));
      }
      /* IMAP server port */
      if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
         ast_copy_string(imapport, val, sizeof(imapport));
      } else {
         ast_copy_string(imapport, "143", sizeof(imapport));
      }
      /* IMAP server flags */
      if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
         ast_copy_string(imapflags, val, sizeof(imapflags));
      }
      /* IMAP server master username */
      if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
         ast_copy_string(authuser, val, sizeof(authuser));
      }
      /* IMAP server master password */
      if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
         ast_copy_string(authpassword, val, sizeof(authpassword));
      }
      /* Expunge on exit */
      if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
         if (ast_false(val))
            expungeonhangup = 0;
         else
            expungeonhangup = 1;
      } else {
         expungeonhangup = 1;
      }
      /* IMAP voicemail folder */
      if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
         ast_copy_string(imapfolder, val, sizeof(imapfolder));
      } else {
         ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
         ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
         imapgreetings = ast_true(val);
      } else {
         imapgreetings = 0;
      }
      if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
         ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
      } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
         /* Also support greetingsfolder as documented in voicemail.conf.sample */
         ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
      } else {
         ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
      }

      /* There is some very unorthodox casting done here. This is due
       * to the way c-client handles the argument passed in. It expects a 
       * void pointer and casts the pointer directly to a long without
       * first dereferencing it. */
      if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
         mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
      } else {
         mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
      }

      if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
         mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
      } else {
         mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
      }

      if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
         mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
      } else {
         mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
      }

      if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
         mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
      } else {
         mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
      }

      /* Increment configuration version */
      imapversion++;
#endif
      /* External voicemail notify application */
      if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
         ast_copy_string(externnotify, val, sizeof(externnotify));
         ast_debug(1, "found externnotify: %s\n", externnotify);
      } else {
         externnotify[0] = '\0';
      }

      /* SMDI voicemail notification */
      if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
         ast_debug(1, "Enabled SMDI voicemail notification\n");
         if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
            smdi_iface = ast_smdi_interface_find(val);
         } else {
            ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
            smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
         }
         if (!smdi_iface) {
            ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
         }
      }

      /* Silence treshold */
      silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
      if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
         silencethreshold = atoi(val);

      if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
         val = ASTERISK_USERNAME;
      ast_copy_string(serveremail, val, sizeof(serveremail));

      vmmaxsecs = 0;
      if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            vmmaxsecs = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
         }
      } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
         static int maxmessage_deprecate = 0;
         if (maxmessage_deprecate == 0) {
            maxmessage_deprecate = 1;
            ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
         }
         if (sscanf(val, "%30d", &x) == 1) {
            vmmaxsecs = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
         }
      }

      vmminsecs = 0;
      if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            vmminsecs = x;
            if (maxsilence / 1000 >= vmminsecs) {
               ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
            }
         } else {
            ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
         }
      } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
         static int maxmessage_deprecate = 0;
         if (maxmessage_deprecate == 0) {
            maxmessage_deprecate = 1;
            ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
         }
         if (sscanf(val, "%30d", &x) == 1) {
            vmminsecs = x;
            if (maxsilence / 1000 >= vmminsecs) {
               ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
            }
         } else {
            ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
         }
      }

      val = ast_variable_retrieve(cfg, "general", "format");
      if (!val) {
         val = "wav";   
      } else {
         tmp = ast_strdupa(val);
         val = ast_format_str_reduce(tmp);
         if (!val) {
            ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
            val = "wav";
         }
      }
      ast_copy_string(vmfmts, val, sizeof(vmfmts));

      skipms = 3000;
      if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            maxgreet = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
         }
      }

      if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            skipms = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
         }
      }

      maxlogins = 3;
      if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            maxlogins = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
         }
      }

      minpassword = MINPASSWORD;
      if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            minpassword = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid minimum password length.  Default to %d\n", minpassword);
         }
      }

      /* Force new user to record name ? */
      if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
         val = "no";
      ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);

      /* Force new user to record greetings ? */
      if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
         val = "no";
      ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);

      if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
         ast_debug(1, "VM_CID Internal context string: %s\n", val);
         stringp = ast_strdupa(val);
         for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
            if (!ast_strlen_zero(stringp)) {
               q = strsep(&stringp, ",");
               while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
                  q++;
               ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
               ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
            } else {
               cidinternalcontexts[x][0] = '\0';
            }
         }
      }
      if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
         ast_debug(1, "VM Review Option disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);

      /* Temporary greeting reminder */
      if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
         ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
         val = "no";
      } else {
         ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
      if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
         ast_debug(1, "VM next message wrap disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);

      if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
         ast_debug(1, "VM Operator break disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);

      if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
         ast_debug(1, "VM CID Info before msg disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);

      if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
         ast_debug(1, "Send Voicemail msg disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);

      if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
         ast_debug(1, "ENVELOPE before msg enabled globally\n");
         val = "yes";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);

      if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
         ast_debug(1, "Move Heard enabled globally\n");
         val = "yes";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);

      if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
         ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);

      if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
         ast_debug(1, "Duration info before msg enabled globally\n");
         val = "yes";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);

      saydurationminfo = 2;
      if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
         if (sscanf(val, "%30d", &x) == 1) {
            saydurationminfo = x;
         } else {
            ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
         }
      }

      if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
         ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
         val = "no";
      }
      ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);

      if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
         ast_copy_string(dialcontext, val, sizeof(dialcontext));
         ast_debug(1, "found dialout context: %s\n", dialcontext);
      } else {
         dialcontext[0] = '\0';
      }

      if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
         ast_copy_string(callcontext, val, sizeof(callcontext));
         ast_debug(1, "found callback context: %s\n", callcontext);
      } else {
         callcontext[0] = '\0';
      }

      if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
         ast_copy_string(exitcontext, val, sizeof(exitcontext));
         ast_debug(1, "found operator context: %s\n", exitcontext);
      } else {
         exitcontext[0] = '\0';
      }

      /* load password sounds configuration */
      if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
         ast_copy_string(vm_password, val, sizeof(vm_password));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
         ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
         ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
         ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
         ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
         ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
      if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
         ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
         ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
      }
      /* load configurable audio prompts */
      if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
         ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
      if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
         ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
      if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
         ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
      if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
         ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
      if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
         ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));

      if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
         val = "no";
      ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD); 

      if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
         val = "voicemail.conf";
      }
      if (!(strcmp(val, "spooldir"))) {
         passwordlocation = OPT_PWLOC_SPOOLDIR;
      } else {
         passwordlocation = OPT_PWLOC_VOICEMAILCONF;
      }

      poll_freq = DEFAULT_POLL_FREQ;
      if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
         if (sscanf(val, "%30u", &poll_freq) != 1) {
            poll_freq = DEFAULT_POLL_FREQ;
            ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
         }
      }

      poll_mailboxes = 0;
      if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
         poll_mailboxes = ast_true(val);

      memset(fromstring, 0, sizeof(fromstring));
      memset(pagerfromstring, 0, sizeof(pagerfromstring));
      strcpy(charset, "ISO-8859-1");
      if (emailbody) {
         ast_free(emailbody);
         emailbody = NULL;
      }
      if (emailsubject) {
         ast_free(emailsubject);
         emailsubject = NULL;
      }
      if (pagerbody) {
         ast_free(pagerbody);
         pagerbody = NULL;
      }
      if (pagersubject) {
         ast_free(pagersubject);
         pagersubject = NULL;
      }
      if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
         ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
      if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
         ast_copy_string(fromstring, val, sizeof(fromstring));
      if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
         ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
      if ((val = ast_variable_retrieve(cfg, "general", "charset")))
         ast_copy_string(charset, val, sizeof(charset));
      if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
         sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
         for (x = 0; x < 4; x++) {
            memcpy(&adsifdn[x], &tmpadsi[x], 1);
         }
      }
      if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
         sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
         for (x = 0; x < 4; x++) {
            memcpy(&adsisec[x], &tmpadsi[x], 1);
         }
      }
      if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
         if (atoi(val)) {
            adsiver = atoi(val);
         }
      }
      if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
         ast_copy_string(zonetag, val, sizeof(zonetag));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
         ast_copy_string(locale, val, sizeof(locale));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
         emailsubject = ast_strdup(substitute_escapes(val));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
         emailbody = ast_strdup(substitute_escapes(val));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
         pagersubject = ast_strdup(substitute_escapes(val));
      }
      if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
         pagerbody = ast_strdup(substitute_escapes(val));
      }

      /* load mailboxes from users.conf */
      if (ucfg) { 
         for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
            if (!strcasecmp(cat, "general")) {
               continue;
            }
            if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
               continue;
            if ((current = find_or_create(userscontext, cat))) {
               populate_defaults(current);
               apply_options_full(current, ast_variable_browse(ucfg, cat));
               ast_copy_string(current->context, userscontext, sizeof(current->context));
               if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
                  current->passwordlocation = OPT_PWLOC_USERSCONF;
               }

               switch (current->passwordlocation) {
               case OPT_PWLOC_SPOOLDIR:
                  snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
                  read_password_from_file(secretfn, current->password, sizeof(current->password));
               }
            }
         }
      }

      /* load mailboxes from voicemail.conf */
      cat = ast_category_browse(cfg, NULL);
      while (cat) {
         if (strcasecmp(cat, "general")) {
            var = ast_variable_browse(cfg, cat);
            if (strcasecmp(cat, "zonemessages")) {
               /* Process mailboxes in this context */
               while (var) {
                  append_mailbox(cat, var->name, var->value);
                  var = var->next;
               }
            } else {
               /* Timezones in this context */
               while (var) {
                  struct vm_zone *z;
                  if ((z = ast_malloc(sizeof(*z)))) {
                     char *msg_format, *tzone;
                     msg_format = ast_strdupa(var->value);
                     tzone = strsep(&msg_format, "|,");
                     if (msg_format) {
                        ast_copy_string(z->name, var->name, sizeof(z->name));
                        ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
                        ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
                        AST_LIST_LOCK(&zones);
                        AST_LIST_INSERT_HEAD(&zones, z, list);
                        AST_LIST_UNLOCK(&zones);
                     } else {
                        ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
                        ast_free(z);
                     }
                  } else {
                     AST_LIST_UNLOCK(&users);
                     return -1;
                  }
                  var = var->next;
               }
            }
         }
         cat = ast_category_browse(cfg, cat);
      }

      AST_LIST_UNLOCK(&users);

      if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
         start_poll_thread();
      if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
         stop_poll_thread();;

      return 0;
   } else {
      AST_LIST_UNLOCK(&users);
      ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
      return 0;
   }
}
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 5134 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().

{
   char tmpdir[256], newtmp[256];
   char fname[256];
   char tmpcmd[256];
   int tmpfd = -1;
   int soxstatus = 0;

   /* Eww. We want formats to tell us their own MIME type */
   char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";

   if (vmu->volgain < -.001 || vmu->volgain > .001) {
      create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
      snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
      tmpfd = mkstemp(newtmp);
      chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
      ast_debug(3, "newtmp: %s\n", newtmp);
      if (tmpfd > -1) {
         snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
         if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
            attach = newtmp;
            ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
         } else {
            ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
               soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
            ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
         }
      }
   }
   fprintf(p, "--%s" ENDL, bound);
   if (msgnum > -1)
      fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
   else
      fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
   fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
   fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
   if (msgnum > -1)
      fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
   else
      fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
   snprintf(fname, sizeof(fname), "%s.%s", attach, format);
   base_encode(fname, p);
   if (last)
      fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
   if (tmpfd > -1) {
      if (soxstatus == 0) {
         unlink(fname);
      }
      close(tmpfd);
      unlink(newtmp);
   }
   return 0;
}
static int add_message_id ( struct ast_config msg_cfg,
char *  dir,
int  msg,
char *  filename,
char *  id,
size_t  id_size,
struct ast_vm_user vmu,
int  folder 
) [static]

Definition at line 11616 of file app_voicemail.c.

References ast_category_get(), ast_config_text_file_save(), ast_log(), ast_variable_append(), ast_variable_new(), ast_variables_destroy(), generate_msg_id(), LOG_ERROR, LOG_WARNING, UPDATE_MSG_ID, and var.

Referenced by vm_msg_snapshot_create().

{
   struct ast_variable *var;
   struct ast_category *cat;
   generate_msg_id(id);

   var = ast_variable_new("msg_id", id, "");
   if (!var) {
      return -1;
   }

   cat = ast_category_get(msg_cfg, "message");
   if (!cat) {
      ast_log(LOG_ERROR, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
      ast_variables_destroy(var);
      return -1;
   }

   ast_variable_append(cat, var);

   if (ast_config_text_file_save(filename, msg_cfg, "app_voicemail")) {
      ast_log(LOG_WARNING, "Unable to update %s to have a message ID\n", filename);
      return -1;
   }

   UPDATE_MSG_ID(dir, msg, id, vmu, msg_cfg, folder);
   return 0;
}
static void adsi_begin ( struct ast_channel chan,
int *  useadsi 
) [static]

Definition at line 7075 of file app_voicemail.c.

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

Referenced by vm_authenticate(), and vm_execmain().

{
   int x;
   if (!ast_adsi_available(chan))
      return;
   x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
   if (x < 0)
      return;
   if (!x) {
      if (adsi_load_vmail(chan, useadsi)) {
         ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
         return;
      }
   } else
      *useadsi = 1;
}
static void adsi_delete ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 7271 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(), ast_mutex_lock, ast_mutex_unlock, vm_state::curmsg, vm_state::deleted, and vm_state::lastmsg.

Referenced by vm_execmain().

{
   int bytes = 0;
   unsigned char buf[256];
   unsigned char keys[8];

   int x;

   if (!ast_adsi_available(chan))
      return;

   /* New meaning for keys */
   for (x = 0; x < 5; x++)
      keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);

   keys[6] = 0x0;
   keys[7] = 0x0;

   if (!vms->curmsg) {
      /* No prev key, provide "Folder" instead */
      keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
   }
   if (vms->curmsg >= vms->lastmsg) {
      /* If last message ... */
      if (vms->curmsg) {
         /* but not only message, provide "Folder" instead */
         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
      } else {
         /* Otherwise if only message, leave blank */
         keys[3] = 1;
      }
   }

   /* If deleted, show "undeleted" */
#ifdef IMAP_STORAGE
   ast_mutex_lock(&vms->lock);
#endif
   if (vms->deleted[vms->curmsg]) {
      keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
   }
#ifdef IMAP_STORAGE
   ast_mutex_unlock(&vms->lock);
#endif

   /* Except "Exit" */
   keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
   bytes += ast_adsi_set_keys(buf + bytes, keys);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_folders ( struct ast_channel chan,
int  start,
char *  label 
) [static]

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

{
   unsigned char buf[256];
   int bytes = 0;
   unsigned char keys[8];
   int x, y;

   if (!ast_adsi_available(chan))
      return;

   for (x = 0; x < 5; x++) {
      y = ADSI_KEY_APPS + 12 + start + x;
      if (y > ADSI_KEY_APPS + 12 + 4)
         y = 0;
      keys[x] = ADSI_KEY_SKT | y;
   }
   keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
   keys[6] = 0;
   keys[7] = 0;

   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_set_keys(buf + bytes, keys);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_goodbye ( struct ast_channel chan) [static]

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

{
   unsigned char buf[256];
   int bytes = 0;

   if (!ast_adsi_available(chan))
      return;
   bytes += adsi_logo(buf + bytes);
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static int adsi_load_vmail ( struct ast_channel chan,
int *  useadsi 
) [static]

Definition at line 6946 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, 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, and mbox().

Referenced by adsi_begin().

{
   unsigned char buf[256];
   int bytes = 0;
   int x;
   char num[5];

   *useadsi = 0;
   bytes += ast_adsi_data_mode(buf + bytes);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);

   bytes = 0;
   bytes += adsi_logo(buf);
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
#ifdef DISPLAY
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
#endif
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_data_mode(buf + bytes);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);

   if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
      bytes = 0;
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
      bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
      bytes += ast_adsi_voice_mode(buf + bytes, 0);
      ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
      return 0;
   }

#ifdef DISPLAY
   /* Add a dot */
   bytes = 0;
   bytes += ast_adsi_logo(buf);
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif
   bytes = 0;
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);

#ifdef DISPLAY
   /* Add another dot */
   bytes = 0;
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif

   bytes = 0;
   /* These buttons we load but don't use yet */
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);

#ifdef DISPLAY
   /* Add another dot */
   bytes = 0;
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif

   bytes = 0;
   for (x = 0; x < 5; x++) {
      snprintf(num, sizeof(num), "%d", x);
      bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
   }
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);

#ifdef DISPLAY
   /* Add another dot */
   bytes = 0;
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif

   if (ast_adsi_end_download(chan)) {
      bytes = 0;
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
      bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
      bytes += ast_adsi_voice_mode(buf + bytes, 0);
      ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
      return 0;
   }
   bytes = 0;
   bytes += ast_adsi_download_disconnect(buf + bytes);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);

   ast_debug(1, "Done downloading scripts...\n");

#ifdef DISPLAY
   /* Add last dot */
   bytes = 0;
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
#endif
   ast_debug(1, "Restarting session...\n");

   bytes = 0;
   /* Load the session now */
   if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
      *useadsi = 1;
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
   } else
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
   return 0;
}
static void adsi_login ( struct ast_channel chan) [static]

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

{
   unsigned char buf[256];
   int bytes = 0;
   unsigned char keys[8];
   int x;
   if (!ast_adsi_available(chan))
      return;

   for (x = 0; x < 8; x++)
      keys[x] = 0;
   /* Set one key for next */
   keys[3] = ADSI_KEY_APPS + 3;

   bytes += adsi_logo(buf + bytes);
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
   bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
   bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
   bytes += ast_adsi_set_keys(buf + bytes, keys);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static int adsi_logo ( unsigned char *  buf) [static]

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

{
   int bytes = 0;
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
   return bytes;
}
static void adsi_message ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 7169 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_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), buf1, buf2, vm_state::curbox, vm_state::curmsg, vm_state::deleted, f, vm_state::fn, vm_state::lastmsg, and name.

Referenced by play_message(), and vm_execmain().

{
   int bytes = 0;
   unsigned char buf[256]; 
   char buf1[256], buf2[256];
   char fn2[PATH_MAX];

   char cid[256] = "";
   char *val;
   char *name, *num;
   char datetime[21] = "";
   FILE *f;

   unsigned char keys[8];

   int x;

   if (!ast_adsi_available(chan))
      return;

   /* Retrieve important info */
   snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
   f = fopen(fn2, "r");
   if (f) {
      while (!feof(f)) {   
         if (!fgets((char *) buf, sizeof(buf), f)) {
            continue;
         }
         if (!feof(f)) {
            char *stringp = NULL;
            stringp = (char *) buf;
            strsep(&stringp, "=");
            val = strsep(&stringp, "=");
            if (!ast_strlen_zero(val)) {
               if (!strcmp((char *) buf, "callerid"))
                  ast_copy_string(cid, val, sizeof(cid));
               if (!strcmp((char *) buf, "origdate"))
                  ast_copy_string(datetime, val, sizeof(datetime));
            }
         }
      }
      fclose(f);
   }
   /* New meaning for keys */
   for (x = 0; x < 5; x++)
      keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
   keys[6] = 0x0;
   keys[7] = 0x0;

   if (!vms->curmsg) {
      /* No prev key, provide "Folder" instead */
      keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
   }
   if (vms->curmsg >= vms->lastmsg) {
      /* If last message ... */
      if (vms->curmsg) {
         /* but not only message, provide "Folder" instead */
         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
         bytes += ast_adsi_voice_mode(buf + bytes, 0);

      } else {
         /* Otherwise if only message, leave blank */
         keys[3] = 1;
      }
   }

   if (!ast_strlen_zero(cid)) {
      ast_callerid_parse(cid, &name, &num);
      if (!name)
         name = num;
   } else {
      name = "Unknown Caller";
   }

   /* If deleted, show "undeleted" */
#ifdef IMAP_STORAGE
   ast_mutex_lock(&vms->lock);
#endif
   if (vms->deleted[vms->curmsg]) {
      keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
   }
#ifdef IMAP_STORAGE
   ast_mutex_unlock(&vms->lock);
#endif

   /* Except "Exit" */
   keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
   snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
      strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
   snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);

   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_set_keys(buf + bytes, keys);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_password ( struct ast_channel chan) [static]

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

{
   unsigned char buf[256];
   int bytes = 0;
   unsigned char keys[8];
   int x;
   if (!ast_adsi_available(chan))
      return;

   for (x = 0; x < 8; x++)
      keys[x] = 0;
   /* Set one key for next */
   keys[3] = ADSI_KEY_APPS + 3;

   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
   bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
   bytes += ast_adsi_set_keys(buf + bytes, keys);
   bytes += ast_adsi_voice_mode(buf + bytes, 0);
   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_status ( struct ast_channel chan,
struct vm_state vms 
) [static]

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

{
   unsigned char buf[256] = "";
   char buf1[256] = "", buf2[256] = "";
   int bytes = 0;
   unsigned char keys[8];
   int x;

   char *newm = (vms->newmessages == 1) ? "message" : "messages";
   char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
   if (!ast_adsi_available(chan))
      return;
   if (vms->newmessages) {
      snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
      if (vms->oldmessages) {
         strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
         snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
      } else {
         snprintf(buf2, sizeof(buf2), "%s.", newm);
      }
   } else if (vms->oldmessages) {
      snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
      snprintf(buf2, sizeof(buf2), "%s.", oldm);
   } else {
      strcpy(buf1, "You have no messages.");
      buf2[0] = ' ';
      buf2[1] = '\0';
   }
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);

   for (x = 0; x < 6; x++)
      keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
   keys[6] = 0;
   keys[7] = 0;

   /* Don't let them listen if there are none */
   if (vms->lastmsg < 0)
      keys[0] = 1;
   bytes += ast_adsi_set_keys(buf + bytes, keys);

   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_status2 ( struct ast_channel chan,
struct vm_state vms 
) [static]

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

{
   unsigned char buf[256] = "";
   char buf1[256] = "", buf2[256] = "";
   int bytes = 0;
   unsigned char keys[8];
   int x;

   char *mess = (vms->lastmsg == 0) ? "message" : "messages";

   if (!ast_adsi_available(chan))
      return;

   /* Original command keys */
   for (x = 0; x < 6; x++)
      keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);

   keys[6] = 0;
   keys[7] = 0;

   if ((vms->lastmsg + 1) < 1)
      keys[0] = 0;

   snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
      strcasecmp(vms->curbox, "INBOX") ? " folder" : "");

   if (vms->lastmsg + 1)
      snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
   else
      strcpy(buf2, "no messages.");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
   bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
   bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
   bytes += ast_adsi_set_keys(buf + bytes, keys);

   bytes += ast_adsi_voice_mode(buf + bytes, 0);

   ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
   
}
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_gainProvides handling for the play message envelope, call the person back, or reply to message.
Returns:
zero on success, -1 on error.

Definition at line 14370 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_strlen_zero(), ast_test_suite_event_notify, ast_variable_retrieve(), ast_verb, ast_waitfordigit(), ast_vm_user::callback, CONFIG_FLAG_NOCACHE, context, 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(), name, play_message_callerid(), play_message_datetime(), leave_vm_options::record_gain, RETRIEVE, vm_state::starting, valid_config(), and wait_file().

Referenced by vm_execmain().

{
   int res = 0;
   char filename[PATH_MAX];
   struct ast_config *msg_cfg = NULL;
   const char *origtime, *context;
   char *name, *num;
   int retries = 0;
   char *cid;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };

   vms->starting = 0; 

   make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);

   /* Retrieve info from VM attribute file */
   snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
   RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
   msg_cfg = ast_config_load(filename, config_flags);
   DISPOSE(vms->curdir, vms->curmsg);
   if (!valid_config(msg_cfg)) {
      ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
      return 0;
   }

   if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
      ast_config_destroy(msg_cfg);
      return 0;
   }

   cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));

   context = ast_variable_retrieve(msg_cfg, "message", "context");
   if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
      context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
   switch (option) {
   case 3: /* Play message envelope */
      if (!res) {
         res = play_message_datetime(chan, vmu, origtime, filename);
      }
      if (!res) {
         res = play_message_callerid(chan, vms, cid, context, 0, 1);
      }

      res = 't';
      break;

   case 2:  /* Call back */

      if (ast_strlen_zero(cid))
         break;

      ast_callerid_parse(cid, &name, &num);
      while ((res > -1) && (res != 't')) {
         switch (res) {
         case '1':
            if (num) {
               /* Dial the CID number */
               res = dialout(chan, vmu, num, vmu->callback);
               if (res) {
                  ast_config_destroy(msg_cfg);
                  return 9;
               }
            } else {
               res = '2';
            }
            break;

         case '2':
            /* Want to enter a different number, can only do this if there's a dialout context for this user */
            if (!ast_strlen_zero(vmu->dialout)) {
               res = dialout(chan, vmu, NULL, vmu->dialout);
               if (res) {
                  ast_config_destroy(msg_cfg);
                  return 9;
               }
            } else {
               ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
               res = ast_play_and_wait(chan, "vm-sorry");
            }
            ast_config_destroy(msg_cfg);
            return res;
         case '*':
            res = 't';
            break;
         case '3':
         case '4':
         case '5':
         case '6':
         case '7':
         case '8':
         case '9':
         case '0':

            res = ast_play_and_wait(chan, "vm-sorry");
            retries++;
            break;
         default:
            if (num) {
               ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
               res = ast_play_and_wait(chan, "vm-num-i-have");
               if (!res)
                  res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
               if (!res)
                  res = ast_play_and_wait(chan, "vm-tocallnum");
               /* Only prompt for a caller-specified number if there is a dialout context specified */
               if (!ast_strlen_zero(vmu->dialout)) {
                  if (!res)
                     res = ast_play_and_wait(chan, "vm-calldiffnum");
               }
            } else {
               res = ast_play_and_wait(chan, "vm-nonumber");
               if (!ast_strlen_zero(vmu->dialout)) {
                  if (!res)
                     res = ast_play_and_wait(chan, "vm-toenternumber");
               }
            }
            if (!res) {
               res = ast_play_and_wait(chan, "vm-star-cancel");
            }
            if (!res) {
               res = ast_waitfordigit(chan, 6000);
            }
            if (!res) {
               retries++;
               if (retries > 3) {
                  res = 't';
               }
            }
            ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
            break; 
            
         }
         if (res == 't')
            res = 0;
         else if (res == '*')
            res = -1;
      }
      break;
      
   case 1:  /* Reply */
      /* Send reply directly to sender */
      if (ast_strlen_zero(cid))
         break;

      ast_callerid_parse(cid, &name, &num);
      if (!num) {
         ast_verb(3, "No CID number available, no reply sent\n");
         if (!res)
            res = ast_play_and_wait(chan, "vm-nonumber");
         ast_config_destroy(msg_cfg);
         return res;
      } else {
         struct ast_vm_user vmu2;
         if (find_user(&vmu2, vmu->context, num)) {
            struct leave_vm_options leave_options;
            char mailbox[AST_MAX_EXTENSION * 2 + 2];
            snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);

            ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
            
            memset(&leave_options, 0, sizeof(leave_options));
            leave_options.record_gain = record_gain;
            res = leave_voicemail(chan, mailbox, &leave_options);
            if (!res)
               res = 't';
            ast_config_destroy(msg_cfg);
            return res;
         } else {
            /* Sender has no mailbox, can't reply */
            ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
            ast_play_and_wait(chan, "vm-nobox");
            res = 't';
            ast_config_destroy(msg_cfg);
            return res;
         }
      } 
      res = 0;

      break;
   }

   ast_config_destroy(msg_cfg);

#ifndef IMAP_STORAGE
   if (!res) {
      make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
      vms->heard[msg] = 1;
      res = wait_file(chan, vms, vms->fn);
   }
#endif
   return res;
}
static int append_mailbox ( const char *  context,
const char *  box,
const char *  data 
) [static]

Definition at line 11685 of file app_voicemail.c.

References apply_options(), ast_alloca, ast_copy_string(), ast_log(), ast_strlen_zero(), ast_vm_user::context, ast_vm_user::email, find_or_create(), ast_vm_user::fullname, inboxcount2(), LOG_WARNING, ast_vm_user::mailbox, OPT_PWLOC_SPOOLDIR, ast_vm_user::pager, ast_vm_user::password, ast_vm_user::passwordlocation, populate_defaults(), queue_mwi_event(), and read_password_from_file().

Referenced by actual_load_config().

{
   /* Assumes lock is already held */
   char *tmp;
   char *stringp;
   char *s;
   struct ast_vm_user *vmu;
   char *mailbox_full;
   int new = 0, old = 0, urgent = 0;
   char secretfn[PATH_MAX] = "";

   tmp = ast_strdupa(data);

   if (!(vmu = find_or_create(context, box)))
      return -1;

   populate_defaults(vmu);

   stringp = tmp;
   if ((s = strsep(&stringp, ","))) {
      if (!ast_strlen_zero(s) && s[0] == '*') {
         ast_log(LOG_WARNING, "Invalid password detected for mailbox %s.  The password"
            "\n\tmust be reset in voicemail.conf.\n", box);
      }
      /* assign password regardless of validity to prevent NULL password from being assigned */
      ast_copy_string(vmu->password, s, sizeof(vmu->password));
   }
   if (stringp && (s = strsep(&stringp, ","))) {
      ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
   }
   if (stringp && (s = strsep(&stringp, ","))) {
      ast_copy_string(vmu->email, s, sizeof(vmu->email));
   }
   if (stringp && (s = strsep(&stringp, ","))) {
      ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
   }
   if (stringp && (s = strsep(&stringp, ","))) {
      apply_options(vmu, s);
   }

   switch (vmu->passwordlocation) {
   case OPT_PWLOC_SPOOLDIR:
      snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
      read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
   }

   mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
   strcpy(mailbox_full, box);
   strcat(mailbox_full, "@");
   strcat(mailbox_full, context);

   inboxcount2(mailbox_full, &urgent, &new, &old);
   queue_mwi_event(mailbox_full, urgent, new, old);

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

Sets a a specific property value.

Parameters:
vmuThe voicemail user object to work with.
varThe name of the property to be set.
valueThe 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 1211 of file app_voicemail.c.

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

Referenced by apply_options(), and apply_options_full().

{
   int x;
   if (!strcasecmp(var, "attach")) {
      ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
   } else if (!strcasecmp(var, "attachfmt")) {
      ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
   } else if (!strcasecmp(var, "serveremail")) {
      ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
   } else if (!strcasecmp(var, "emailbody")) {
      ast_free(vmu->emailbody);
      vmu->emailbody = ast_strdup(substitute_escapes(value));
   } else if (!strcasecmp(var, "emailsubject")) {
      ast_free(vmu->emailsubject);
      vmu->emailsubject = ast_strdup(substitute_escapes(value));
   } else if (!strcasecmp(var, "language")) {
      ast_copy_string(vmu->language, value, sizeof(vmu->language));
   } else if (!strcasecmp(var, "tz")) {
      ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
   } else if (!strcasecmp(var, "locale")) {
      ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
#ifdef IMAP_STORAGE
   } else if (!strcasecmp(var, "imapuser")) {
      ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imapserver")) {
      ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imapport")) {
      ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imapflags")) {
      ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
      ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imapfolder")) {
      ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
      vmu->imapversion = imapversion;
   } else if (!strcasecmp(var, "imapvmshareid")) {
      ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
      vmu->imapversion = imapversion;
#endif
   } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
      ast_set2_flag(vmu, ast_true(value), VM_DELETE); 
   } else if (!strcasecmp(var, "saycid")){
      ast_set2_flag(vmu, ast_true(value), VM_SAYCID); 
   } else if (!strcasecmp(var, "sendvoicemail")){
      ast_set2_flag(vmu, ast_true(value), VM_SVMAIL); 
   } else if (!strcasecmp(var, "review")){
      ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
   } else if (!strcasecmp(var, "tempgreetwarn")){
      ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);   
   } else if (!strcasecmp(var, "messagewrap")){
      ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);  
   } else if (!strcasecmp(var, "operator")) {
      ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);  
   } else if (!strcasecmp(var, "envelope")){
      ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);  
   } else if (!strcasecmp(var, "moveheard")){
      ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
   } else if (!strcasecmp(var, "sayduration")){
      ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);  
   } else if (!strcasecmp(var, "saydurationm")){
      if (sscanf(value, "%30d", &x) == 1) {
         vmu->saydurationm = x;
      } else {
         ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
      }
   } else if (!strcasecmp(var, "forcename")){
      ast_set2_flag(vmu, ast_true(value), VM_FORCENAME); 
   } else if (!strcasecmp(var, "forcegreetings")){
      ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);   
   } else if (!strcasecmp(var, "callback")) {
      ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
   } else if (!strcasecmp(var, "dialout")) {
      ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
   } else if (!strcasecmp(var, "exitcontext")) {
      ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
   } else if (!strcasecmp(var, "minsecs")) {
      if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
         vmu->minsecs = x;
      } else {
         ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
         vmu->minsecs = vmminsecs;
      }
   } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
      vmu->maxsecs = atoi(value);
      if (vmu->maxsecs <= 0) {
         ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
         vmu->maxsecs = vmmaxsecs;
      } else {
         vmu->maxsecs = atoi(value);
      }
      if (!strcasecmp(var, "maxmessage"))
         ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'.  Please make that change in your voicemail config.\n");
   } else if (!strcasecmp(var, "maxmsg")) {
      vmu->maxmsg = atoi(value);
      /* Accept maxmsg=0 (Greetings only voicemail) */
      if (vmu->maxmsg < 0) {
         ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
         vmu->maxmsg = MAXMSG;
      } else if (vmu->maxmsg > MAXMSGLIMIT) {
         ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
         vmu->maxmsg = MAXMSGLIMIT;
      }
   } else if (!strcasecmp(var, "nextaftercmd")) {
      ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
   } else if (!strcasecmp(var, "backupdeleted")) {
      if (sscanf(value, "%30d", &x) == 1)
         vmu->maxdeletedmsg = x;
      else if (ast_true(value))
         vmu->maxdeletedmsg = MAXMSG;
      else
         vmu->maxdeletedmsg = 0;

      if (vmu->maxdeletedmsg < 0) {
         ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
         vmu->maxdeletedmsg = MAXMSG;
      } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
         ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
         vmu->maxdeletedmsg = MAXMSGLIMIT;
      }
   } else if (!strcasecmp(var, "volgain")) {
      sscanf(value, "%30lf", &vmu->volgain);
   } else if (!strcasecmp(var, "passwordlocation")) {
      if (!strcasecmp(value, "spooldir")) {
         vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
      } else {
         vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
      }
   } else if (!strcasecmp(var, "options")) {
      apply_options(vmu, value);
   }
}
static void apply_options ( struct ast_vm_user vmu,
const char *  options 
) [static]

Destructively Parse options and apply.

Definition at line 1464 of file app_voicemail.c.

References apply_option(), value, and var.

Referenced by append_mailbox(), apply_option(), and AST_TEST_DEFINE().

{  
   char *stringp;
   char *s;
   char *var, *value;
   stringp = ast_strdupa(options);
   while ((s = strsep(&stringp, "|"))) {
      value = s;
      if ((var = strsep(&value, "=")) && value) {
         apply_option(vmu, var, value);
      }
   }  
}
static void apply_options_full ( struct ast_vm_user retval,
struct ast_variable var 
) [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 1483 of file app_voicemail.c.

References apply_option(), ast_copy_string(), ast_free, ast_log(), 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, LOG_WARNING, ast_vm_user::mailbox, ast_variable::name, ast_variable::next, ast_vm_user::pager, ast_vm_user::password, substitute_escapes(), ast_vm_user::uniqueid, ast_variable::value, and var.

Referenced by actual_load_config(), and find_user_realtime().

{
   for (; var; var = var->next) {
      if (!strcasecmp(var->name, "vmsecret")) {
         ast_copy_string(retval->password, var->value, sizeof(retval->password));
      } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
         if (ast_strlen_zero(retval->password)) {
            if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
               ast_log(LOG_WARNING, "Invalid password detected for mailbox %s.  The password"
                  "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
            } else {
               ast_copy_string(retval->password, var->value, sizeof(retval->password));
            }
         }
      } else if (!strcasecmp(var->name, "uniqueid")) {
         ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
      } else if (!strcasecmp(var->name, "pager")) {
         ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
      } else if (!strcasecmp(var->name, "email")) {
         ast_copy_string(retval->email, var->value, sizeof(retval->email));
      } else if (!strcasecmp(var->name, "fullname")) {
         ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
      } else if (!strcasecmp(var->name, "context")) {
         ast_copy_string(retval->context, var->value, sizeof(retval->context));
      } else if (!strcasecmp(var->name, "emailsubject")) {
         ast_free(retval->emailsubject);
         retval->emailsubject = ast_strdup(substitute_escapes(var->value));
      } else if (!strcasecmp(var->name, "emailbody")) {
         ast_free(retval->emailbody);
         retval->emailbody = ast_strdup(substitute_escapes(var->value));
#ifdef IMAP_STORAGE
      } else if (!strcasecmp(var->name, "imapuser")) {
         ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imapserver")) {
         ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imapport")) {
         ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imapflags")) {
         ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
         ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imapfolder")) {
         ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
         retval->imapversion = imapversion;
      } else if (!strcasecmp(var->name, "imapvmshareid")) {
         ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
         retval->imapversion = imapversion;
#endif
      } else
         apply_option(retval, var->name, var->value);
   }
}
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:
endAn expandable buffer for holding the result
maxlenAlways zero, but see
See also:
ast_str
Parameters:
startA string to be encoded
preambleThe length of the first line already used for this string, to ensure that each line maintains a maximum length of 76 chars.
postamblethe length of any additional characters appended to the line, used to ensure proper field wrapping.
Return values:
Theencoded string.

Definition at line 4790 of file app_voicemail.c.

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

Referenced by make_email_file(), and sendpage().

{
   struct ast_str *tmp = ast_str_alloca(80);
   int first_section = 1;

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

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

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

Definition at line 4718 of file app_voicemail.c.

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

Referenced by make_email_file(), and sendpage().

{
   const char *ptr;

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

   return ast_str_buffer(*buf);
}
AST_TEST_DEFINE ( test_voicemail_vmuser  )

Definition at line 11742 of file app_voicemail.c.

References apply_options(), ast_calloc, ast_set_flag, AST_TEST_FAIL, ast_test_flag, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_vm_user::attachfmt, ast_vm_user::callback, ast_vm_user::dialout, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::exit, free_user(), ast_vm_user::maxdeletedmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, OPT_PWLOC_SPOOLDIR, ast_vm_user::passwordlocation, populate_defaults(), ast_vm_user::saydurationm, ast_vm_user::serveremail, TEST_EXECUTE, TEST_INIT, VM_ALLOCED, VM_ATTACH, VM_DELETE, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_MESSAGEWRAP, VM_MOVEHEARD, VM_OPERATOR, VM_REVIEW, VM_SAYCID, VM_SAYDURATION, VM_SKIPAFTERCMD, VM_SVMAIL, VM_TEMPGREETWARN, ast_vm_user::volgain, and ast_vm_user::zonetag.

{
   int res = 0;
   struct ast_vm_user *vmu;
   /* language parameter seems to only be used for display in manager action */
   static const char options_string[] = "attach=yes|attachfmt=wav49|"
      "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
      "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
      "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
      "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
      "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
      "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
      "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
      "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
#ifdef IMAP_STORAGE
   static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
      "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
#endif

   switch (cmd) {
   case TEST_INIT:
      info->name = "vmuser";
      info->category = "/apps/app_voicemail/";
      info->summary = "Vmuser unit test";
      info->description =
         "This tests passing all supported parameters to apply_options, the voicemail user config parser";
      return AST_TEST_NOT_RUN;
   case TEST_EXECUTE:
      break;
   }

   if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
      return AST_TEST_NOT_RUN;
   }
   populate_defaults(vmu);
   ast_set_flag(vmu, VM_ALLOCED);

   apply_options(vmu, options_string);

   if (!ast_test_flag(vmu, VM_ATTACH)) {
      ast_test_status_update(test, "Parse failure for attach option\n");
      res = 1;
   }
   if (strcasecmp(vmu->attachfmt, "wav49")) {
      ast_test_status_update(test, "Parse failure for attachftm option\n");
      res = 1;
   }
   if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
      ast_test_status_update(test, "Parse failure for serveremail option\n");
      res = 1;
   }
   if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
      ast_test_status_update(test, "Parse failure for emailsubject option\n");
      res = 1;
   }
   if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
      ast_test_status_update(test, "Parse failure for emailbody option\n");
      res = 1;
   }
   if (strcasecmp(vmu->zonetag, "central")) {
      ast_test_status_update(test, "Parse failure for tz option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_DELETE)) {
      ast_test_status_update(test, "Parse failure for delete option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_SAYCID)) {
      ast_test_status_update(test, "Parse failure for saycid option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_SVMAIL)) {
      ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_REVIEW)) {
      ast_test_status_update(test, "Parse failure for review option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
      ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
      ast_test_status_update(test, "Parse failure for messagewrap option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_OPERATOR)) {
      ast_test_status_update(test, "Parse failure for operator option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_ENVELOPE)) {
      ast_test_status_update(test, "Parse failure for envelope option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
      ast_test_status_update(test, "Parse failure for moveheard option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_SAYDURATION)) {
      ast_test_status_update(test, "Parse failure for sayduration option\n");
      res = 1;
   }
   if (vmu->saydurationm != 5) {
      ast_test_status_update(test, "Parse failure for saydurationm option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_FORCENAME)) {
      ast_test_status_update(test, "Parse failure for forcename option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_FORCEGREET)) {
      ast_test_status_update(test, "Parse failure for forcegreetings option\n");
      res = 1;
   }
   if (strcasecmp(vmu->callback, "somecontext")) {
      ast_test_status_update(test, "Parse failure for callbacks option\n");
      res = 1;
   }
   if (strcasecmp(vmu->dialout, "somecontext2")) {
      ast_test_status_update(test, "Parse failure for dialout option\n");
      res = 1;
   }
   if (strcasecmp(vmu->exit, "somecontext3")) {
      ast_test_status_update(test, "Parse failure for exitcontext option\n");
      res = 1;
   }
   if (vmu->minsecs != 10) {
      ast_test_status_update(test, "Parse failure for minsecs option\n");
      res = 1;
   }
   if (vmu->maxsecs != 100) {
      ast_test_status_update(test, "Parse failure for maxsecs option\n");
      res = 1;
   }
   if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
      ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
      res = 1;
   }
   if (vmu->maxdeletedmsg != 50) {
      ast_test_status_update(test, "Parse failure for backupdeleted option\n");
      res = 1;
   }
   if (vmu->volgain != 1.3) {
      ast_test_status_update(test, "Parse failure for volgain option\n");
      res = 1;
   }
   if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
      ast_test_status_update(test, "Parse failure for passwordlocation option\n");
      res = 1;
   }
#ifdef IMAP_STORAGE
   apply_options(vmu, option_string2);

   if (strcasecmp(vmu->imapuser, "imapuser")) {
      ast_test_status_update(test, "Parse failure for imapuser option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imappassword, "imappasswd")) {
      ast_test_status_update(test, "Parse failure for imappasswd option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imapfolder, "INBOX")) {
      ast_test_status_update(test, "Parse failure for imapfolder option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imapvmshareid, "6000")) {
      ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imapserver, "imapserver")) {
      ast_test_status_update(test, "Parse failure for imapserver option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imapport, "1234")) {
      ast_test_status_update(test, "Parse failure for imapport option\n");
      res = 1;
   }
   if (strcasecmp(vmu->imapflags, "flagged")) {
      ast_test_status_update(test, "Parse failure for imapflags option\n");
      res = 1;
   }
#endif

   free_user(vmu);
   return res ? AST_TEST_FAIL : AST_TEST_PASS;
}
static int base_encode ( char *  filename,
FILE *  so 
) [static]

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

Parameters:
filenameThe path to the file to be encoded. Must be readable, file is opened in read mode.
soA 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 4596 of file app_voicemail.c.

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

Referenced by add_email_attachment().

{
   static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
      'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
      '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
   int i, hiteof = 0;
   FILE *fi;
   struct baseio bio;

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

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

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

      memset(igroup, 0, sizeof(igroup));

      for (n = 0; n < 3; n++) {
         if ((c = inchar(&bio, fi)) == EOF) {
            hiteof = 1;
            break;
         }

         igroup[n] = (unsigned char) c;
      }

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

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

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

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

   fclose(fi);
   
   if (fputs(ENDL, so) == EOF) {
      return 0;
   }

   return 1;
}
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:
vmuThe voicemail user to change the password for.
passwordThe 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 1442 of file app_voicemail.c.

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

Referenced by vm_change_password().

{
   int res = -1;
   if (!strcmp(vmu->password, password)) {
      /* No change (but an update would return 0 rows updated, so we opt out here) */
      return 0;
   }

   if (strlen(password) > 10) {
      ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
   }
   if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
      ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
      ast_copy_string(vmu->password, password, sizeof(vmu->password));
      res = 0;
   }
   return res;
}
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 4763 of file app_voicemail.c.

References str.

Referenced by make_email_file(), and sendpage().

{
   for (; *str; str++) {
      if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
         return 1;
      }
   }
   return 0;
}
static int check_password ( struct ast_vm_user vmu,
char *  password 
) [static]

Check that password meets minimum required length.

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

Definition at line 1401 of file app_voicemail.c.

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

Referenced by vm_newuser(), and vm_options().

{
   /* check minimum length */
   if (strlen(password) < minpassword)
      return 1;
   /* check that password does not contain '*' character */
   if (!ast_strlen_zero(password) && password[0] == '*')
      return 1;
   if (!ast_strlen_zero(ext_pass_check_cmd)) {
      char cmd[255], buf[255];

      ast_debug(1, "Verify password policies for %s\n", password);

      snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
      if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
         ast_debug(5, "Result: %s\n", buf);
         if (!strncasecmp(buf, "VALID", 5)) {
            ast_debug(3, "Passed password check: '%s'\n", buf);
            return 0;
         } else if (!strncasecmp(buf, "FAILURE", 7)) {
            ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
            return 0;
         } else {
            ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
            return 1;
         }
      }
   }
   return 0;
}
static int close_mailbox ( struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Definition at line 8705 of file app_voicemail.c.

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

Referenced by play_message_by_id(), vm_execmain(), vm_mailbox_snapshot_create(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   int x = 0;
   int last_msg_idx = 0;

#ifndef IMAP_STORAGE
   int res = 0, nummsg;
   char fn2[PATH_MAX];
#endif

   if (vms->lastmsg <= -1) {
      goto done;
   }

   vms->curmsg = -1;
#ifndef IMAP_STORAGE
   /* Get the deleted messages fixed */
   if (vm_lock_path(vms->curdir)) {
      return ERROR_LOCK_PATH;
   }

   /* update count as message may have arrived while we've got mailbox open */
   last_msg_idx = last_message_index(vmu, vms->curdir);
   if (last_msg_idx != vms->lastmsg) {
      ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
   }

   /* must check up to last detected message, just in case it is erroneously greater than maxmsg */
   for (x = 0; x < last_msg_idx + 1; x++) {
      if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
         /* Save this message.  It's not in INBOX or hasn't been heard */
         make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
         if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
            break;
         }
         vms->curmsg++;
         make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
         if (strcmp(vms->fn, fn2)) {
            RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
         }
      } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
         /* Move to old folder before deleting */
         res = save_to_folder(vmu, vms, x, 1, NULL, 0);
         if (res == ERROR_LOCK_PATH) {
            /* If save failed do not delete the message */
            ast_log(AST_LOG_WARNING, "Save failed.  Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
            vms->deleted[x] = 0;
            vms->heard[x] = 0;
            --x;
         }
      } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
         /* Move to deleted folder */
         res = save_to_folder(vmu, vms, x, 10, NULL, 0);
         if (res == ERROR_LOCK_PATH) {
            /* If save failed do not delete the message */
            vms->deleted[x] = 0;
            vms->heard[x] = 0;
            --x;
         }
      } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
         /* If realtime storage enabled - we should explicitly delete this message,
         cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */
         make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
         if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
            DELETE(vms->curdir, x, vms->fn, vmu);
         }
      }
   }

   /* Delete ALL remaining messages */
   nummsg = x - 1;
   for (x = vms->curmsg + 1; x <= nummsg; x++) {
      make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
      if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
         DELETE(vms->curdir, x, vms->fn, vmu);
      }
   }
   ast_unlock_path(vms->curdir);
#else /* defined(IMAP_STORAGE) */
   ast_mutex_lock(&vms->lock);
   if (vms->deleted) {
      /* Since we now expunge after each delete, deleting in reverse order
       * ensures that no reordering occurs between each step. */
      last_msg_idx = vms->dh_arraysize;
      for (x = last_msg_idx - 1; x >= 0; x--) {
         if (vms->deleted[x]) {
            ast_debug(3, "IMAP delete of %d\n", x);
            DELETE(vms->curdir, x, vms->fn, vmu);
         }
      }
   }
#endif

done:
   if (vms->deleted) {
      ast_free(vms->deleted);
      vms->deleted = NULL;
   }
   if (vms->heard) {
      ast_free(vms->heard);
      vms->heard = NULL;
   }
   vms->dh_arraysize = 0;
#ifdef IMAP_STORAGE
   ast_mutex_unlock(&vms->lock);
#endif

   return 0;
}
static char* complete_voicemail_show_users ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 12162 of file app_voicemail.c.

References AST_LIST_TRAVERSE, ast_strdup, and ast_vm_user::context.

Referenced by handle_voicemail_show_users().

{
   int which = 0;
   int wordlen;
   struct ast_vm_user *vmu;
   const char *context = "";

   /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
   if (pos > 4)
      return NULL;
   if (pos == 3)
      return (state == 0) ? ast_strdup("for") : NULL;
   wordlen = strlen(word);
   AST_LIST_TRAVERSE(&users, vmu, list) {
      if (!strncasecmp(word, vmu->context, wordlen)) {
         if (context && strcmp(context, vmu->context) && ++which > state)
            return ast_strdup(vmu->context);
         /* ignore repeated contexts ? */
         context = vmu->context;
      }
   }
   return NULL;
}
static int copy ( char *  infile,
char *  outfile 
) [static]

Utility function to copy a file.

Parameters:
infileThe path to the file to be copied. The file must be readable, it is opened in read only mode.
outfileThe 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 4401 of file app_voicemail.c.

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

Referenced by ast_func_read(), ast_func_read2(), ast_func_write(), config_hook_exec(), copy_plain_file(), iax2_register(), parse_hint_device(), parse_hint_presence(), and vm_forwardoptions().

{
   int ifd;
   int ofd;
   int res;
   int len;
   char buf[4096];

#ifdef HARDLINK_WHEN_POSSIBLE
   /* Hard link if possible; saves disk space & is faster */
   if (link(infile, outfile)) {
#endif
      if ((ifd = open(infile, O_RDONLY)) < 0) {
         ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
         return -1;
      }
      if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
         ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
         close(ifd);
         return -1;
      }
      do {
         len = read(ifd, buf, sizeof(buf));
         if (len < 0) {
            ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
            close(ifd);
            close(ofd);
            unlink(outfile);
         } else if (len) {
            res = write(ofd, buf, len);
            if (errno == ENOMEM || errno == ENOSPC || res != len) {
               ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
               close(ifd);
               close(ofd);
               unlink(outfile);
            }
         }
      } while (len);
      close(ifd);
      close(ofd);
      return 0;
#ifdef HARDLINK_WHEN_POSSIBLE
   } else {
      /* Hard link succeeded */
      return 0;
   }
#endif
}
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,
const char *  dest_folder 
) [static]

Copies a message from one mailbox to another.

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

Definition at line 5674 of file app_voicemail.c.

References ast_channel_caller(), ast_channel_language(), ast_copy_string(), ast_log(), AST_LOG_ERROR, AST_LOG_NOTICE, ast_strlen_zero(), ast_unlock_path(), ast_vm_user::context, COPY, copy_plain_file(), create_dirpath(), ERROR_LOCK_PATH, EXISTS, ast_party_caller::id, inprocess_count(), last_message_index(), ast_vm_user::mailbox, make_dir(), make_file(), mbox(), ast_party_id::name, notify_new_message(), ast_party_id::number, S_COR, STORE, ast_party_name::str, ast_party_number::str, ast_party_name::valid, ast_party_number::valid, vm_delete(), and vm_lock_path().

Referenced by forward_message(), leave_voicemail(), and vm_msg_forward().

{
   char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
   const char *frombox = mbox(vmu, imbox);
   const char *userfolder;
   int recipmsgnum;
   int res = 0;

   ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);

   if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
      userfolder = "Urgent";
   } else if (!ast_strlen_zero(dest_folder)) {
      userfolder = dest_folder;
   } else {
      userfolder = "INBOX";
   }

   create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);

   if (!dir)
      make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
   else
      ast_copy_string(fromdir, dir, sizeof(fromdir));

   make_file(frompath, sizeof(frompath), fromdir, msgnum);
   make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);

   if (vm_lock_path(todir))
      return ERROR_LOCK_PATH;

   recipmsgnum = last_message_index(recip, todir) + 1;
   if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
      make_file(topath, sizeof(topath), todir, recipmsgnum);
#ifndef ODBC_STORAGE
      if (EXISTS(fromdir, msgnum, frompath, chan ? ast_channel_language(chan) : "")) {
         COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
      } else {
#endif
         /* If we are prepending a message for ODBC, then the message already
          * exists in the database, but we want to force copying from the
          * filesystem (since only the FS contains the prepend). */
         copy_plain_file(frompath, topath);
         STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
         vm_delete(topath);
#ifndef ODBC_STORAGE
      }
#endif
   } else {
      ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
      res = -1;
   }
   ast_unlock_path(todir);
   if (chan) {
      struct ast_party_caller *caller = ast_channel_caller(chan);
      notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
         S_COR(caller->id.number.valid, caller->id.number.str, NULL),
         S_COR(caller->id.name.valid, caller->id.name.str, NULL),
         flag);
   }

   return res;
}
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 4459 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().

{
   char frompath2[PATH_MAX], topath2[PATH_MAX];
   struct ast_variable *tmp,*var = NULL;
   const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
   ast_filecopy(frompath, topath, NULL);
   snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
   snprintf(topath2, sizeof(topath2), "%s.txt", topath);
   if (ast_check_realtime("voicemail_data")) {
      var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
      /* This cycle converts ast_variable linked list, to va_list list of arguments, may be there is a better way to do it? */
      for (tmp = var; tmp; tmp = tmp->next) {
         if (!strcasecmp(tmp->name, "origmailbox")) {
            origmailbox = tmp->value;
         } else if (!strcasecmp(tmp->name, "context")) {
            context = tmp->value;
         } else if (!strcasecmp(tmp->name, "macrocontext")) {
            macrocontext = tmp->value;
         } else if (!strcasecmp(tmp->name, "exten")) {
            exten = tmp->value;
         } else if (!strcasecmp(tmp->name, "priority")) {
            priority = tmp->value;
         } else if (!strcasecmp(tmp->name, "callerchan")) {
            callerchan = tmp->value;
         } else if (!strcasecmp(tmp->name, "callerid")) {
            callerid = tmp->value;
         } else if (!strcasecmp(tmp->name, "origdate")) {
            origdate = tmp->value;
         } else if (!strcasecmp(tmp->name, "origtime")) {
            origtime = tmp->value;
         } else if (!strcasecmp(tmp->name, "category")) {
            category = tmp->value;
         } else if (!strcasecmp(tmp->name, "duration")) {
            duration = tmp->value;
         }
      }
      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);
   }
   copy(frompath2, topath2);
   ast_variables_destroy(var);
}
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
dirThis 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 4296 of file app_voicemail.c.

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

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

{

   int vmcount = 0;
   DIR *vmdir = NULL;
   struct dirent *vment = NULL;

   if (vm_lock_path(dir))
      return ERROR_LOCK_PATH;

   if ((vmdir = opendir(dir))) {
      while ((vment = readdir(vmdir))) {
         if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
            vmcount++;
         }
      }
      closedir(vmdir);
   }
   ast_unlock_path(dir);
   
   return vmcount;
}
static 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:
destString. base directory.
lenLength of dest.
contextString. Ignored if is null or empty string.
extString. Ignored if is null or empty string.
folderString. Ignored if is null or empty string.
Returns:
-1 on failure, 0 on success.

Definition at line 1875 of file app_voicemail.c.

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

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

{
   mode_t   mode = VOICEMAIL_DIR_MODE;
   int res;

   make_dir(dest, len, context, ext, folder);
   if ((res = ast_mkdir(dest, mode))) {
      ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
      return -1;
   }
   return 0;
}
static int dialout ( struct ast_channel chan,
struct ast_vm_user vmu,
char *  num,
char *  outgoing_context 
) [static]

Definition at line 14299 of file app_voicemail.c.

References ast_channel_context(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_priority_set(), ast_copy_string(), ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_test_suite_event_notify, ast_verb, and ast_waitfordigit().

Referenced by advanced_options(), and vm_execmain().

{
   int cmd = 0;
   char destination[80] = "";
   int retries = 0;

   if (!num) {
      ast_verb(3, "Destination number will be entered manually\n");
      while (retries < 3 && cmd != 't') {
         destination[1] = '\0';
         destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
         if (!cmd)
            destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
         if (!cmd)
            destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
         if (!cmd) {
            cmd = ast_waitfordigit(chan, 6000);
            if (cmd)
               destination[0] = cmd;
         }
         if (!cmd) {
            retries++;
         } else {

            if (cmd < 0)
               return 0;
            if (cmd == '*') {
               ast_verb(3, "User hit '*' to cancel outgoing call\n");
               return 0;
            }
            if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0) 
               retries++;
            else
               cmd = 't';
         }
         ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
      }
      if (retries >= 3) {
         return 0;
      }
      
   } else {
      ast_verb(3, "Destination number is CID number '%s'\n", num);
      ast_copy_string(destination, num, sizeof(destination));
   }

   if (!ast_strlen_zero(destination)) {
      if (destination[strlen(destination) -1 ] == '*')
         return 0; 
      ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan));
      ast_channel_exten_set(chan, destination);
      ast_channel_context_set(chan, outgoing_context);
      ast_channel_priority_set(chan, 0);
      return 9;
   }
   return 0;
}
static struct ast_vm_user* find_or_create ( const char *  context,
const char *  box 
) [static, read]

Definition at line 11645 of file app_voicemail.c.

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

Referenced by actual_load_config(), and append_mailbox().

{
   struct ast_vm_user *vmu;

   if (!ast_strlen_zero(box) && box[0] == '*') {
      ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character.  The '*' character,"
            "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
            "\n\tpredefined extension 'a'.  A mailbox or password beginning with '*' is not valid"
            "\n\tand will be ignored.\n", box, context);
      return NULL;
   }

   AST_LIST_TRAVERSE(&users, vmu, list) {
      if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
         if (strcasecmp(vmu->context, context)) {
            ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
                  \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
                  \n\tconfiguration creates an ambiguity that you likely do not want. Please\
                  \n\tamend your voicemail.conf file to avoid this situation.\n", box);
         }
         ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
         return NULL;
      }
      if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
         ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
         return NULL;
      }
   }
   
   if (!(vmu = ast_calloc(1, sizeof(*vmu))))
      return NULL;
   
   ast_copy_string(vmu->context, context, sizeof(vmu->context));
   ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));

   AST_LIST_INSERT_TAIL(&users, vmu, list);
   
   return vmu;
}
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 1614 of file app_voicemail.c.

References AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_malloc, ast_set2_flag, ast_strdup, ast_test_flag, ast_vm_user::emailbody, ast_vm_user::emailsubject, find_user_realtime(), VM_ALLOCED, and VM_SEARCH.

Referenced by acf_mailbox_exists(), acf_vm_info(), advanced_options(), forward_message(), leave_voicemail(), msg_create_from_file(), play_message_by_id(), vm_authenticate(), vm_box_exists(), vm_execmain(), vm_mailbox_snapshot_create(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   /* This function could be made to generate one from a database, too */
   struct ast_vm_user *vmu = NULL, *cur;
   AST_LIST_LOCK(&users);

   if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
      context = "default";

   AST_LIST_TRAVERSE(&users, cur, list) {
#ifdef IMAP_STORAGE
      if (cur->imapversion != imapversion) {
         continue;
      }
#endif
      if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
         break;
      if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
         break;
   }
   if (cur) {
      /* Make a copy, so that on a reload, we have no race */
      if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
         *vmu = *cur;
         if (!ivm) {
            vmu->emailbody = ast_strdup(cur->emailbody);
            vmu->emailsubject = ast_strdup(cur->emailsubject);
         }
         ast_set2_flag(vmu, !ivm, VM_ALLOCED);
         AST_LIST_NEXT(vmu, list) = NULL;
      }
   } else
      vmu = find_user_realtime(ivm, context, mailbox);
   AST_LIST_UNLOCK(&users);
   return vmu;
}
static 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
mailboxThis 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 1573 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(), ast_vm_user::mailbox, populate_defaults(), SENTINEL, var, VM_ALLOCED, and VM_SEARCH.

Referenced by find_user().

{
   struct ast_variable *var;
   struct ast_vm_user *retval;

   if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
      if (ivm) {
         memset(retval, 0, sizeof(*retval));
      }
      populate_defaults(retval);
      if (!ivm) {
         ast_set_flag(retval, VM_ALLOCED);
      }
      if (mailbox) {
         ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
      }
      if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
         var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
      } else {
         var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
      }
      if (var) {
         apply_options_full(retval, var);
         ast_variables_destroy(var);
      } else { 
         if (!ivm) 
            ast_free(retval);
         retval = NULL;
      }  
   } 
   return retval;
}
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:
chan
context
vms
sender
fmt
is_new_messageUsed 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
urgentReads 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 7878 of file app_voicemail.c.

References ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_language(), ast_channel_priority(), ast_channel_priority_set(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_fileexists(), ast_filerename(), 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_test_suite_event_notify, ast_variable_retrieve(), ast_waitfordigit(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, copy_message(), vm_state::curbox, vm_state::curdir, vm_state::curmsg, DISPOSE, find_user(), vm_state::fn, free_user(), inboxcount(), inprocess_count(), leave_voicemail(), LOG_ERROR, LOG_NOTICE, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, pbx_exec(), pbx_findapp(), leave_vm_options::record_gain, RETRIEVE, run_externnotify(), S_COR, S_OR, sendmail(), serveremail, STORE, vm_state::username, VM_ATTACH, VM_DIRECFORWARD, vm_forwardoptions(), and VM_FWDURGAUTO.

Referenced by vm_execmain().

{
#ifdef IMAP_STORAGE
   int todircount = 0;
   struct vm_state *dstvms;
#endif
   char username[70]="";
   char fn[PATH_MAX]; /* for playback of name greeting */
   char ecodes[16] = "#";
   int res = 0, cmd = 0;
   struct ast_vm_user *receiver = NULL, *vmtmp;
   AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
   char *stringp;
   const char *s;
   int saved_messages = 0;
   int valid_extensions = 0;
   char *dir;
   int curmsg;
   char urgent_str[7] = "";
   int prompt_played = 0;
#ifndef IMAP_STORAGE
   char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
#endif
   if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
      ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
   }

   if (vms == NULL) return -1;
   dir = vms->curdir;
   curmsg = vms->curmsg;

   ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
   while (!res && !valid_extensions) {
      int use_directory = 0;
      if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
         int done = 0;
         int retries = 0;
         cmd = 0;
         while ((cmd >= 0) && !done ){
            if (cmd)
               retries = 0;
            switch (cmd) {
            case '1': 
               use_directory = 0;
               done = 1;
               break;
            case '2': 
               use_directory = 1;
               done = 1;
               break;
            case '*': 
               cmd = 't';
               done = 1;
               break;
            default: 
               /* Press 1 to enter an extension press 2 to use the directory */
               cmd = ast_play_and_wait(chan, "vm-forward");
               if (!cmd) {
                  cmd = ast_waitfordigit(chan, 3000);
               }
               if (!cmd) {
                  retries++;
               }
               if (retries > 3) {
                  cmd = 't';
                  done = 1;
               }
               ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
            }
         }
         if (cmd < 0 || cmd == 't')
            break;
      }

      if (use_directory) {
         /* use app_directory */

         struct ast_app* directory_app;

         directory_app = pbx_findapp("Directory");
         if (directory_app) {
            char vmcontext[256];
            char *old_context;
            char *old_exten;
            int old_priority;
            /* make backup copies */
            old_context = ast_strdupa(ast_channel_context(chan));
            old_exten = ast_strdupa(ast_channel_exten(chan));
            old_priority = ast_channel_priority(chan);

            /* call the the Directory, changes the channel */
            snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
            res = pbx_exec(chan, directory_app, vmcontext);

            ast_copy_string(username, ast_channel_exten(chan), sizeof(username));

            /* restore the old context, exten, and priority */
            ast_channel_context_set(chan, old_context);
            ast_channel_exten_set(chan, old_exten);
            ast_channel_priority_set(chan, old_priority);
         } else {
            ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
            ast_clear_flag((&globalflags), VM_DIRECFORWARD);
         }
      } else {
         /* Ask for an extension */
         ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
         res = ast_streamfile(chan, "vm-extension", ast_channel_language(chan)); /* "extension" */
         prompt_played++;
         if (res || prompt_played > 4)
            break;
         if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#")) < 0)
            break;
      }

      /* start all over if no username */
      if (ast_strlen_zero(username))
         continue;
      stringp = username;
      s = strsep(&stringp, "*");
      /* start optimistic */
      valid_extensions = 1;
      while (s) {
         if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
            int oldmsgs;
            int newmsgs;
            int capacity;
            if (inboxcount(s, &newmsgs, &oldmsgs)) {
               ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
               /* Shouldn't happen, but allow trying another extension if it does */
               res = ast_play_and_wait(chan, "pbx-invalid");
               valid_extensions = 0;
               break;
            }
            capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
            if ((newmsgs + oldmsgs) >= capacity) {
               ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
               res = ast_play_and_wait(chan, "vm-mailboxfull");
               valid_extensions = 0;
               while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
                  inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
                  free_user(vmtmp);
               }
               inprocess_count(receiver->mailbox, receiver->context, -1);
               break;
            }
            AST_LIST_INSERT_HEAD(&extensions, receiver, list);
         } else {
            /* XXX Optimization for the future.  When we encounter a single bad extension,
             * bailing out on all of the extensions may not be the way to go.  We should
             * probably just bail on that single extension, then allow the user to enter
             * several more. XXX
             */
            while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
               free_user(receiver);
            }
            ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
            /* "I am sorry, that's not a valid extension.  Please try again." */
            res = ast_play_and_wait(chan, "pbx-invalid");
            valid_extensions = 0;
            break;
         }

         /* play name if available, else play extension number */
         snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
         RETRIEVE(fn, -1, s, receiver->context);
         if (ast_fileexists(fn, NULL, NULL) > 0) {
            res = ast_stream_and_wait(chan, fn, ecodes);
            if (res) {
               DISPOSE(fn, -1);
               return res;
            }
         } else {
            res = ast_say_digit_str(chan, s, ecodes, ast_channel_language(chan));
         }
         DISPOSE(fn, -1);

         s = strsep(&stringp, "*");
      }
      /* break from the loop of reading the extensions */
      if (valid_extensions)
         break;
   }
   /* check if we're clear to proceed */
   if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
      return res;
   if (is_new_message == 1) {
      struct leave_vm_options leave_options;
      char mailbox[AST_MAX_EXTENSION * 2 + 2];
      snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);

      /* Send VoiceMail */
      memset(&leave_options, 0, sizeof(leave_options));
      leave_options.record_gain = record_gain;
      cmd = leave_voicemail(chan, mailbox, &leave_options);
   } else {
      /* Forward VoiceMail */
      long duration = 0;
      struct vm_state vmstmp;
      int copy_msg_result = 0;
#ifdef IMAP_STORAGE
      char filename[PATH_MAX];
      struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
      const char *msg_id = NULL;
      struct ast_config *msg_cfg;
#endif
      memcpy(&vmstmp, vms, sizeof(vmstmp));

      RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
#ifdef IMAP_STORAGE
      make_file(filename, sizeof(filename), dir, curmsg);
      strncat(filename, ".txt", sizeof(filename) - strlen(filename) - 1);
      msg_cfg = ast_config_load(filename, config_flags);
      if (msg_cfg && msg_cfg == CONFIG_STATUS_FILEINVALID) {
         msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
         ast_config_destroy(msg_cfg);
      }
#endif

      cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
      if (!cmd) {
         AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
#ifdef IMAP_STORAGE
            int attach_user_voicemail;
            char *myserveremail = serveremail;
            
            /* get destination mailbox */
            dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
            if (!dstvms) {
               dstvms = create_vm_state_from_user(vmtmp);
            }
            if (dstvms) {
               init_mailstream(dstvms, 0);
               if (!dstvms->mailstream) {
                  ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
               } else {
                  copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
                  run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str); 
               }
            } else {
               ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
            }
            if (!ast_strlen_zero(vmtmp->serveremail))
               myserveremail = vmtmp->serveremail;
            attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
            /* NULL category for IMAP storage */
            sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
               dstvms->curbox,
               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
               S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
               vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
               NULL, urgent_str, msg_id);
#else
            copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL);
#endif
            saved_messages++;
            AST_LIST_REMOVE_CURRENT(list);
            inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
            free_user(vmtmp);
            if (res)
               break;
         }
         AST_LIST_TRAVERSE_SAFE_END;
         if (saved_messages > 0 && !copy_msg_result) {
            /* give confirmation that the message was saved */
            /* commented out since we can't forward batches yet
            if (saved_messages == 1)
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
            if (!res)
               res = ast_play_and_wait(chan, "vm-saved"); */
#ifdef IMAP_STORAGE
            /* If forwarded with intro, DON'T PLAY THIS MESSAGE AGAIN! */
            if (ast_strlen_zero(vmstmp.introfn))
#endif
            res = ast_play_and_wait(chan, "vm-msgsaved");
         }
#ifndef IMAP_STORAGE
         else {
            /* with IMAP, mailbox full warning played by imap_check_limits */
            res = ast_play_and_wait(chan, "vm-mailboxfull");
         }
         /* Restore original message without prepended message if backup exists */
         make_file(msgfile, sizeof(msgfile), dir, curmsg);
         strcpy(textfile, msgfile);
         strcpy(backup, msgfile);
         strcpy(backup_textfile, msgfile);
         strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
         strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
         strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
         if (ast_fileexists(backup, NULL, NULL) > 0) {
            ast_filerename(backup, msgfile, NULL);
            rename(backup_textfile, textfile);
         }
#endif
      }
      DISPOSE(dir, curmsg);
#ifndef IMAP_STORAGE
      if (cmd) { /* assuming hangup, cleanup backup file */
         make_file(msgfile, sizeof(msgfile), dir, curmsg);
         strcpy(textfile, msgfile);
         strcpy(backup_textfile, msgfile);
         strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
         strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
         rename(backup_textfile, textfile);
      }
#endif
   }

   /* If anything failed above, we still have this list to free */
   while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
      inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
      free_user(vmtmp);
   }
   return res ? res : cmd;
}
static void free_vm_users ( void  ) [static]

Free the users structure.

Definition at line 12781 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 actual_load_config(), and unload_module().

{
   struct ast_vm_user *current;
   AST_LIST_LOCK(&users);
   while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
      ast_set_flag(current, VM_ALLOCED);
      free_user(current);
   }
   AST_LIST_UNLOCK(&users);
}
static void free_vm_zones ( void  ) [static]

Free the zones structure.

Definition at line 12793 of file app_voicemail.c.

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

Referenced by actual_load_config(), and unload_module().

{
   struct vm_zone *zcur;
   AST_LIST_LOCK(&zones);
   while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
      free_zone(zcur);
   AST_LIST_UNLOCK(&zones);
}
static void free_zone ( struct vm_zone z) [static]

Definition at line 5438 of file app_voicemail.c.

References ast_free.

Referenced by free_vm_zones().

{
   ast_free(z);
}
static void generate_msg_id ( char *  dst) [static]

Sets the destination string to a uniquely identifying msg_id string.

Parameters:
dstpointer to a character buffer that should contain MSG_ID_LEN characters.

Definition at line 5939 of file app_voicemail.c.

References ast_atomic_fetchadd_int(), and MSG_ID_LEN.

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

{
   /* msg id is time of msg_id generation plus an incrementing value
    * called each time a new msg_id is generated. This should achieve uniqueness,
    * but only in single system solutions.
    */
   int unique_counter = ast_atomic_fetchadd_int(&msg_id_incrementor, +1);
   snprintf(dst, MSG_ID_LEN, "%ld-%08x", (long) time(NULL), unique_counter);
}
static int get_date ( char *  s,
int  len 
) [static]

Gets the current date and time, as formatted string.

Parameters:
sThe buffer to hold the output formatted date.
lenthe 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 5394 of file app_voicemail.c.

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

Referenced by leave_voicemail(), and msg_create_from_file().

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

   ast_localtime(&t, &tm, "UTC");

   return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
}
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 7446 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_fileexists(), ast_play_and_wait(), ast_say_number(), ast_test_suite_event_notify, ast_verb, ast_waitfordigit(), mbox(), and vm_play_folder_name().

Referenced by get_folder2().

{
   int x;
   int d;
   char fn[PATH_MAX];
   d = ast_play_and_wait(chan, "vm-press");  /* "Press" */
   if (d)
      return d;
   for (x = start; x < 5; x++) { /* For all folders */
      if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
         return d;
      d = ast_play_and_wait(chan, "vm-for"); /* "for" */
      if (d)
         return d;
      snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));  /* Folder name */

      /* The inbox folder can have its name changed under certain conditions
       * so this checks if the sound file exists for the inbox folder name and
       * if it doesn't, plays the default name instead. */
      if (x == 0) {
         if (ast_fileexists(fn, NULL, NULL)) {
            d = vm_play_folder_name(chan, fn);
         } else {
            ast_verb(1, "failed to find %s\n", fn);
            d = vm_play_folder_name(chan, "vm-INBOX");
         }
      } else {
         ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
         d = vm_play_folder_name(chan, fn);
      }

      if (d)
         return d;
      d = ast_waitfordigit(chan, 500);
      if (d)
         return d;
   }

   d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
   if (d)
      return d;
   d = ast_waitfordigit(chan, 4000);
   return d;
}
static int get_folder2 ( struct ast_channel chan,
char *  fn,
int  start 
) [static]

plays a prompt and waits for a keypress.

Parameters:
chan
fnthe name of the voice prompt file to be played. For example, 'vm-changeto', 'vm-savefolder'
startDoes 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 7503 of file app_voicemail.c.

References ast_play_and_wait(), ast_test_suite_event_notify, and get_folder().

Referenced by vm_execmain().

{
   int res = 0;
   int loops = 0;

   res = ast_play_and_wait(chan, fn);  /* Folder name */
   while (((res < '0') || (res > '9')) &&
         (res != '#') && (res >= 0) &&
         loops < 4) {
      res = get_folder(chan, 0);
      loops++;
   }
   if (loops == 4) { /* give up */
      ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
      return '#';
   }
   ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
   return res;
}
static int get_folder_by_name ( const char *  name) [static]

Definition at line 1904 of file app_voicemail.c.

References ARRAY_LEN.

Referenced by vm_execmain(), vm_mailbox_snapshot_create(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   size_t i;

   for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
      if (strcasecmp(name, mailbox_folders[i]) == 0) {
         return i;
      }
   }

   return -1;
}
static int handle_subscribe ( void *  datap) [static]

Definition at line 12544 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, len(), mwi_sub_task::mailbox, mwi_sub, poll_subscribed_mailbox(), and mwi_sub_task::uniqueid.

Referenced by mwi_sub_event_cb().

{
   unsigned int len;
   struct mwi_sub *mwi_sub;
   struct mwi_sub_task *p = datap;

   len = sizeof(*mwi_sub);
   if (!ast_strlen_zero(p->mailbox))
      len += strlen(p->mailbox);

   if (!ast_strlen_zero(p->context))
      len += strlen(p->context) + 1; /* Allow for seperator */

   if (!(mwi_sub = ast_calloc(1, len)))
      return -1;

   mwi_sub->uniqueid = p->uniqueid;
   if (!ast_strlen_zero(p->mailbox))
      strcpy(mwi_sub->mailbox, p->mailbox);

   if (!ast_strlen_zero(p->context)) {
      strcat(mwi_sub->mailbox, "@");
      strcat(mwi_sub->mailbox, p->context);
   }

   AST_RWLIST_WRLOCK(&mwi_subs);
   AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
   AST_RWLIST_UNLOCK(&mwi_subs);
   ast_free((void *) p->mailbox);
   ast_free((void *) p->context);
   ast_free(p);
   poll_subscribed_mailbox(mwi_sub);
   return 0;
}
static int handle_unsubscribe ( void *  datap) [static]

Definition at line 12522 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, and mwi_sub_destroy().

Referenced by mwi_unsub_event_cb().

{
   struct mwi_sub *mwi_sub;
   uint32_t *uniqueid = datap;
   
   AST_RWLIST_WRLOCK(&mwi_subs);
   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
      if (mwi_sub->uniqueid == *uniqueid) {
         AST_LIST_REMOVE_CURRENT(entry);
         break;
      }
   }
   AST_RWLIST_TRAVERSE_SAFE_END
   AST_RWLIST_UNLOCK(&mwi_subs);

   if (mwi_sub)
      mwi_sub_destroy(mwi_sub);

   ast_free(uniqueid);  
   return 0;
}
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 12299 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.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "voicemail reload";
      e->usage =
         "Usage: voicemail reload\n"
         "       Reload voicemail configuration\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

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

   ast_cli(a->fd, "Reloading voicemail configuration...\n");   
   load_config(1);
   
   return CLI_SUCCESS;
}
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 12187 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.

{
   struct ast_vm_user *vmu;
#define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
   const char *context = NULL;
   int users_counter = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "voicemail show users";
      e->usage =
         "Usage: voicemail show users [for <context>]\n"
         "       Lists all mailboxes currently set up\n";
      return NULL;
   case CLI_GENERATE:
      return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
   }  

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

   if (ast_check_realtime("voicemail")) {
      if (!context) {
         ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
         return CLI_SHOWUSAGE;
      }
      return show_users_realtime(a->fd, context);
   }

   AST_LIST_LOCK(&users);
   if (AST_LIST_EMPTY(&users)) {
      ast_cli(a->fd, "There are no voicemail users currently defined\n");
      AST_LIST_UNLOCK(&users);
      return CLI_FAILURE;
   }
   if (!context) {
      ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
   } else {
      int count = 0;
      AST_LIST_TRAVERSE(&users, vmu, list) {
         if (!strcmp(context, vmu->context)) {
            count++;
            break;
         }
      }
      if (count) {
         ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
      } else {
         ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
         AST_LIST_UNLOCK(&users);
         return CLI_FAILURE;
      }
   }
   AST_LIST_TRAVERSE(&users, vmu, list) {
      int newmsgs = 0, oldmsgs = 0;
      char count[12], tmp[256] = "";

      if (!context || !strcmp(context, vmu->context)) {
         snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
         inboxcount(tmp, &newmsgs, &oldmsgs);
         snprintf(count, sizeof(count), "%d", newmsgs);
         ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
         users_counter++;
      }
   }
   AST_LIST_UNLOCK(&users);
   ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
   return CLI_SUCCESS;
}
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 12263 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.

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

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

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

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

   return res;
}
static int has_voicemail ( const char *  mailbox,
const char *  folder 
) [static]

Determines if the given folder has messages.

Parameters:
mailboxThe @ delimited string for user. If no context is found, uses 'default' for the context.
folderthe folder to look in

This function is used when the mailbox is stored in a filesystem back end. This invokes the __has_voicemail(). 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 5791 of file app_voicemail.c.

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

Referenced by load_module(), and vm_execmain().

{
   char tmp[256], *tmp2 = tmp, *box, *context;
   ast_copy_string(tmp, mailbox, sizeof(tmp));
   if (ast_strlen_zero(folder)) {
      folder = "INBOX";
   }
   while ((box = strsep(&tmp2, ",&"))) {
      if ((context = strchr(box, '@')))
         *context++ = '\0';
      else
         context = "default";
      if (__has_voicemail(context, box, folder, 1))
         return 1;
      /* If we are checking INBOX, we should check Urgent as well */
      if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
         return 1;
      }
   }
   return 0;
}
static int inboxcount ( const char *  mailbox,
int *  newmsgs,
int *  oldmsgs 
) [static]

Definition at line 5873 of file app_voicemail.c.

References inboxcount2().

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

{
   int urgentmsgs = 0;
   int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
   if (newmsgs) {
      *newmsgs += urgentmsgs;
   }
   return res;
}
static int inboxcount2 ( const char *  mailbox,
int *  urgentmsgs,
int *  newmsgs,
int *  oldmsgs 
) [static]

Definition at line 5814 of file app_voicemail.c.

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

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

{
   char tmp[256];
   char *context;

   /* If no mailbox, return immediately */
   if (ast_strlen_zero(mailbox))
      return 0;

   if (newmsgs)
      *newmsgs = 0;
   if (oldmsgs)
      *oldmsgs = 0;
   if (urgentmsgs)
      *urgentmsgs = 0;

   if (strchr(mailbox, ',')) {
      int tmpnew, tmpold, tmpurgent;
      char *mb, *cur;

      ast_copy_string(tmp, mailbox, sizeof(tmp));
      mb = tmp;
      while ((cur = strsep(&mb, ", "))) {
         if (!ast_strlen_zero(cur)) {
            if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
               return -1;
            else {
               if (newmsgs)
                  *newmsgs += tmpnew; 
               if (oldmsgs)
                  *oldmsgs += tmpold;
               if (urgentmsgs)
                  *urgentmsgs += tmpurgent;
            }
         }
      }
      return 0;
   }

   ast_copy_string(tmp, mailbox, sizeof(tmp));
   
   if ((context = strchr(tmp, '@')))
      *context++ = '\0';
   else
      context = "default";

   if (newmsgs)
      *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
   if (oldmsgs)
      *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
   if (urgentmsgs)
      *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);

   return 0;
}
static int inbuf ( struct baseio bio,
FILE *  fi 
) [static]

utility used by inchar(), for base_encode()

Definition at line 4531 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(), netconsole(), sip_addheader(), sip_removeheader(), and term_strip().

{
   int l;

   if (bio->ateof)
      return 0;

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

      bio->ateof = 1;
      return 0;
   }

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

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

utility used by base_encode()

Definition at line 4555 of file app_voicemail.c.

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

Referenced by base_encode().

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

   return bio->iobuf[bio->iocp++];
}
static int inprocess_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1087 of file app_voicemail.c.

References CMP_MATCH, inprocess::context, and inprocess::mailbox.

Referenced by load_module().

{
   struct inprocess *i = obj, *j = arg;
   if (strcmp(i->mailbox, j->mailbox)) {
      return 0;
   }
   return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
}
static int inprocess_count ( const char *  context,
const char *  mailbox,
int  delta 
) [static]

Definition at line 1096 of file app_voicemail.c.

References ao2_alloc, ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_alloca, ast_atomic_fetchadd_int(), ast_log(), inprocess::context, inprocess::count, LOG_WARNING, and inprocess::mailbox.

Referenced by copy_message(), forward_message(), leave_voicemail(), and msg_create_from_file().

{
   struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
   arg->context = arg->mailbox + strlen(mailbox) + 1;
   strcpy(arg->mailbox, mailbox); /* SAFE */
   strcpy(arg->context, context); /* SAFE */
   ao2_lock(inprocess_container);
   if ((i = ao2_find(inprocess_container, arg, 0))) {
      int ret = ast_atomic_fetchadd_int(&i->count, delta);
      ao2_unlock(inprocess_container);
      ao2_ref(i, -1);
      return ret;
   }
   if (delta < 0) {
      ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
   }
   if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
      ao2_unlock(inprocess_container);
      return 0;
   }
   i->context = i->mailbox + strlen(mailbox) + 1;
   strcpy(i->mailbox, mailbox); /* SAFE */
   strcpy(i->context, context); /* SAFE */
   i->count = delta;
   ao2_link(inprocess_container, i);
   ao2_unlock(inprocess_container);
   ao2_ref(i, -1);
   return 0;
}
static int inprocess_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 1081 of file app_voicemail.c.

References inprocess::mailbox.

Referenced by load_module().

{
   const struct inprocess *i = obj;
   return atoi(i->mailbox);
}
static int invent_message ( struct ast_channel chan,
char *  context,
char *  ext,
int  busy,
char *  ecodes 
) [static]

Definition at line 5404 of file app_voicemail.c.

References ast_channel_language(), ast_fileexists(), ast_log(), AST_LOG_WARNING, ast_say_digit_str(), ast_stream_and_wait(), create_dirpath(), DISPOSE, and RETRIEVE.

Referenced by leave_voicemail().

{
   int res;
   char fn[PATH_MAX];
   char dest[PATH_MAX];

   snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);

   if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
      ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
      return -1;
   }

   RETRIEVE(fn, -1, ext, context);
   if (ast_fileexists(fn, NULL, NULL) > 0) {
      res = ast_stream_and_wait(chan, fn, ecodes);
      if (res) {
         DISPOSE(fn, -1);
         return res;
      }
   } else {
      /* Dispose just in case */
      DISPOSE(fn, -1);
      res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
      if (res)
         return res;
      res = ast_say_digit_str(chan, ext, ecodes, ast_channel_language(chan));
      if (res)
         return res;
   }
   res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
   return res;
}
static int is_valid_dtmf ( const char *  key) [static]

Determines if a DTMF key entered is valid.

Parameters:
keyThe 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 1548 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, and VALID_DTMF.

Referenced by actual_load_config().

{
   int i;
   char *local_key = ast_strdupa(key);

   for (i = 0; i < strlen(key); ++i) {
      if (!strchr(VALID_DTMF, *local_key)) {
         ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
         return 0;
      }
      local_key++;
   }
   return 1;
}
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
dirthe 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 4350 of file app_voicemail.c.

References ast_debug, map, ast_vm_user::maxmsg, and MAXMSGLIMIT.

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

{
   int x;
   unsigned char map[MAXMSGLIMIT] = "";
   DIR *msgdir;
   struct dirent *msgdirent;
   int msgdirint;
   char extension[4];
   int stopcount = 0;

   /* Reading the entire directory into a file map scales better than
    * doing a stat repeatedly on a predicted sequence.  I suspect this
    * is partially due to stat(2) internally doing a readdir(2) itself to
    * find each file. */
   if (!(msgdir = opendir(dir))) {
      return -1;
   }

   while ((msgdirent = readdir(msgdir))) {
      if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
         map[msgdirint] = 1;
         stopcount++;
         ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
      }
   }
   closedir(msgdir);

   for (x = 0; x < vmu->maxmsg; x++) {
      if (map[x] == 1) {
         stopcount--;
      } else if (map[x] == 0 && !stopcount) {
         break;
      }
   }

   return x - 1;
}
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
optionsOPT_BUSY_GREETING, OPT_UNAVAIL_GREETING
Returns:
zero on success, -1 on error.

Definition at line 6247 of file app_voicemail.c.

References ast_callerid_merge(), ast_canmatch_extension(), ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_language(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_redirecting(), 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_buffer(), ast_str_create(), ast_str_set(), ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_unlock_path(), ast_update_realtime(), ast_verb, ast_waitstream(), context, ast_vm_user::context, copy_message(), count_messages(), create_dirpath(), DISPOSE, errno, ast_vm_user::exit, leave_vm_options::exitcontext, exten, find_user(), free_user(), generate_msg_id(), get_date(), inboxcount(), inprocess_count(), INTRO, invent_message(), last_message_index(), LOG_WARNING, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, MSG_ID_LEN, vm_state::newmessages, notify_new_message(), OPERATOR_EXIT, OPT_BUSY_GREETING, OPT_DTMFEXIT, OPT_MESSAGE_PRIORITY, OPT_MESSAGE_Urgent, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), play_record_review(), leave_vm_options::record_gain, RENAME, RETRIEVE, S_COR, S_OR, SENTINEL, STORE, transfer, vm_lock_path(), VM_OPERATOR, VOICEMAIL_DIR_MODE, and VOICEMAIL_FILE_MODE.

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

{
#ifdef IMAP_STORAGE
   int newmsgs, oldmsgs;
#else
   char urgdir[PATH_MAX];
#endif
   char txtfile[PATH_MAX];
   char tmptxtfile[PATH_MAX];
   struct vm_state *vms = NULL;
   char callerid[256];
   FILE *txt;
   char date[256];
   int txtdes;
   int res = 0;
   int msgnum;
   int duration = 0;
   int sound_duration = 0;
   int ausemacro = 0;
   int ousemacro = 0;
   int ouseexten = 0;
   char tmpdur[16];
   char priority[16];
   char origtime[16];
   char dir[PATH_MAX];
   char tmpdir[PATH_MAX];
   char fn[PATH_MAX];
   char prefile[PATH_MAX] = "";
   char tempfile[PATH_MAX] = "";
   char ext_context[256] = "";
   char fmt[80];
   char *context;
   char ecodes[17] = "#";
   struct ast_str *tmp = ast_str_create(16);
   char *tmpptr;
   struct ast_vm_user *vmu;
   struct ast_vm_user svm;
   const char *category = NULL;
   const char *code;
   const char *alldtmf = "0123456789ABCD*#";
   char flag[80];

   if (!tmp) {
      return -1;
   }

   ast_str_set(&tmp, 0, "%s", ext);
   ext = ast_str_buffer(tmp);
   if ((context = strchr(ext, '@'))) {
      *context++ = '\0';
      tmpptr = strchr(context, '&');
   } else {
      tmpptr = strchr(ext, '&');
   }

   if (tmpptr)
      *tmpptr++ = '\0';

   ast_channel_lock(chan);
   if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
      category = ast_strdupa(category);
   }
   ast_channel_unlock(chan);

   if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
      ast_copy_string(flag, "Urgent", sizeof(flag));
   } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
      ast_copy_string(flag, "PRIORITY", sizeof(flag));
   } else {
      flag[0] = '\0';
   }

   ast_debug(3, "Before find_user\n");
   if (!(vmu = find_user(&svm, context, ext))) {
      ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
      pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
      ast_free(tmp);
      return res;
   }
   /* Setup pre-file if appropriate */
   if (strcmp(vmu->context, "default"))
      snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
   else
      ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));

   /* Set the path to the prefile. Will be one of 
      VM_SPOOL_DIRcontext/ext/busy
      VM_SPOOL_DIRcontext/ext/unavail
      Depending on the flag set in options.
   */
   if (ast_test_flag(options, OPT_BUSY_GREETING)) {
      snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
   } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
      snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
   }
   /* Set the path to the tmpfile as
      VM_SPOOL_DIR/context/ext/temp
      and attempt to create the folder structure.
   */
   snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
   if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
      ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
      ast_free(tmp);
      return -1;
   }
   RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
   if (ast_fileexists(tempfile, NULL, NULL) > 0)
      ast_copy_string(prefile, tempfile, sizeof(prefile));

   DISPOSE(tempfile, -1);
   /* It's easier just to try to make it than to check for its existence */
#ifndef IMAP_STORAGE
   create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
#else
   snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
   if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
      ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
   }
#endif

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

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

   if (ast_test_flag(options, OPT_DTMFEXIT)) {
      for (code = alldtmf; *code; code++) {
         char e[2] = "";
         e[0] = *code;
         if (strchr(ecodes, e[0]) == NULL
            && ast_canmatch_extension(chan,
               (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : ast_channel_context(chan)),
               e, 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
            strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
         }
      }
   }

   /* Play the beginning intro if desired */
   if (!ast_strlen_zero(prefile)) {
#ifdef ODBC_STORAGE
      int success = 
#endif
         RETRIEVE(prefile, -1, ext, context);
      if (ast_fileexists(prefile, NULL, NULL) > 0) {
         if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1) 
            res = ast_waitstream(chan, ecodes);
#ifdef ODBC_STORAGE
         if (success == -1) {
            /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
            ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
            store_file(prefile, vmu->mailbox, vmu->context, -1);
         }
#endif
      } else {
         ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
         res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
      }
      DISPOSE(prefile, -1);
      if (res < 0) {
         ast_debug(1, "Hang up during prefile playback\n");
         free_user(vmu);
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
         ast_free(tmp);
         return -1;
      }
   }
   if (res == '#') {
      /* On a '#' we skip the instructions */
      ast_set_flag(options, OPT_SILENT);
      res = 0;
   }
   /* If maxmsg is zero, act as a "greetings only" voicemail: Exit successfully without recording */
   if (vmu->maxmsg == 0) {
      ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
      pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
      goto leave_vm_out;
   }
   if (!res && !ast_test_flag(options, OPT_SILENT)) {
      res = ast_stream_and_wait(chan, INTRO, ecodes);
      if (res == '#') {
         ast_set_flag(options, OPT_SILENT);
         res = 0;
      }
   }
   if (res > 0)
      ast_stopstream(chan);
   /* Check for a '*' here in case the caller wants to escape from voicemail to something
    other than the operator -- an automated attendant or mailbox login for example */
   if (res == '*') {
      ast_channel_exten_set(chan, "a");
      if (!ast_strlen_zero(vmu->exit)) {
         ast_channel_context_set(chan, vmu->exit);
      } else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
         ast_channel_context_set(chan, ast_channel_macrocontext(chan));
      }
      ast_channel_priority_set(chan, 0);
      free_user(vmu);
      pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
      ast_free(tmp);
      return 0;
   }

   /* Check for a '0' here */
   if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
   transfer:
      if (ouseexten || ousemacro) {
         ast_channel_exten_set(chan, "o");
         if (!ast_strlen_zero(vmu->exit)) {
            ast_channel_context_set(chan, vmu->exit);
         } else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
            ast_channel_context_set(chan, ast_channel_macrocontext(chan));
         }
         ast_play_and_wait(chan, "transfer");
         ast_channel_priority_set(chan, 0);
         free_user(vmu);
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
      }
      ast_free(tmp);
      return OPERATOR_EXIT;
   }

   /* Allow all other digits to exit Voicemail and return to the dialplan */
   if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
      if (!ast_strlen_zero(options->exitcontext)) {
         ast_channel_context_set(chan, options->exitcontext);
      }
      free_user(vmu);
      ast_free(tmp);
      pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
      return res;
   }

   if (res < 0) {
      free_user(vmu);
      pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
      ast_free(tmp);
      return -1;
   }
   /* The meat of recording the message...  All the announcements and beeps have been played*/
   ast_copy_string(fmt, vmfmts, sizeof(fmt));
   if (!ast_strlen_zero(fmt)) {
      char msg_id[MSG_ID_LEN] = "";
      msgnum = 0;

#ifdef IMAP_STORAGE
      /* Is ext a mailbox? */
      /* must open stream for this user to get info! */
      res = inboxcount(ext_context, &newmsgs, &oldmsgs);
      if (res < 0) {
         ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
         ast_free(tmp);
         return -1;
      }
      if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
      /* It is possible under certain circumstances that inboxcount did not
       * create a vm_state when it was needed. This is a catchall which will
       * rarely be used.
       */
         if (!(vms = create_vm_state_from_user(vmu))) {
            ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
            ast_free(tmp);
            return -1;
         }
      }
      vms->newmessages++;

      /* here is a big difference! We add one to it later */
      msgnum = newmsgs + oldmsgs;
      ast_debug(3, "Messagecount set to %d\n", msgnum);
      snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
      /* set variable for compatibility */
      pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");

      if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
         goto leave_vm_out;
      }
#else
      if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
         res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
         if (!res)
            res = ast_waitstream(chan, "");
         ast_log(AST_LOG_WARNING, "No more messages possible\n");
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
         inprocess_count(vmu->mailbox, vmu->context, -1);
         goto leave_vm_out;
      }

#endif
      snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
      txtdes = mkstemp(tmptxtfile);
      chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
      if (txtdes < 0) {
         res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
         if (!res)
            res = ast_waitstream(chan, "");
         ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
         inprocess_count(vmu->mailbox, vmu->context, -1);
         goto leave_vm_out;
      }

      /* Now play the beep once we have the message number for our next message. */
      if (res >= 0) {
         /* Unless we're *really* silent, try to send the beep */
         res = ast_stream_and_wait(chan, "beep", "");
      }
            
      /* Store information in real-time storage */
      if (ast_check_realtime("voicemail_data")) {
         snprintf(priority, sizeof(priority), "%d", ast_channel_priority(chan));
         snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
         get_date(date, sizeof(date));
         ast_callerid_merge(callerid, sizeof(callerid),
            S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
            S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
            "Unknown");
         ast_store_realtime("voicemail_data",
            "origmailbox", ext,
            "context", ast_channel_context(chan),
            "macrocontext", ast_channel_macrocontext(chan),
            "exten", ast_channel_exten(chan),
            "priority", priority,
            "callerchan", ast_channel_name(chan),
            "callerid", callerid,
            "origdate", date,
            "origtime", origtime,
            "category", S_OR(category, ""),
            "filename", tmptxtfile,
            SENTINEL);
      }

      /* Store information */
      txt = fdopen(txtdes, "w+");
      if (txt) {
         generate_msg_id(msg_id);
         get_date(date, sizeof(date));
         ast_callerid_merge(callerid, sizeof(callerid),
            S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
            S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
            "Unknown");
         fprintf(txt, 
            ";\n"
            "; Message Information file\n"
            ";\n"
            "[message]\n"
            "origmailbox=%s\n"
            "context=%s\n"
            "macrocontext=%s\n"
            "exten=%s\n"
            "rdnis=%s\n"
            "priority=%d\n"
            "callerchan=%s\n"
            "callerid=%s\n"
            "origdate=%s\n"
            "origtime=%ld\n"
            "category=%s\n"
            "msg_id=%s\n",
            ext,
            ast_channel_context(chan),
            ast_channel_macrocontext(chan), 
            ast_channel_exten(chan),
            S_COR(ast_channel_redirecting(chan)->from.number.valid,
               ast_channel_redirecting(chan)->from.number.str, "unknown"),
            ast_channel_priority(chan),
            ast_channel_name(chan),
            callerid,
            date, (long) time(NULL),
            category ? category : "",
            msg_id);
      } else {
         ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
         inprocess_count(vmu->mailbox, vmu->context, -1);
         if (ast_check_realtime("voicemail_data")) {
            ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
         }
         res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
         goto leave_vm_out;
      }
      res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag, msg_id);

      if (txt) {
         fprintf(txt, "flag=%s\n", flag);
         if (sound_duration < vmu->minsecs) {
            fclose(txt);
            ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
            ast_filedelete(tmptxtfile, NULL);
            unlink(tmptxtfile);
            if (ast_check_realtime("voicemail_data")) {
               ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
            }
            inprocess_count(vmu->mailbox, vmu->context, -1);
         } else {
            fprintf(txt, "duration=%d\n", duration);
            fclose(txt);
            if (vm_lock_path(dir)) {
               ast_log(AST_LOG_ERROR, "Couldn't lock directory %s.  Voicemail will be lost.\n", dir);
               /* Delete files */
               ast_filedelete(tmptxtfile, NULL);
               unlink(tmptxtfile);
               inprocess_count(vmu->mailbox, vmu->context, -1);
            } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
               ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
               unlink(tmptxtfile);
               ast_unlock_path(dir);
               inprocess_count(vmu->mailbox, vmu->context, -1);
               if (ast_check_realtime("voicemail_data")) {
                  ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
               }
            } else {
#ifndef IMAP_STORAGE
               msgnum = last_message_index(vmu, dir) + 1;
#endif
               make_file(fn, sizeof(fn), dir, msgnum);

               /* assign a variable with the name of the voicemail file */ 
#ifndef IMAP_STORAGE
               pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
#else
               pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
#endif

               snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
               ast_filerename(tmptxtfile, fn, NULL);
               rename(tmptxtfile, txtfile);
               inprocess_count(vmu->mailbox, vmu->context, -1);

               /* Properly set permissions on voicemail text descriptor file.
                  Unfortunately mkstemp() makes this file 0600 on most unix systems. */
               if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
                  ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));

               ast_unlock_path(dir);
               if (ast_check_realtime("voicemail_data")) {
                  snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
                  ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
               }
               /* We must store the file first, before copying the message, because
                * ODBC storage does the entire copy with SQL.
                */
               if (ast_fileexists(fn, NULL, NULL) > 0) {
                  STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
               }

               /* Are there to be more recipients of this message? */
               while (tmpptr) {
                  struct ast_vm_user recipu, *recip;
                  char *exten, *cntx;

                  exten = strsep(&tmpptr, "&");
                  cntx = strchr(exten, '@');
                  if (cntx) {
                     *cntx = '\0';
                     cntx++;
                  }
                  if ((recip = find_user(&recipu, cntx, exten))) {
                     copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
                     free_user(recip);
                  }
               }
#ifndef IMAP_STORAGE
               if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If this is an Urgent message */
                  /* Move the message from INBOX to Urgent folder if this is urgent! */
                  char sfn[PATH_MAX];
                  char dfn[PATH_MAX];
                  int x;
                  /* It's easier just to try to make it than to check for its existence */
                  create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
                  x = last_message_index(vmu, urgdir) + 1;
                  make_file(sfn, sizeof(sfn), dir, msgnum);
                  make_file(dfn, sizeof(dfn), urgdir, x);
                  ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
                  RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
                  /* Notification must happen for this new message in Urgent folder, not INBOX */
                  ast_copy_string(fn, dfn, sizeof(fn));
                  msgnum = x;
               }
#endif
               /* Notification needs to happen after the copy, though. */
               if (ast_fileexists(fn, NULL, NULL)) {
#ifdef IMAP_STORAGE
                  notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
                     S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
                     S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
                     flag);
#else
                  notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
                     S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
                     S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
                     flag);
#endif
               }

               /* Disposal needs to happen after the optional move and copy */
               if (ast_fileexists(fn, NULL, NULL)) {
                  DISPOSE(dir, msgnum);
               }
            }
         }
      } else {
         inprocess_count(vmu->mailbox, vmu->context, -1);
      }
      if (res == '0') {
         goto transfer;
      } else if (res > 0 && res != 't')
         res = 0;

      if (sound_duration < vmu->minsecs)
         /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
      else
         pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
   } else
      ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
leave_vm_out:
   free_user(vmu);

#ifdef IMAP_STORAGE
   /* expunge message - use UID Expunge if supported on IMAP server*/
   ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
   if (expungeonhangup == 1) {
      ast_mutex_lock(&vms->lock);
#ifdef HAVE_IMAP_TK2006
      if (LEVELUIDPLUS (vms->mailstream)) {
         mail_expunge_full(vms->mailstream, NIL, EX_UID);
      } else 
#endif
         mail_expunge(vms->mailstream);
      ast_mutex_unlock(&vms->lock);
   }
#endif

   ast_free(tmp);
   return res;
}
static int load_config ( int  reload) [static]

Definition at line 12849 of file app_voicemail.c.

References actual_load_config(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_log(), ast_unload_realtime(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, and VOICEMAIL_CONFIG.

Referenced by handle_voicemail_reload(), load_module(), and reload().

{
   struct ast_config *cfg, *ucfg;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
   int res;

   ast_unload_realtime("voicemail");
   ast_unload_realtime("voicemail_data");

   if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
      if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
         return 0;
      } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
         ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Avoiding.\n");
         ucfg = NULL;
      }
      ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
      if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
         ast_config_destroy(ucfg);
         ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
         return 0;
      }
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format.  Aborting.\n");
      return 0;
   } else {
      ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
      if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
         ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Avoiding.\n");
         ucfg = NULL;
      }
   }

   res = actual_load_config(reload, cfg, ucfg);

   ast_config_destroy(cfg);
   ast_config_destroy(ucfg);

   return res;
}
static int load_module ( void  ) [static]

Definition at line 14240 of file app_voicemail.c.

References ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_config_AST_SPOOL_DIR, ast_custom_function_register, ast_data_register_multiple, ast_install_vm_functions(), ast_log(), AST_LOG_WARNING, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application_xml, ast_taskprocessor_get(), AST_TEST_REGISTER, EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, has_voicemail(), inboxcount(), inboxcount2(), inprocess_cmp_fn(), inprocess_hash_fn(), load_config(), manager_list_voicemail_users(), messagecount(), msg_create_from_file(), RQ_CHAR, RQ_UINTEGER3, sayname(), SENTINEL, vm_box_exists(), vm_exec(), vm_execmain(), vm_index_to_foldername(), vm_mailbox_snapshot_create(), vm_mailbox_snapshot_destroy(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), vm_msg_remove(), vm_playmsgexec(), vmauthenticate(), and vmsayname_exec().

{
   int res;
   my_umask = umask(0);
   umask(my_umask);

   if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
      return AST_MODULE_LOAD_DECLINE;
   }

   /* compute the location of the voicemail spool directory */
   snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
   
   if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
      ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor.  MWI will not work\n");
   }

   if ((res = load_config(0)))
      return res;

   res = ast_register_application_xml(app, vm_exec);
   res |= ast_register_application_xml(app2, vm_execmain);
   res |= ast_register_application_xml(app3, vm_box_exists);
   res |= ast_register_application_xml(app4, vmauthenticate);
   res |= ast_register_application_xml(playmsg_app, vm_playmsgexec);
   res |= ast_register_application_xml(sayname_app, vmsayname_exec);
   res |= ast_custom_function_register(&mailbox_exists_acf);
   res |= ast_custom_function_register(&vm_info_acf);
   res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
#ifdef TEST_FRAMEWORK
   res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
   res |= AST_TEST_REGISTER(test_voicemail_msgcount);
   res |= AST_TEST_REGISTER(test_voicemail_vmuser);
   res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
   res |= AST_TEST_REGISTER(test_voicemail_load_config);
   res |= AST_TEST_REGISTER(test_voicemail_vm_info);
#endif

   if (res)
      return res;

   ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
   ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));

   ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname, msg_create_from_file,
             vm_index_to_foldername,
             vm_mailbox_snapshot_create, vm_mailbox_snapshot_destroy,
             vm_msg_move, vm_msg_remove, vm_msg_forward, vm_msg_play);

#ifdef TEST_FRAMEWORK
   ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
#endif

   ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
   ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);

   return res;
}
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:
destThe variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
lenThe length of the path string that was written out.
context
ext
folder

The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns:
zero on success, -1 on error.

Definition at line 1829 of file app_voicemail.c.

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

{
   return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
}
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,
const char *  msg_id 
) [static]

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

Parameters:
pThe output file to generate the email contents into.
srcemailThe email address to send the email to, presumably the email address for the owner of the mailbox.
vmuThe voicemail user who is sending the voicemail.
msgnumThe message index in the mailbox folder.
context
mailboxThe voicemail box to read the voicemail to be notified in this email.
fromfolder
cidnumThe caller ID number.
cidnameThe caller ID name.
attachthe name of the sound file to be attached to the email, if attach_user_voicemail == 1.
attach2
formatThe message sound file format. i.e. .wav
durationThe time of the message content, in seconds.
attach_user_voicemailif 1, the sound file is attached to the email.
chan
category
imapif == 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.
flagThe 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 4846 of file app_voicemail.c.

References add_email_attachment(), ast_channel_name(), ast_channel_priority(), ast_channel_unref, 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_strftime(), ast_strftime_locale(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), check_mime(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, emailbody, ast_vm_user::emailsubject, emailsubject, ENDL, ast_vm_user::fullname, ast_vm_user::locale, ast_vm_user::mailbox, make_dir(), make_file(), prep_email_sub_vars(), S_OR, strip_control_and_high(), valid_config(), VM_PBXSKIP, and vmu_tm().

Referenced by sendmail().

{
   char date[256];
   char host[MAXHOSTNAMELEN] = "";
   char who[256];
   char bound[256];
   char dur[256];
   struct ast_tm tm;
   char enc_cidnum[256] = "", enc_cidname[256] = "";
   struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
   char *greeting_attachment; 
   char filename[256];

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

   if (cidnum) {
      strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
   }
   if (cidname) {
      strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
   }
   gethostname(host, sizeof(host) - 1);

   if (strchr(srcemail, '@')) {
      ast_copy_string(who, srcemail, sizeof(who));
   } else {
      snprintf(who, sizeof(who), "%s@%s", srcemail, host);
   }

   greeting_attachment = strrchr(ast_strdupa(attach), '/');
   if (greeting_attachment) {
      *greeting_attachment++ = '\0';
   }

   snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
   ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
   fprintf(p, "Date: %s" ENDL, date);

   /* Set date format for voicemail mail */
   ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));

   if (!ast_strlen_zero(fromstring)) {
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         char *ptr;
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, fromstring);

         if (check_mime(ast_str_buffer(str1))) {
            int first_line = 1;
            ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
            while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
               *ptr = '\0';
               fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
               first_line = 0;
               /* Substring is smaller, so this will never grow */
               ast_str_set(&str2, 0, "%s", ptr + 1);
            }
            fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
         } else {
            fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
         }
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else {
      fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
   }

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

   if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
      char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, e_subj);
         if (check_mime(ast_str_buffer(str1))) {
            int first_line = 1;
            char *ptr;
            ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
            while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
               *ptr = '\0';
               fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
               first_line = 0;
               /* Substring is smaller, so this will never grow */
               ast_str_set(&str2, 0, "%s", ptr + 1);
            }
            fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
         } else {
            fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
         }
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
      if (ast_strlen_zero(flag)) {
         fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
      } else {
         fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
      }
   } else {
      if (ast_strlen_zero(flag)) {
         fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
      } else {
         fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
      }
   }

   fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
      (unsigned int) ast_random(), mailbox, (int) getpid(), host);
   if (imap) {
      /* additional information needed for IMAP searching */
      fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
      /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
      fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
      fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
#ifdef IMAP_STORAGE
      fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
#else
      fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
#endif
      /* flag added for Urgent */
      fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
      fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan ? ast_channel_priority(chan) : 0);
      fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan ? ast_channel_name(chan) : "");
      fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
      fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
      fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
      if (!ast_strlen_zero(category)) {
         fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
      } else {
         fprintf(p, "X-Asterisk-VM-Category: " ENDL);
      }
      fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
      fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
      fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
      fprintf(p, "X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
   }
   if (!ast_strlen_zero(cidnum)) {
      fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
   }
   if (!ast_strlen_zero(cidname)) {
      fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
   }
   fprintf(p, "MIME-Version: 1.0" ENDL);
   if (attach_user_voicemail) {
      /* Something unique. */
      snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
         (int) getpid(), (unsigned int) ast_random());

      fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
      fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
      fprintf(p, "--%s" ENDL, bound);
   }
   fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
   if (emailbody || vmu->emailbody) {
      char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, e_body);
#ifdef IMAP_STORAGE
            {
               /* Convert body to native line terminators for IMAP backend */
               char *line = ast_str_buffer(str1), *next;
               do {
                  /* Terminate line before outputting it to the file */
                  if ((next = strchr(line, '\n'))) {
                     *next++ = '\0';
                  }
                  fprintf(p, "%s" ENDL, line);
                  line = next;
               } while (!ast_strlen_zero(line));
            }
#else
         fprintf(p, "%s" ENDL, ast_str_buffer(str1));
#endif
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else if (msgnum > -1) {
      if (strcmp(vmu->mailbox, mailbox)) {
         /* Forwarded type */
         struct ast_config *msg_cfg;
         const char *v;
         int inttime;
         char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
         struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
         /* Retrieve info from VM attribute file */
         make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
         make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
         if (strlen(fromfile) < sizeof(fromfile) - 5) {
            strcat(fromfile, ".txt");
         }
         if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
            if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
               ast_copy_string(origcallerid, v, sizeof(origcallerid));
            }

            /* You might be tempted to do origdate, except that a) it's in the wrong
             * format, and b) it's missing for IMAP recordings. */
            if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
               struct timeval tv = { inttime, };
               struct ast_tm tm;
               ast_localtime(&tv, &tm, NULL);
               ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
            }
            fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
               " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
               "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
               " chance.  Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
               msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
               date, origcallerid, origdate);
            ast_config_destroy(msg_cfg);
         } else {
            goto plain_message;
         }
      } else {
plain_message:
         fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
            "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
            "want to check it when you get a chance.  Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
            ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
            (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
      }
   } else {
      fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
            "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
   }

   if (imap || attach_user_voicemail) {
      if (!ast_strlen_zero(attach2)) {
         snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
         ast_debug(5, "creating second attachment filename %s\n", filename);
         add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
         snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
         ast_debug(5, "creating attachment filename %s\n", filename);
         add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
      } else {
         snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
         ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
         add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
      }
   }
   ast_free(str1);
   ast_free(str2);
}
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:
destThe variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
lenThe length of the path string that was written out.
dir
num

The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns:
zero on success, -1 on error.

Definition at line 1846 of file app_voicemail.c.

Referenced by advanced_options(), close_mailbox(), copy_message(), forward_message(), leave_voicemail(), make_email_file(), message_range_and_existence_check(), msg_create_from_file(), notify_new_message(), play_message(), play_message_by_id_helper(), prep_email_sub_vars(), resequence_mailbox(), save_to_folder(), vm_execmain(), vm_forwardoptions(), vm_msg_forward(), vm_msg_play(), and vm_msg_snapshot_create().

{
   return snprintf(dest, len, "%s/msg%04d", dir, num);
}
static int manager_list_voicemail_users ( struct mansession s,
const struct message m 
) [static]

Manager list voicemail users command.

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

{
   struct ast_vm_user *vmu = NULL;
   const char *id = astman_get_header(m, "ActionID");
   char actionid[128] = "";

   if (!ast_strlen_zero(id))
      snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);

   AST_LIST_LOCK(&users);

   if (AST_LIST_EMPTY(&users)) {
      astman_send_ack(s, m, "There are no voicemail users currently defined.");
      AST_LIST_UNLOCK(&users);
      return RESULT_SUCCESS;
   }
   
   astman_send_ack(s, m, "Voicemail user list will follow");
   
   AST_LIST_TRAVERSE(&users, vmu, list) {
      char dirname[256];

#ifdef IMAP_STORAGE
      int new, old;
      inboxcount(vmu->mailbox, &new, &old);
#endif
      
      make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
      astman_append(s,
         "%s"
         "Event: VoicemailUserEntry\r\n"
         "VMContext: %s\r\n"
         "VoiceMailbox: %s\r\n"
         "Fullname: %s\r\n"
         "Email: %s\r\n"
         "Pager: %s\r\n"
         "ServerEmail: %s\r\n"
         "MailCommand: %s\r\n"
         "Language: %s\r\n"
         "TimeZone: %s\r\n"
         "Callback: %s\r\n"
         "Dialout: %s\r\n"
         "UniqueID: %s\r\n"
         "ExitContext: %s\r\n"
         "SayDurationMinimum: %d\r\n"
         "SayEnvelope: %s\r\n"
         "SayCID: %s\r\n"
         "AttachMessage: %s\r\n"
         "AttachmentFormat: %s\r\n"
         "DeleteMessage: %s\r\n"
         "VolumeGain: %.2f\r\n"
         "CanReview: %s\r\n"
         "CallOperator: %s\r\n"
         "MaxMessageCount: %d\r\n"
         "MaxMessageLength: %d\r\n"
         "NewMessageCount: %d\r\n"
#ifdef IMAP_STORAGE
         "OldMessageCount: %d\r\n"
         "IMAPUser: %s\r\n"
         "IMAPServer: %s\r\n"
         "IMAPPort: %s\r\n"
         "IMAPFlags: %s\r\n"
#endif
         "\r\n",
         actionid,
         vmu->context,
         vmu->mailbox,
         vmu->fullname,
         vmu->email,
         vmu->pager,
         ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
         mailcmd,
         vmu->language,
         vmu->zonetag,
         vmu->callback,
         vmu->dialout,
         vmu->uniqueid,
         vmu->exit,
         vmu->saydurationm,
         ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
         ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
         ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
         vmu->attachfmt,
         ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
         vmu->volgain,
         ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
         ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
         vmu->maxmsg,
         vmu->maxsecs,
#ifdef IMAP_STORAGE
         new, old,
         vmu->imapuser,
         vmu->imapserver,
         vmu->imapport,
         vmu->imapflags
#else
         count_messages(vmu, dirname)
#endif
         );
   }     
   astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);

   AST_LIST_UNLOCK(&users);

   return RESULT_SUCCESS;
}
static void* mb_poll_thread ( void *  data) [static]

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

{
   while (poll_thread_run) {
      struct timespec ts = { 0, };
      struct timeval wait;

      wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
      ts.tv_sec = wait.tv_sec;
      ts.tv_nsec = wait.tv_usec * 1000;

      ast_mutex_lock(&poll_lock);
      ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
      ast_mutex_unlock(&poll_lock);

      if (!poll_thread_run)
         break;

      poll_subscribed_mailboxes();
   }

   return NULL;
}
static const char* mbox ( struct ast_vm_user vmu,
int  id 
) [static]

Definition at line 1888 of file app_voicemail.c.

References ARRAY_LEN, and id.

Referenced by acf_mailbox_exists(), add_peer_mailboxes(), adsi_load_vmail(), build_gateway(), copy_message(), get_folder(), has_voicemail(), notify_new_message(), open_mailbox(), save_to_folder(), vm_box_exists(), vm_execmain(), and vm_index_to_foldername().

{
#ifdef IMAP_STORAGE
   if (vmu && id == 0) {
      return vmu->imapfolder;
   }
#endif
   return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
}
static int message_range_and_existence_check ( struct vm_state vms,
const char *  msg_ids[],
size_t  num_msgs,
int *  msg_nums,
struct ast_vm_user vmu 
) [static]

common bounds checking and existence check for Voicemail API functions.

This is called by vm_msg_move, vm_msg_remove, and vm_msg_forward to ensure that data passed in are valid. This ensures that given the desired message IDs, they can be found.

Parameters:
vmsThe voicemail state corresponding to an open mailbox
msg_idsAn array of message identifiers
num_msgsThe number of identifiers in msg_ids
msg_nums[out] The message indexes corresponding to the given message IDs
Precondition:
vms must have open_mailbox() called on it prior to this function.
Return values:
-1Failure
0Success

Definition at line 15131 of file app_voicemail.c.

References ast_config_destroy(), ast_config_load, ast_strlen_zero(), ast_variable_retrieve(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, vm_state::fn, vm_state::lastmsg, ast_vm_user::mailbox, make_file(), and RETRIEVE.

Referenced by play_message_by_id_helper(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   int i;
   int res = 0;
   for (i = 0; i < num_msgs; ++i) {
      const char *msg_id = msg_ids[i];
      int found = 0;
      for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
         const char *other_msg_id;
         char filename[PATH_MAX];
         struct ast_config *msg_cfg;
         struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };

         make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
         snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
         RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
         msg_cfg = ast_config_load(filename, config_flags);
         if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
            DISPOSE(vms->curdir, vms->curmsg);
            res = -1;
            goto done;
         }

         other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");

         if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
            /* Message found. We can get out of this inner loop
             * and move on to the next message to find
             */
            found = 1;
            msg_nums[i] = vms->curmsg;
            ast_config_destroy(msg_cfg);
            DISPOSE(vms->curdir, vms->curmsg);
            break;
         }
         ast_config_destroy(msg_cfg);
         DISPOSE(vms->curdir, vms->curmsg);
      }
      if (!found) {
         /* If we can't find one of the message IDs requested, then OH NO! */
         res = -1;
         goto done;
      }
   }

done:
   return res;
}
static int messagecount ( const char *  context,
const char *  mailbox,
const char *  folder 
) [static]

Definition at line 5740 of file app_voicemail.c.

References __has_voicemail().

Referenced by acf_vm_info(), and load_module().

{
   return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
}
static int msg_create_from_file ( struct ast_vm_recording_data recdata) [static]

Definition at line 5963 of file app_voicemail.c.

References ast_check_realtime(), ast_debug, ast_destroy_realtime(), ast_filecopy(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_format_rate(), ast_getformatbyname(), ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, ast_readfile(), ast_seekstream(), ast_store_realtime(), ast_tellstream(), ast_unlock_path(), ast_vm_recording_data::call_callerchan, ast_vm_recording_data::call_callerid, ast_vm_recording_data::call_context, ast_vm_recording_data::call_extension, ast_vm_recording_data::call_macrocontext, ast_vm_recording_data::call_priority, ast_vm_recording_data::context, ast_vm_user::context, count_messages(), create_dirpath(), errno, find_user(), ast_vm_recording_data::folder, free_user(), generate_msg_id(), get_date(), inboxcount(), inprocess_count(), last_message_index(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_vm_recording_data::mailbox, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, MSG_ID_LEN, vm_state::newmessages, ast_vm_recording_data::recording_ext, ast_vm_recording_data::recording_file, S_OR, SENTINEL, STORE, vm_lock_path(), VOICEMAIL_DIR_MODE, and VOICEMAIL_FILE_MODE.

Referenced by load_module().

{
   /* voicemail recipient structure */
   struct ast_vm_user *recipient; /* points to svm once it's been created */
   struct ast_vm_user svm; /* struct storing the voicemail recipient */

   /* File paths */
   char tmpdir[PATH_MAX]; /* directory temp files are stored in */
   char tmptxtfile[PATH_MAX]; /* tmp file for voicemail txt file */
   char desttxtfile[PATH_MAX]; /* final destination for txt file */
   char tmpaudiofile[PATH_MAX]; /* tmp file where audio is stored */
   char dir[PATH_MAX]; /* destination for tmp files on completion */
   char destination[PATH_MAX]; /* destination with msgXXXX.  Basically <dir>/msgXXXX */

   /* stuff that only seems to be needed for IMAP */
   #ifdef IMAP_STORAGE
   struct vm_state *vms = NULL;
   char ext_context[256] = "";
   char *fmt = ast_strdupa(recdata->recording_ext);
   int newmsgs = 0;
   int oldmsgs = 0;
   #endif

   /* miscellaneous operational variables */
   int res = 0; /* Used to store error codes from functions */
   int txtdes /* File descriptor for the text file used to write the voicemail info */;
   FILE *txt; /* FILE pointer to text file used to write the voicemail info */
   char date[256]; /* string used to hold date of the voicemail (only used for ODBC) */
   int msgnum; /* the 4 digit number designated to the voicemail */
   int duration = 0; /* Length of the audio being recorded in seconds */
   struct ast_filestream *recording_fs; /*used to read the recording to get duration data */

   /* We aren't currently doing anything with category, since it comes from a channel variable and
    * this function doesn't use channels, but this function could add that as an argument later. */
   const char *category = NULL; /* pointless for now */
   char msg_id[MSG_ID_LEN];

   /* Start by checking to see if the file actually exists... */
   if (!(ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL))) {
      ast_log(LOG_ERROR, "File: %s not found.\n", recdata->recording_file);
      return -1;
   }

   if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) {
      ast_log(LOG_ERROR, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
      return -1;
   }

   /* determine duration in seconds */
   if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
      if (!ast_seekstream(recording_fs, 0, SEEK_END)) {
         long framelength = ast_tellstream(recording_fs);
         struct ast_format result = {0,};
         /* XXX This use of ast_getformatbyname seems incorrect here. The file extension does not necessarily correspond
          * to the name of the format. For instance, if "raw" were passed in, I don't think ast_getformatbyname would
          * find the slinear format
          */
         ast_getformatbyname(recdata->recording_ext, &result);
         duration = (int) (framelength / ast_format_rate(&result));
      }
   }

   /* If the duration was below the minimum duration for the user, let's just drop the whole thing now */
   if (duration < recipient->minsecs) {
      ast_log(LOG_NOTICE, "Copying recording to voicemail %s@%s skipped because duration was shorter than "
               "minmessage of recipient\n", recdata->mailbox, recdata->context);
      return -1;
   }

   /* Note that this number must be dropped back to a net sum of zero before returning from this function */

   if ((res = create_dirpath(tmpdir, sizeof(tmpdir), recipient->context, recdata->mailbox, "tmp"))) {
      ast_log(LOG_ERROR, "Failed to make directory.\n");
   }

   snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
   txtdes = mkstemp(tmptxtfile);
   if (txtdes < 0) {
      chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
      /* Something screwed up.  Abort. */
      ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
      free_user(recipient);
      return -1;
   }

   /* Store information */
   txt = fdopen(txtdes, "w+");
   if (txt) {
      generate_msg_id(msg_id);
      get_date(date, sizeof(date));
      fprintf(txt,
         ";\n"
         "; Message Information file\n"
         ";\n"
         "[message]\n"
         "origmailbox=%s\n"
         "context=%s\n"
         "macrocontext=%s\n"
         "exten=%s\n"
         "rdnis=Unknown\n"
         "priority=%d\n"
         "callerchan=%s\n"
         "callerid=%s\n"
         "origdate=%s\n"
         "origtime=%ld\n"
         "category=%s\n"
         "msg_id=%s\n"
         "flag=\n" /* flags not supported in copy from file yet */
         "duration=%d\n", /* Don't have any reliable way to get duration of file. */

         recdata->mailbox,
         S_OR(recdata->call_context, ""),
         S_OR(recdata->call_macrocontext, ""),
         S_OR(recdata->call_extension, ""),
         recdata->call_priority,
         S_OR(recdata->call_callerchan, "Unknown"),
         S_OR(recdata->call_callerid, "Unknown"),
         date, (long) time(NULL),
         S_OR(category, ""),
         msg_id,
         duration);

      /* Since we are recording from a file, we shouldn't need to do anything else with
       * this txt file */
      fclose(txt);

   } else {
      ast_log(LOG_WARNING, "Error opening text file for output\n");
      if (ast_check_realtime("voicemail_data")) {
         ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
      }
      free_user(recipient);
      return -1;
   }

   /* At this point, the actual creation of a voicemail message should be finished.
    * Now we just need to copy the files being recorded into the receiving folder. */

   create_dirpath(dir, sizeof(dir), recipient->context, recipient->mailbox, recdata->folder);

#ifdef IMAP_STORAGE
   /* make recipient info into an inboxcount friendly string */
   snprintf(ext_context, sizeof(ext_context), "%s@%s", recipient->mailbox, recipient->context);

   /* Is ext a mailbox? */
   /* must open stream for this user to get info! */
   res = inboxcount(ext_context, &newmsgs, &oldmsgs);
   if (res < 0) {
      ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
      free_user(recipient);
      unlink(tmptxtfile);
      return -1;
   }
   if (!(vms = get_vm_state_by_mailbox(recipient->mailbox, recipient->context, 0))) {
   /* It is possible under certain circumstances that inboxcount did not
    * create a vm_state when it was needed. This is a catchall which will
    * rarely be used.
    */
      if (!(vms = create_vm_state_from_user(recipient))) {
         ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
         free_user(recipient);
         unlink(tmptxtfile);
         return -1;
      }
   }
   vms->newmessages++;

   /* here is a big difference! We add one to it later */
   msgnum = newmsgs + oldmsgs;
   ast_debug(3, "Messagecount set to %d\n", msgnum);
   snprintf(destination, sizeof(destination), "%simap/msg%s%04d", VM_SPOOL_DIR, recipient->mailbox, msgnum);

   /* Check to see if we have enough room in the mailbox. If not, spit out an error and end
    * Note that imap_check_limits raises inprocess_count if successful */
   if ((res = imap_check_limits(NULL, vms, recipient, msgnum))) {
      ast_log(LOG_NOTICE, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
      inprocess_count(recipient->mailbox, recipient->context, -1);
      free_user(recipient);
      unlink(tmptxtfile);
      return -1;
   }

#else

   /* Check to see if the mailbox is full for ODBC/File storage */
   ast_debug(3, "mailbox = %d : inprocess = %d\n", count_messages(recipient, dir),
      inprocess_count(recipient->mailbox, recipient->context, 0));
   if (count_messages(recipient, dir) > recipient->maxmsg - inprocess_count(recipient->mailbox, recipient->context, +1)) {
      ast_log(AST_LOG_WARNING, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
      inprocess_count(recipient->mailbox, recipient->context, -1);
      free_user(recipient);
      unlink(tmptxtfile);
      return -1;
   }

   msgnum = last_message_index(recipient, dir) + 1;
#endif

   /* Lock the directory receiving the voicemail since we want it to still exist when we attempt to copy the voicemail.
    * We need to unlock it before we return. */
   if (vm_lock_path(dir)) {
      ast_log(LOG_ERROR, "Couldn't lock directory %s.  Voicemail will be lost.\n", dir);
      /* Delete files */
      ast_filedelete(tmptxtfile, NULL);
      unlink(tmptxtfile);
      free_user(recipient);
      return -1;
   }

   make_file(destination, sizeof(destination), dir, msgnum);

   make_file(tmpaudiofile, sizeof(tmpaudiofile), tmpdir, msgnum);

   if (ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
      ast_log(LOG_ERROR, "Audio file failed to copy to tmp dir. Probably low disk space.\n");

      inprocess_count(recipient->mailbox, recipient->context, -1);
      ast_unlock_path(dir);
      free_user(recipient);
      unlink(tmptxtfile);
      return -1;
   }

   /* Alright, try to copy to the destination folder now. */
   if (ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
      ast_log(LOG_ERROR, "Audio file failed to move to destination directory. Permissions/Overlap?\n");
      inprocess_count(recipient->mailbox, recipient->context, -1);
      ast_unlock_path(dir);
      free_user(recipient);
      unlink(tmptxtfile);
      return -1;
   }

   snprintf(desttxtfile, sizeof(desttxtfile), "%s.txt", destination);
   rename(tmptxtfile, desttxtfile);

   if (chmod(desttxtfile, VOICEMAIL_FILE_MODE) < 0) {
      ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno));
   }


   ast_unlock_path(dir);
   inprocess_count(recipient->mailbox, recipient->context, -1);

   /* If we copied something, we should store it either to ODBC or IMAP if we are using those. The STORE macro allows us
    * to do both with one line and is also safe to use with file storage mode. Also, if we are using ODBC, now is a good
    * time to create the voicemail database entry. */
   if (ast_fileexists(destination, NULL, NULL) > 0) {
      if (ast_check_realtime("voicemail_data")) {
         get_date(date, sizeof(date));
         ast_store_realtime("voicemail_data",
            "origmailbox", recdata->mailbox,
            "context", S_OR(recdata->context, ""),
            "macrocontext", S_OR(recdata->call_macrocontext, ""),
            "exten", S_OR(recdata->call_extension, ""),
            "priority", recdata->call_priority,
            "callerchan", S_OR(recdata->call_callerchan, "Unknown"),
            "callerid", S_OR(recdata->call_callerid, "Unknown"),
            "origdate", date,
            "origtime", time(NULL),
            "category", S_OR(category, ""),
            "filename", tmptxtfile,
            "duration", duration,
            SENTINEL);
      }

      STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
   }

   free_user(recipient);
   unlink(tmptxtfile);
   return 0;
}
static void mwi_sub_destroy ( struct mwi_sub mwi_sub) [static]

Definition at line 12517 of file app_voicemail.c.

References ast_free.

Referenced by handle_unsubscribe().

{
   ast_free(mwi_sub);
}
static void mwi_unsub_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 12579 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_log(), ast_taskprocessor_push(), handle_unsubscribe(), LOG_ERROR, and mwi_sub_task::uniqueid.

Referenced by start_poll_thread().

{
   uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));

   if (!uniqueid) {
      ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
      return;
   }

   if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
      ast_free(uniqueid);
      return;
   }

   if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
      ast_free(uniqueid);
      return;
   }

   u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
   *uniqueid = u;
   if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
      ast_free(uniqueid);
   }
}
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
cidnumThe Caller ID phone number value.
cidnameThe Caller ID name value.
flag
Returns:
zero on success, -1 on error.

Definition at line 7739 of file app_voicemail.c.

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

Referenced by copy_message(), and leave_voicemail().

{
   char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
   int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
   const char *category;
   char *myserveremail = serveremail;

   ast_channel_lock(chan);
   if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
      category = ast_strdupa(category);
   }
   ast_channel_unlock(chan);

#ifndef IMAP_STORAGE
   make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
#else
   snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
#endif
   make_file(fn, sizeof(fn), todir, msgnum);
   snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);

   if (!ast_strlen_zero(vmu->attachfmt)) {
      if (strstr(fmt, vmu->attachfmt))
         fmt = vmu->attachfmt;
      else
         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);
   }

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

   if (!ast_strlen_zero(vmu->serveremail))
      myserveremail = vmu->serveremail;

   if (!ast_strlen_zero(vmu->email)) {
      int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
      char *msg_id = NULL;
#ifdef IMAP_STORAGE
      struct ast_config *msg_cfg;
      struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
      char filename[PATH_MAX];

      snprintf(filename, sizeof(filename), "%s.txt", fn);
      msg_cfg = ast_config_load(filename, config_flags);
      if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
         msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
         ast_config_destroy(msg_cfg);
      }
#endif

      if (attach_user_voicemail)
         RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);

      /* XXX possible imap issue, should category be NULL XXX */
      sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag, msg_id);

      if (attach_user_voicemail)
         DISPOSE(todir, msgnum);
   }

   if (!ast_strlen_zero(vmu->pager)) {
      sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
   }

   if (ast_test_flag(vmu, VM_DELETE))
      DELETE(todir, msgnum, fn, vmu);

   /* Leave voicemail for someone */
   if (ast_app_has_voicemail(ext_context, NULL)) 
      ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);

   queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);

   /*** DOCUMENTATION
      <managerEventInstance>
         <synopsis>Raised when a new message has been left in a voicemail mailbox.</synopsis>
         <syntax>
            <parameter name="Mailbox">
               <para>The mailbox with the new message, specified as <emphasis>mailbox</emphasis>@<emphasis>context</emphasis></para>
            </parameter>
            <parameter name="Waiting">
               <para>Whether or not the mailbox has access to a voicemail application.</para>
            </parameter>
            <parameter name="New">
               <para>The number of new messages.</para>
            </parameter>
            <parameter name="Old">
               <para>The number of old messages.</para>
            </parameter>
         </syntax>
      </managerEventInstance>
   ***/
   ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting",
         "Mailbox: %s@%s\r\n"
         "Waiting: %d\r\n"
         "New: %d\r\n"
         "Old: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
   run_externnotify(vmu->context, vmu->mailbox, flag);

#ifdef IMAP_STORAGE
   vm_delete(fn);  /* Delete the file, but not the IMAP message */
   if (ast_test_flag(vmu, VM_DELETE))  { /* Delete the IMAP message if delete = yes */
      vm_imap_delete(NULL, vms->curmsg, vmu);
      vms->newmessages--;  /* Fix new message count */
   }
#endif

   return 0;
}
static void notify_new_state ( struct ast_vm_user vmu) [static]

Definition at line 15180 of file app_voicemail.c.

References ast_app_inboxcount2(), ast_vm_user::context, ast_vm_user::mailbox, queue_mwi_event(), and run_externnotify().

Referenced by vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   int new = 0, old = 0, urgent = 0;
   char ext_context[1024];

   snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
   run_externnotify(vmu->context, vmu->mailbox, NULL);
   ast_app_inboxcount2(ext_context, &urgent, &new, &old);
   queue_mwi_event(ext_context, urgent, new, old);
}
static int ochar ( struct baseio bio,
int  c,
FILE *  so 
) [static]

utility used by base_encode()

Definition at line 4568 of file app_voicemail.c.

References BASELINELEN, ENDL, and baseio::linelength.

Referenced by base_encode().

{
   if (bio->linelength >= BASELINELEN) {
      if (fputs(ENDL, so) == EOF) {
         return -1;
      }

      bio->linelength = 0;
   }

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

   bio->linelength++;

   return 1;
}
static int open_mailbox ( struct vm_state vms,
struct ast_vm_user vmu,
int  box 
) [static]

Definition at line 8652 of file app_voicemail.c.

References ast_copy_string(), ast_log(), AST_LOG_ERROR, ast_unlock_path(), ast_vm_user::context, count_messages(), create_dirpath(), vm_state::curbox, vm_state::curdir, ERROR_LOCK_PATH, last_message_index(), vm_state::lastmsg, LOG_NOTICE, ast_vm_user::maxmsg, mbox(), resequence_mailbox(), vm_state::username, vm_allocate_dh(), vm_lock_path(), and vm_state::vmbox.

Referenced by play_message_by_id(), vm_execmain(), vm_mailbox_snapshot_create(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

{
   int count_msg, last_msg;

   ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));

   /* Rename the member vmbox HERE so that we don't try to return before
    * we know what's going on.
    */
   snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);

   /* Faster to make the directory than to check if it exists. */
   create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);

   /* traverses directory using readdir (or select query for ODBC) */
   count_msg = count_messages(vmu, vms->curdir);
   if (count_msg < 0) {
      return count_msg;
   } else {
      vms->lastmsg = count_msg - 1;
   }

   if (vm_allocate_dh(vms, vmu, count_msg)) {
      return -1;
   }

   /*
   The following test is needed in case sequencing gets messed up.
   There appears to be more than one way to mess up sequence, so
   we will not try to find all of the root causes--just fix it when
   detected.
   */

   if (vm_lock_path(vms->curdir)) {
      ast_log(AST_LOG_ERROR, "Could not open mailbox %s:  mailbox is locked\n", vms->curdir);
      return ERROR_LOCK_PATH;
   }

   /* for local storage, checks directory for messages up to maxmsg limit */
   last_msg = last_message_index(vmu, vms->curdir);
   ast_unlock_path(vms->curdir);

   if (last_msg < -1) {
      return last_msg;
   } else if (vms->lastmsg != last_msg) {
      ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
      resequence_mailbox(vmu, vms->curdir, count_msg);
   }

   return 0;
}
static int play_message ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms 
) [static]

Definition at line 8426 of file app_voicemail.c.

References adsi_message(), ast_channel_language(), ast_config_destroy(), ast_config_load, AST_DIGIT_ANY, ast_fileexists(), ast_log(), AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_say_number(), ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, ast_variable_retrieve(), CONFIG_FLAG_NOCACHE, context, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, vm_state::fn, vm_state::heard, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), play_message_callerid(), play_message_category(), play_message_datetime(), play_message_duration(), RETRIEVE, ast_vm_user::saydurationm, vm_state::starting, valid_config(), VM_ENVELOPE, VM_SAYCID, VM_SAYDURATION, wait_file(), and wait_file2().

Referenced by vm_browse_messages_en(), vm_browse_messages_es(), vm_browse_messages_gr(), vm_browse_messages_he(), vm_browse_messages_it(), vm_browse_messages_pt(), vm_browse_messages_vi(), vm_browse_messages_zh(), and vm_execmain().

{
   int res = 0;
   char filename[256], *cid;
   const char *origtime, *context, *category, *duration, *flag;
   struct ast_config *msg_cfg;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };

   vms->starting = 0;
   make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
   adsi_message(chan, vms);
   if (!vms->curmsg) {
      res = wait_file2(chan, vms, "vm-first");  /* "First" */
   } else if (vms->curmsg == vms->lastmsg) {
      res = wait_file2(chan, vms, "vm-last");      /* "last" */
   }

   snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
   RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
   msg_cfg = ast_config_load(filename, config_flags);
   if (!valid_config(msg_cfg)) {
      ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
      return 0;
   }
   flag = ast_variable_retrieve(msg_cfg, "message", "flag");

   /* Play the word urgent if we are listening to urgent messages */
   if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
      res = wait_file2(chan, vms, "vm-Urgent"); /* "urgent" */
   }

   if (!res) {
      /* XXX Why are we playing messages above, and then playing the same language-specific stuff here? */
      /* POLISH syntax */
      if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
         if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
            int ten, one;
            char nextmsg[256];
            ten = (vms->curmsg + 1) / 10;
            one = (vms->curmsg + 1) % 10;

            if (vms->curmsg < 20) {
               snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
               res = wait_file2(chan, vms, nextmsg);
            } else {
               snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
               res = wait_file2(chan, vms, nextmsg);
               if (one > 0) {
                  if (!res) {
                     snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
                     res = wait_file2(chan, vms, nextmsg);
                  }
               }
            }
         }
         if (!res)
            res = wait_file2(chan, vms, "vm-message");
      /* HEBREW syntax */
      } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
         if (!vms->curmsg) {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-first");
         } else if (vms->curmsg == vms->lastmsg) {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-last");
         } else {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-number");
            res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
         }
      /* VIETNAMESE syntax */
      } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
         if (!vms->curmsg) {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-first");
         } else if (vms->curmsg == vms->lastmsg) {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-last");
         } else {
            res = wait_file2(chan, vms, "vm-message");
            res = wait_file2(chan, vms, "vm-number");
            res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
         }
      } else {
         if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
            res = wait_file2(chan, vms, "vm-meddelandet");  /* "message" */
         } else { /* DEFAULT syntax */
            res = wait_file2(chan, vms, "vm-message");
         }
         if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
            if (!res) {
               ast_test_suite_event_notify("PLAYBACK", "Message: message number");
               res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
            }
         }
      }
   }

   if (!valid_config(msg_cfg)) {
      ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
      return 0;
   }

   if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
      ast_log(AST_LOG_WARNING, "No origtime?!\n");
      DISPOSE(vms->curdir, vms->curmsg);
      ast_config_destroy(msg_cfg);
      return 0;
   }

   cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
   duration = ast_variable_retrieve(msg_cfg, "message", "duration");
   category = ast_variable_retrieve(msg_cfg, "message", "category");

   context = ast_variable_retrieve(msg_cfg, "message", "context");
   if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
      context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
   if (!res) {
      res = play_message_category(chan, category);
   }
   if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
      res = play_message_datetime(chan, vmu, origtime, filename);
   }
   if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
      res = play_message_callerid(chan, vms, cid, context, 0, 0);
   }
   if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
      res = play_message_duration(chan, vms, duration, vmu->saydurationm);
   }
   /* Allow pressing '1' to skip envelope / callerid */
   if (res == '1') {
      ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
      res = 0;
   }
   ast_config_destroy(msg_cfg);

   if (!res) {
      make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
#ifdef IMAP_STORAGE
      ast_mutex_lock(&vms->lock);
#endif
      vms->heard[vms->curmsg] = 1;
#ifdef IMAP_STORAGE
      ast_mutex_unlock(&vms->lock);
      /*IMAP storage stores any prepended message from a forward
       * as a separate file from the rest of the message
       */
      if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
         wait_file(chan, vms, vms->introfn);
      }
#endif
      if ((res = wait_file(chan, vms, vms->fn)) < 0) {
         ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
         res = 0;
      }
      ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
   }
   DISPOSE(vms->curdir, vms->curmsg);
   return res;
}
static int play_message_by_id ( struct ast_channel chan,
const char *  mailbox,
const char *  context,
const char *  msg_id 
) [static]

Finds a message in a specific mailbox by msg_id and plays it to the channel.

Return values:
0Success
-1Failure

Definition at line 10692 of file app_voicemail.c.

References ARRAY_LEN, ast_copy_string(), ast_log(), close_mailbox(), ERROR_LOCK_PATH, find_user(), vm_state::lastmsg, LOG_WARNING, open_mailbox(), play_message_by_id_helper(), and vm_state::username.

Referenced by vm_playmsgexec().

{
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   int res = 0;
   int open = 0;
   int played = 0;
   int i;

   memset(&vmus, 0, sizeof(vmus));
   memset(&vms, 0, sizeof(vms));

   if (!(vmu = find_user(&vmus, context, mailbox))) {
      goto play_msg_cleanup;
   }

   /* Iterate through every folder, find the msg, and play it */
   for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
      ast_copy_string(vms.username, mailbox, sizeof(vms.username));
      vms.lastmsg = -1;

      /* open the mailbox state */
      if ((res = open_mailbox(&vms, vmu, i)) < 0) {
         ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
         res = -1;
         goto play_msg_cleanup;
      }
      open = 1;

      /* play msg if it exists in this mailbox */
      if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
         played = 1;
      }

      /* close mailbox */
      if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
         res = -1;
         goto play_msg_cleanup;
      }
      open = 0;
   }

play_msg_cleanup:
   if (!played) {
      res = -1;
   }

   if (vmu && open) {
      close_mailbox(&vms, vmu);
   }

#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif

   return res;
}
static int play_message_by_id_helper ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
const char *  msg_id 
) [static]

Definition at line 10650 of file app_voicemail.c.

References ast_fileexists(), ast_log(), AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), vm_state::curdir, vm_state::curmsg, vm_state::fn, vm_state::heard, make_file(), message_range_and_existence_check(), and wait_file().

Referenced by play_message_by_id().

{
   if (message_range_and_existence_check(vms, &msg_id, 1, &vms->curmsg, vmu)) {
      return -1;
   }
   /* Found the msg, so play it back */

   make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
   make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);

#ifdef IMAP_STORAGE
   /*IMAP storage stores any prepended message from a forward
    * as a separate file from the rest of the message
    */
   if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
      wait_file(chan, vms, vms->introfn);
   }
#endif
   if ((wait_file(chan, vms, vms->fn)) < 0) {
      ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
   } else {
#ifdef IMAP_STORAGE
      ast_mutex_lock(&vms->lock);
#endif
      vms->heard[vms->curmsg] = 1;
#ifdef IMAP_STORAGE
      ast_mutex_unlock(&vms->lock);
#endif
   }

   return 0;
}
static int play_message_callerid ( struct ast_channel chan,
struct vm_state vms,
char *  cid,
const char *  context,
int  callback,
int  saycidnumber 
) [static]

Definition at line 8299 of file app_voicemail.c.

References ast_callerid_parse(), ast_channel_language(), ast_config_AST_SPOOL_DIR, ast_debug, AST_DIGIT_ANY, ast_fileexists(), ast_say_digit_str(), ast_stream_and_wait(), ast_strlen_zero(), ast_verb, MAX_NUM_CID_CONTEXTS, name, and wait_file2().

Referenced by advanced_options(), and play_message().

{
   int res = 0;
   int i;
   char *callerid, *name;
   char prefile[PATH_MAX] = "";

   /* If voicemail cid is not enabled, or we didn't get cid or context from
    * the attribute file, leave now.
    *
    * TODO Still need to change this so that if this function is called by the
    * message envelope (and someone is explicitly requesting to hear the CID),
    * it does not check to see if CID is enabled in the config file.
    */
   if ((cid == NULL)||(context == NULL))
      return res;

   /* Strip off caller ID number from name */
   ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
   ast_callerid_parse(cid, &name, &callerid);
   if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
      /* Check for internal contexts and only */
      /* say extension when the call didn't come from an internal context in the list */
      for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
         ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
         if ((strcmp(cidinternalcontexts[i], context) == 0))
            break;
      }
      if (i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
         if (!res) {
            snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
            if (!ast_strlen_zero(prefile)) {
               /* See if we can find a recorded name for this callerid
                * and if found, use that instead of saying number. */
               if (ast_fileexists(prefile, NULL, NULL) > 0) {
                  ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
                  if (!callback)
                     res = wait_file2(chan, vms, "vm-from");
                  res = ast_stream_and_wait(chan, prefile, "");
               } else {
                  ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
                  /* Say "from extension" as one saying to sound smoother */
                  if (!callback)
                     res = wait_file2(chan, vms, "vm-from-extension");
                  res = ast_say_digit_str(chan, callerid, "", ast_channel_language(chan));
               }
            }
         }
      } else if (!res) {
         ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
         /* If there is a recording for this numeric callerid then play that */
         if (!callback) {
            /* See if we can find a recorded name for this person instead of their extension number */
            snprintf(prefile, sizeof(prefile), "%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
            if (!saycidnumber && ast_fileexists(prefile, NULL, NULL) > 0) {
               ast_verb(3, "Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
               wait_file2(chan, vms, "vm-from");
               res = ast_stream_and_wait(chan, prefile, "");
               ast_verb(3, "Played recorded name result '%d'\n", res);
            } else {
               /* Since this is all nicely figured out, why not say "from phone number" in this case" */
               wait_file2(chan, vms, "vm-from-phonenumber");
               res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
            }
         } else {
            res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
         }
      }
   } else {
      /* Number unknown */
      ast_debug(1, "VM-CID: From an unknown number\n");
      /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
      res = wait_file2(chan, vms, "vm-unknown-caller");
   }
   return res;
}
static int play_message_category ( struct ast_channel chan,
const char *  category 
) [static]

Definition at line 8210 of file app_voicemail.c.

References ast_log(), AST_LOG_WARNING, ast_play_and_wait(), and ast_strlen_zero().

Referenced by play_message().

{
   int res = 0;

   if (!ast_strlen_zero(category))
      res = ast_play_and_wait(chan, category);

   if (res) {
      ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
      res = 0;
   }

   return res;
}
static int play_message_datetime ( struct ast_channel chan,
struct ast_vm_user vmu,
const char *  origtime,
const char *  filename 
) [static]

Definition at line 8225 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_get_time_t(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_log(), AST_LOG_WARNING, ast_say_date_with_format, ast_strlen_zero(), ast_tvnow(), vm_zone::msg_format, vm_zone::name, pbx_builtin_setvar_helper(), vm_zone::timezone, and ast_vm_user::zonetag.

Referenced by advanced_options(), and play_message().

{
   int res = 0;
   struct vm_zone *the_zone = NULL;
   time_t t;

   if (ast_get_time_t(origtime, &t, 0, NULL)) {
      ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
      return 0;
   }

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

/* No internal variable parsing for now, so we'll comment it out for the time being */
#if 0
   /* Set the DIFF_* variables */
   ast_localtime(&t, &time_now, NULL);
   tv_now = ast_tvnow();
   ast_localtime(&tv_now, &time_then, NULL);

   /* Day difference */
   if (time_now.tm_year == time_then.tm_year)
      snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
   else
      snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
   pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);

   /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
#endif
   if (the_zone) {
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
   } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {     /* GERMAN syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {     /* GREEK syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q  H 'digits/kai' M ", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {     /* ITALIAN syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {     /* DUTCH syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {     /* NORWEGIAN syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {     /* POLISH syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q HM", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {  /* Brazillian PORTUGUESE syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {     /* SWEDISH syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {     /* CHINESE (Taiwan) syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "qR 'vm-received'", NULL);
   } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {     /* VIETNAMESE syntax */
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
   } else {
      res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL);
   }
#if 0
   pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
#endif
   return res;
}
static int play_message_duration ( struct ast_channel chan,
struct vm_state vms,
const char *  duration,
int  minduration 
) [static]

Definition at line 8376 of file app_voicemail.c.

References ast_channel_language(), ast_debug, AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), say_and_wait(), and wait_file2().

Referenced by play_message().

{
   int res = 0;
   int durationm;
   int durations;
   /* Verify that we have a duration for the message */
   if (duration == NULL)
      return res;

   /* Convert from seconds to minutes */
   durations = atoi(duration);
   durationm = (durations / 60);

   ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);

   if ((!res) && (durationm >= minduration)) {
      res = wait_file2(chan, vms, "vm-duration");

      /* POLISH syntax */
      if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
         div_t num = div(durationm, 10);

         if (durationm == 1) {
            res = ast_play_and_wait(chan, "digits/1z");
            res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
         } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
            if (num.rem == 2) {
               if (!num.quot) {
                  res = ast_play_and_wait(chan, "digits/2-ie");
               } else {
                  res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
                  res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
               }
            } else {
               res = say_and_wait(chan, durationm, ast_channel_language(chan));
            }
            res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
         } else {
            res = say_and_wait(chan, durationm, ast_channel_language(chan));
            res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
         }
      /* DEFAULT syntax */
      } else {
         res = ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
         res = wait_file2(chan, vms, "vm-minutes");
      }
   }
   return res;
}
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,
int *  sound_duration,
const char *  unlockdir,
signed char  record_gain,
struct vm_state vms,
char *  flag,
const char *  msg_id 
) [static]

Definition at line 14564 of file app_voicemail.c.

References acceptdtmf, ast_channel_setoption(), ast_copy_string(), AST_DIGIT_ANY, ast_filedelete(), ast_filerename(), ast_log(), AST_LOG_WARNING, AST_OPTION_RXGAIN, ast_play_and_record_full(), ast_play_and_wait(), ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfordigit(), ast_vm_user::context, DELETE, DISPOSE, INTRO, ast_vm_user::mailbox, STORE, vm_exec(), VM_OPERATOR, and VM_REVIEW.

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

{
   /* Record message & let caller review or re-record it, or set options if applicable */
   int res = 0;
   int cmd = 0;
   int max_attempts = 3;
   int attempts = 0;
   int recorded = 0;
   int msg_exists = 0;
   signed char zero_gain = 0;
   char tempfile[PATH_MAX];
   char *acceptdtmf = "#";
   char *canceldtmf = "";
   int canceleddtmf = 0;

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

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

   if (!outsidecaller)
      snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
   else
      ast_copy_string(tempfile, recordfile, sizeof(tempfile));

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

   while ((cmd >= 0) && (cmd != 't')) {
      switch (cmd) {
      case '1':
         if (!msg_exists) {
            /* In this case, 1 is to record a message */
            cmd = '3';
            break;
         } else {
            /* Otherwise 1 is to save the existing message */
            ast_verb(3, "Saving message as is\n");
            if (!outsidecaller) 
               ast_filerename(tempfile, recordfile, NULL);
            ast_stream_and_wait(chan, "vm-msgsaved", "");
            if (!outsidecaller) {
               /* Saves to IMAP server only if imapgreeting=yes */
               STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id);
               DISPOSE(recordfile, -1);
            }
            cmd = 't';
            return res;
         }
      case '2':
         /* Review */
         ast_verb(3, "Reviewing the message\n");
         cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
         break;
      case '3':
         msg_exists = 0;
         /* Record */
         if (recorded == 1) 
            ast_verb(3, "Re-recording the message\n");
         else  
            ast_verb(3, "Recording the message\n");
         
         if (recorded && outsidecaller) {
            cmd = ast_play_and_wait(chan, INTRO);
            cmd = ast_play_and_wait(chan, "beep");
         }
         recorded = 1;
         /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
         if (ast_test_flag(vmu, VM_OPERATOR))
            canceldtmf = "0";
         cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
         if (strchr(canceldtmf, cmd)) {
         /* need this flag here to distinguish between pressing '0' during message recording or after */
            canceleddtmf = 1;
         }
         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
         if (cmd == -1) {
            /* User has hung up, no options to give */
            if (!outsidecaller) {
               /* user was recording a greeting and they hung up, so let's delete the recording. */
               ast_filedelete(tempfile, NULL);
            }     
            return cmd;
         }
         if (cmd == '0') {
            break;
         } else if (cmd == '*') {
            break;
#if 0
         } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
            /* Message is too short */
            ast_verb(3, "Message too short\n");
            cmd = ast_play_and_wait(chan, "vm-tooshort");
            cmd = ast_filedelete(tempfile, NULL);
            break;
         } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
            /* Message is all silence */
            ast_verb(3, "Nothing recorded\n");
            cmd = ast_filedelete(tempfile, NULL);
            cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
            if (!cmd)
               cmd = ast_play_and_wait(chan, "vm-speakup");
            break;
#endif
         } else {
            /* If all is well, a message exists */
            msg_exists = 1;
            cmd = 0;
         }
         break;
      case '4':
         if (outsidecaller) {  /* only mark vm messages */
            /* Mark Urgent */
            if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
               ast_verb(3, "marking message as Urgent\n");
               res = ast_play_and_wait(chan, "vm-marked-urgent");
               strcpy(flag, "Urgent");
            } else if (flag) {
               ast_verb(3, "UNmarking message as Urgent\n");
               res = ast_play_and_wait(chan, "vm-marked-nonurgent");
               strcpy(flag, "");
            } else {
               ast_play_and_wait(chan, "vm-sorry");
            }
            cmd = 0;
         } else {
            cmd = ast_play_and_wait(chan, "vm-sorry");
         }
         break;
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '*':
      case '#':
         cmd = ast_play_and_wait(chan, "vm-sorry");
         break;
#if 0 
/*  XXX Commented out for the moment because of the dangers of deleting
    a message while recording (can put the message numbers out of sync) */
      case '*':
         /* Cancel recording, delete message, offer to take another message*/
         cmd = ast_play_and_wait(chan, "vm-deleted");
         cmd = ast_filedelete(tempfile, NULL);
         if (outsidecaller) {
            res = vm_exec(chan, NULL);
            return res;
         }
         else
            return 1;
#endif
      case '0':
         if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
            cmd = ast_play_and_wait(chan, "vm-sorry");
            break;
         }
         if (msg_exists || recorded) {
            cmd = ast_play_and_wait(chan, "vm-saveoper");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 3000);
            if (cmd == '1') {
               ast_filerename(tempfile, recordfile, NULL);
               ast_play_and_wait(chan, "vm-msgsaved");
               cmd = '0';
            } else if (cmd == '4') {
               if (flag) {
                  ast_play_and_wait(chan, "vm-marked-urgent");
                  strcpy(flag, "Urgent");
               }
               ast_play_and_wait(chan, "vm-msgsaved");
               cmd = '0';
            } else {
               ast_play_and_wait(chan, "vm-deleted");
               DELETE(tempfile, -1, tempfile, vmu);
               cmd = '0';
            }
         }
         return cmd;
      default:
         /* If the caller is an ouside caller, and the review option is enabled,
            allow them to review the message, but let the owner of the box review
            their OGM's */
         if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
            return cmd;
         if (msg_exists) {
            cmd = ast_play_and_wait(chan, "vm-review");
            if (!cmd && outsidecaller) {
               if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
                  cmd = ast_play_and_wait(chan, "vm-review-urgent");
               } else if (flag) {
                  cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
               }
            }
         } else {
            cmd = ast_play_and_wait(chan, "vm-torerecord");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 600);
         }
         
         if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
            cmd = ast_play_and_wait(chan, "vm-reachoper");
            if (!cmd)
               cmd = ast_waitfordigit(chan, 600);
         }
#if 0
         if (!cmd)
            cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
#endif
         if (!cmd)
            cmd = ast_waitfordigit(chan, 6000);
         if (!cmd) {
            attempts++;
         }
         if (attempts > max_attempts) {
            cmd = 't';
         }
      }
   }
   if (!outsidecaller && (cmd == -1 || cmd == 't')) {
      /* Hang up or timeout, so delete the recording. */
      ast_filedelete(tempfile, NULL);
   }

   if (cmd != 't' && outsidecaller)
      ast_play_and_wait(chan, "vm-goodbye");

   return cmd;
}
static void poll_subscribed_mailbox ( struct mwi_sub mwi_sub) [static]

Definition at line 12466 of file app_voicemail.c.

References inboxcount2(), queue_mwi_event(), and run_externnotify().

Referenced by handle_subscribe(), and poll_subscribed_mailboxes().

{
   int new = 0, old = 0, urgent = 0;

   inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);

   if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
      mwi_sub->old_urgent = urgent;
      mwi_sub->old_new = new;
      mwi_sub->old_old = old;
      queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
      run_externnotify(NULL, mwi_sub->mailbox, NULL);
   }
}
static void poll_subscribed_mailboxes ( void  ) [static]
static void populate_defaults ( struct ast_vm_user vmu) [static]

Sets default voicemail system options to a voicemail user.

This applies select global settings to a newly created (dynamic) instance of a voicemail user.

  • all the globalflags
  • the saydurationminfo
  • the callcontext
  • the dialcontext
  • the exitcontext
  • vmmaxsecs, vmmaxmsg, maxdeletedmsg
  • volume gain.
  • emailsubject, emailbody set to NULL

Definition at line 1166 of file app_voicemail.c.

References ast_copy_flags, ast_copy_string(), AST_FLAGS_ALL, ast_free, ast_vm_user::callback, ast_vm_user::dialout, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::exit, ast_vm_user::locale, ast_vm_user::maxdeletedmsg, maxdeletedmsg, ast_vm_user::maxmsg, maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, ast_vm_user::passwordlocation, passwordlocation, ast_vm_user::saydurationm, saydurationminfo, vmmaxsecs, vmminsecs, ast_vm_user::volgain, volgain, and ast_vm_user::zonetag.

Referenced by actual_load_config(), append_mailbox(), AST_TEST_DEFINE(), and find_user_realtime().

{
   ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
   vmu->passwordlocation = passwordlocation;
   if (saydurationminfo) {
      vmu->saydurationm = saydurationminfo;
   }
   ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
   ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
   ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
   ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
   ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
   if (vmminsecs) {
      vmu->minsecs = vmminsecs;
   }
   if (vmmaxsecs) {
      vmu->maxsecs = vmmaxsecs;
   }
   if (maxmsg) {
      vmu->maxmsg = maxmsg;
   }
   if (maxdeletedmsg) {
      vmu->maxdeletedmsg = maxdeletedmsg;
   }
   vmu->volgain = volgain;
   ast_free(vmu->emailsubject);
   vmu->emailsubject = NULL;
   ast_free(vmu->emailbody);
   vmu->emailbody = NULL;
#ifdef IMAP_STORAGE
   ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
   ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
   ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
   ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
#endif
}
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]

Definition at line 4656 of file app_voicemail.c.

References ast_callerid_merge(), ast_callerid_split(), ast_config_destroy(), ast_config_load, ast_debug, ast_localtime(), ast_strftime_locale(), ast_strlen_zero(), ast_variable_retrieve(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::fullname, ast_vm_user::locale, ast_vm_user::mailbox, make_dir(), make_file(), pbx_builtin_setvar_helper(), S_OR, and valid_config().

Referenced by make_email_file(), and sendpage().

{
   char callerid[256];
   char num[12];
   char fromdir[256], fromfile[256];
   struct ast_config *msg_cfg;
   const char *origcallerid, *origtime;
   char origcidname[80], origcidnum[80], origdate[80];
   int inttime;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };

   /* Prepare variables for substitution in email body and subject */
   pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
   pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
   snprintf(num, sizeof(num), "%d", msgnum);
   pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
   pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
   pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
   pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
      ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
   pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
   pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
   pbx_builtin_setvar_helper(ast, "VM_DATE", date);
   pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
   pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);

   /* Retrieve info from VM attribute file */
   make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
   make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
   if (strlen(fromfile) < sizeof(fromfile) - 5) {
      strcat(fromfile, ".txt");
   }
   if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
      ast_debug(1, "Config load for message text file '%s' failed\n", fromfile);
      return;
   }

   if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
      pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
      ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
      pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
      pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
   }

   if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
      struct timeval tv = { inttime, };
      struct ast_tm tm;
      ast_localtime(&tv, &tm, NULL);
      ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
      pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
   }
   ast_config_destroy(msg_cfg);
}
static void queue_mwi_event ( const char *  box,
int  urgent,
int  new,
int  old 
) [static]
static void read_password_from_file ( const char *  secretfn,
char *  password,
int  passwordlen 
) [static]

Definition at line 13579 of file app_voicemail.c.

References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log(), ast_variable_retrieve(), LOG_NOTICE, and valid_config().

Referenced by actual_load_config(), and append_mailbox().

                                                                                           {
   struct ast_config *pwconf;
   struct ast_flags config_flags = { 0 };

   pwconf = ast_config_load(secretfn, config_flags);
   if (valid_config(pwconf)) {
      const char *val = ast_variable_retrieve(pwconf, "general", "password");
      if (val) {
         ast_copy_string(password, val, passwordlen);
         ast_config_destroy(pwconf);
         return;
      }
      ast_config_destroy(pwconf);
   }
   ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
}
static int reload ( void  ) [static]

Definition at line 14194 of file app_voicemail.c.

References load_config().

{
   return load_config(1);
}
static void rename_file ( char *  sfn,
char *  dfn 
) [static]

Renames a message in a mailbox folder.

Parameters:
sfnThe path to the mailbox information and data file to be renamed.
dfnThe path for where the message data and information files will be renamed to.

This method is used by the RENAME macro when mailboxes are stored on the filesystem. (not ODBC and not IMAP).

Definition at line 4326 of file app_voicemail.c.

References ast_check_realtime(), ast_filerename(), ast_update_realtime(), and SENTINEL.

{
   char stxt[PATH_MAX];
   char dtxt[PATH_MAX];
   ast_filerename(sfn, dfn, NULL);
   snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
   snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
   if (ast_check_realtime("voicemail_data")) {
      ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
   }
   rename(stxt, dtxt);
}
static int resequence_mailbox ( struct ast_vm_user vmu,
char *  dir,
int  stopcount 
) [static]

Definition at line 6814 of file app_voicemail.c.

References ast_unlock_path(), ast_vm_user::context, ERROR_LOCK_PATH, EXISTS, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, RENAME, and vm_lock_path().

Referenced by open_mailbox().

{
   /* we know the actual number of messages, so stop process when number is hit */

   int x, dest;
   char sfn[PATH_MAX];
   char dfn[PATH_MAX];

   if (vm_lock_path(dir)) {
      return ERROR_LOCK_PATH;
   }

   for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
      make_file(sfn, sizeof(sfn), dir, x);
      if (EXISTS(dir, x, sfn, NULL)) {

         if (x != dest) {
            make_file(dfn, sizeof(dfn), dir, dest);
            RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
         }

         dest++;
      }
   }
   ast_unlock_path(dir);

   return dest;
}
static int reset_user_pw ( const char *  context,
const char *  mailbox,
const char *  newpass 
) [static]

Resets a user password to a specified password.

Parameters:
context
mailbox
newpassThis does the actual change password work, called by the vm_change_password() function.
Returns:
zero on success, -1 on error.

Definition at line 1661 of file app_voicemail.c.

References ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_vm_user::context, ast_vm_user::mailbox, and ast_vm_user::password.

Referenced by vm_change_password(), and vm_change_password_shell().

{
   /* This function could be made to generate one from a database, too */
   struct ast_vm_user *cur;
   int res = -1;
   AST_LIST_LOCK(&users);
   AST_LIST_TRAVERSE(&users, cur, list) {
      if ((!context || !strcasecmp(context, cur->context)) &&
         (!strcasecmp(mailbox, cur->mailbox)))
            break;
   }
   if (cur) {
      ast_copy_string(cur->password, newpass, sizeof(cur->password));
      res = 0;
   }
   AST_LIST_UNLOCK(&users);
   return res;
}
static void run_externnotify ( char *  context,
char *  extension,
const char *  flag 
) [static]

Definition at line 5883 of file app_voicemail.c.

References ast_app_has_voicemail(), ast_copy_string(), ast_debug, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, ast_safe_system(), ast_smdi_mwi_message_destroy(), ast_smdi_mwi_message_wait_station(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), ast_strlen_zero(), ASTOBJ_UNREF, ast_smdi_mwi_message::cause, ast_smdi_mwi_message::fwd_st, inboxcount2(), S_OR, and SMDI_MWI_WAIT_TIMEOUT.

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

{
   char arguments[255];
   char ext_context[256] = "";
   int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
   struct ast_smdi_mwi_message *mwi_msg;

   if (!ast_strlen_zero(context))
      snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
   else
      ast_copy_string(ext_context, extension, sizeof(ext_context));

   if (smdi_iface) {
      if (ast_app_has_voicemail(ext_context, NULL)) 
         ast_smdi_mwi_set(smdi_iface, extension);
      else
         ast_smdi_mwi_unset(smdi_iface, extension);

      if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
         ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
         if (!strncmp(mwi_msg->cause, "INV", 3))
            ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
         else if (!strncmp(mwi_msg->cause, "BLK", 3))
            ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
         ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
         ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
      } else {
         ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
      }
   }

   if (!ast_strlen_zero(externnotify)) {
      if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
         ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
      } else {
         snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
            externnotify, S_OR(context, "\"\""),
            extension, newvoicemails,
            oldvoicemails, urgentvoicemails);
         ast_debug(1, "Executing %s\n", arguments);
         ast_safe_system(arguments);
      }
   }
}
static int save_to_folder ( struct ast_vm_user vmu,
struct vm_state vms,
int  msg,
int  box,
int *  newmsg,
int  move 
) [static]

Place a message in the indicated folder

Parameters:
vmuVoicemail user
vmsCurrent voicemail state for the user
msgThe message number to save
boxThe folder into which the message should be saved
[out]newmsgThe new message number of the saved message
moveTells whether to copy or to move the message
Note:
the "move" parameter is only honored for IMAP voicemail presently
Return values:
0Success other Failure

Definition at line 6851 of file app_voicemail.c.

References ast_debug, ast_log(), AST_LOG_NOTICE, ast_mutex_lock, ast_mutex_unlock, ast_unlock_path(), ast_vm_user::context, COPY, create_dirpath(), vm_state::curbox, vm_state::curdir, ERROR_LOCK_PATH, EXISTS, last_message_index(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, mbox(), NEW_FOLDER, OLD_FOLDER, RENAME, vm_state::username, and vm_lock_path().

Referenced by close_mailbox(), vm_execmain(), and vm_msg_move().

{
#ifdef IMAP_STORAGE
   /* we must use mbox(x) folder names, and copy the message there */
   /* simple. huh? */
   char sequence[10];
   char mailbox[256];
   int res;

   /* get the real IMAP message number for this message */
   snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);

   ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
   ast_mutex_lock(&vms->lock);
   /* if save to Old folder, put in INBOX as read */
   if (box == OLD_FOLDER) {
      mail_setflag(vms->mailstream, sequence, "\\Seen");
      mail_clearflag(vms->mailstream, sequence, "\\Unseen");
   } else if (box == NEW_FOLDER) {
      mail_setflag(vms->mailstream, sequence, "\\Unseen");
      mail_clearflag(vms->mailstream, sequence, "\\Seen");
   }
   if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
      ast_mutex_unlock(&vms->lock);
      return 0;
   }
   /* Create the folder if it don't exist */
   imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */
   ast_debug(5, "Checking if folder exists: %s\n", mailbox);
   if (mail_create(vms->mailstream, mailbox) == NIL)
      ast_debug(5, "Folder exists.\n");
   else
      ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
   if (move) {
      res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box));
   } else {
      res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
   }
   ast_mutex_unlock(&vms->lock);
   return res;
#else
   char *dir = vms->curdir;
   char *username = vms->username;
   char *context = vmu->context;
   char sfn[PATH_MAX];
   char dfn[PATH_MAX];
   char ddir[PATH_MAX];
   const char *dbox = mbox(vmu, box);
   int x, i;
   create_dirpath(ddir, sizeof(ddir), context, username, dbox);

   if (vm_lock_path(ddir))
      return ERROR_LOCK_PATH;

   x = last_message_index(vmu, ddir) + 1;

   if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/
      x--;
      for (i = 1; i <= x; i++) {
         /* Push files down a "slot".  The oldest file (msg0000) will be deleted. */
         make_file(sfn, sizeof(sfn), ddir, i);
         make_file(dfn, sizeof(dfn), ddir, i - 1);
         if (EXISTS(ddir, i, sfn, NULL)) {
            RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
         } else
            break;
      }
   } else {
      if (x >= vmu->maxmsg) {
         ast_unlock_path(ddir);
         return -1;
      }
   }
   make_file(sfn, sizeof(sfn), dir, msg);
   make_file(dfn, sizeof(dfn), ddir, x);
   if (strcmp(sfn, dfn)) {
      COPY(dir, msg, ddir, x, username, context, sfn, dfn);
   }
   ast_unlock_path(ddir);

   if (newmsg) {
      *newmsg = x;
   }
   return 0;
#endif
}
static int say_and_wait ( struct ast_channel chan,
int  num,
const char *  language 
) [static]
static int sayname ( struct ast_channel chan,
const char *  mailbox,
const char *  context 
) [static]

Definition at line 13565 of file app_voicemail.c.

References ast_debug, AST_DIGIT_ANY, ast_fileexists(), ast_stream_and_wait(), DISPOSE, and RETRIEVE.

Referenced by load_module(), and vmsayname_exec().

{
   int res = -1;
   char dir[PATH_MAX];
   snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
   ast_debug(2, "About to try retrieving name file %s\n", dir);
   RETRIEVE(dir, -1, mailbox, context);
   if (ast_fileexists(dir, NULL, NULL)) {
      res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
   }
   DISPOSE(dir, -1);
   return res;
}
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,
const char *  msg_id 
) [static]

Definition at line 5188 of file app_voicemail.c.

References ast_debug, ast_log(), AST_LOG_WARNING, ast_safe_system(), ast_strlen_zero(), ast_test_flag, ast_vm_user::email, format, ast_vm_user::mailbox, make_email_file(), VM_ATTACH, and vm_mkftemp().

Referenced by forward_message(), and notify_new_message().

{
   FILE *p = NULL;
   char tmp[80] = "/tmp/astmail-XXXXXX";
   char tmp2[256];
   char *stringp;

   if (vmu && ast_strlen_zero(vmu->email)) {
      ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s].  E-mail will not be sent.\n", vmu->mailbox);
      return(0);
   }

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

   if (!strcmp(format, "wav49"))
      format = "WAV";
   ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
   /* Make a temporary file instead of piping directly to sendmail, in case the mail
      command hangs */
   if ((p = vm_mkftemp(tmp)) == NULL) {
      ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
      return -1;
   } else {
      make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag, msg_id);
      fclose(p);
      snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
      ast_safe_system(tmp2);
      ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
   }
   return 0;
}
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]

Definition at line 5239 of file app_voicemail.c.

References ast_channel_unref, ast_copy_string(), ast_debug, ast_dummy_channel_alloc(), ast_free, ast_log(), AST_LOG_WARNING, ast_safe_system(), ast_str_buffer(), ast_str_create(), ast_str_encode_mime(), ast_str_quote(), ast_str_set(), ast_str_substitute_variables(), ast_strftime(), ast_strftime_locale(), ast_strlen_zero(), check_mime(), ENDL, ast_vm_user::fullname, ast_vm_user::locale, prep_email_sub_vars(), S_OR, strip_control_and_high(), vm_mkftemp(), and vmu_tm().

Referenced by notify_new_message().

{
   char enc_cidnum[256], enc_cidname[256];
   char date[256];
   char host[MAXHOSTNAMELEN] = "";
   char who[256];
   char dur[PATH_MAX];
   char tmp[80] = "/tmp/astmail-XXXXXX";
   char tmp2[PATH_MAX];
   struct ast_tm tm;
   FILE *p;
   struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);

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

   if (cidnum) {
      strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
   }
   if (cidname) {
      strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
   }

   if ((p = vm_mkftemp(tmp)) == NULL) {
      ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
      ast_free(str1);
      ast_free(str2);
      return -1;
   }
   gethostname(host, sizeof(host)-1);
   if (strchr(srcemail, '@')) {
      ast_copy_string(who, srcemail, sizeof(who));
   } else {
      snprintf(who, sizeof(who), "%s@%s", srcemail, host);
   }
   snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
   ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
   fprintf(p, "Date: %s\n", date);

   /* Reformat for custom pager format */
   ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));

   if (!ast_strlen_zero(pagerfromstring)) {
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         char *ptr;
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);

         if (check_mime(ast_str_buffer(str1))) {
            int first_line = 1;
            ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
            while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
               *ptr = '\0';
               fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
               first_line = 0;
               /* Substring is smaller, so this will never grow */
               ast_str_set(&str2, 0, "%s", ptr + 1);
            }
            fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
         } else {
            fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
         }
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else {
      fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
   }

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

   if (!ast_strlen_zero(pagersubject)) {
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, pagersubject);
         if (check_mime(ast_str_buffer(str1))) {
            int first_line = 1;
            char *ptr;
            ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
            while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
               *ptr = '\0';
               fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
               first_line = 0;
               /* Substring is smaller, so this will never grow */
               ast_str_set(&str2, 0, "%s", ptr + 1);
            }
            fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
         } else {
            fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
         }
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else {
      if (ast_strlen_zero(flag)) {
         fprintf(p, "Subject: New VM\n\n");
      } else {
         fprintf(p, "Subject: New %s VM\n\n", flag);
      }
   }

   if (pagerbody) {
      struct ast_channel *ast;
      if ((ast = ast_dummy_channel_alloc())) {
         prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
         ast_str_substitute_variables(&str1, 0, ast, pagerbody);
         fprintf(p, "%s" ENDL, ast_str_buffer(str1));
         ast = ast_channel_unref(ast);
      } else {
         ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
      }
   } else {
      fprintf(p, "New %s long %s msg in box %s\n"
            "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
   }

   fclose(p);
   snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
   ast_safe_system(tmp2);
   ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
   ast_free(str1);
   ast_free(str2);
   return 0;
}
static char* show_users_realtime ( int  fd,
const char *  context 
) [static]

Definition at line 12123 of file app_voicemail.c.

References ast_category_browse(), ast_cli(), ast_config_destroy(), ast_load_realtime_multientry(), ast_variable_browse(), CLI_FAILURE, CLI_SUCCESS, ast_variable::name, ast_variable::next, SENTINEL, ast_variable::value, and var.

Referenced by handle_voicemail_show_users().

{
   struct ast_config *cfg;
   const char *cat = NULL;

   if (!(cfg = ast_load_realtime_multientry("voicemail", 
      "context", context, SENTINEL))) {
      return CLI_FAILURE;
   }

   ast_cli(fd,
      "\n"
      "=============================================================\n"
      "=== Configured Voicemail Users ==============================\n"
      "=============================================================\n"
      "===\n");

   while ((cat = ast_category_browse(cfg, cat))) {
      struct ast_variable *var = NULL;
      ast_cli(fd,
         "=== Mailbox ...\n"
         "===\n");
      for (var = ast_variable_browse(cfg, cat); var; var = var->next)
         ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
      ast_cli(fd,
         "===\n"
         "=== ---------------------------------------------------------\n"
         "===\n");
   }

   ast_cli(fd,
      "=============================================================\n"
      "\n");

   ast_config_destroy(cfg);

   return CLI_SUCCESS;
}
static char* strip_control_and_high ( const char *  input,
char *  buf,
size_t  buflen 
) [static]

Strips control and non 7-bit clean characters from input string.

Note:
To map control and none 7-bit characters to a 7-bit clean characters please use ast_str_encode_mine().

Definition at line 1136 of file app_voicemail.c.

References input().

Referenced by make_email_file(), and sendpage().

{
   char *bufptr = buf;
   for (; *input; input++) {
      if (*input < 32) {
         continue;
      }
      *bufptr++ = *input;
      if (bufptr == buf + buflen - 1) {
         break;
      }
   }
   *bufptr = '\0';
   return buf;
}
static const char * substitute_escapes ( const char *  value) [static]

Definition at line 12802 of file app_voicemail.c.

References ast_log(), AST_LOG_NOTICE, ast_str_append(), ast_str_buffer(), ast_str_reset(), and ast_str_thread_get().

Referenced by actual_load_config(), apply_option(), and apply_options_full().

{
   char *current;

   /* Add 16 for fudge factor */
   struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);

   ast_str_reset(str);
   
   /* Substitute strings \r, \n, and \t into the appropriate characters */
   for (current = (char *) value; *current; current++) {
      if (*current == '\\') {
         current++;
         if (!*current) {
            ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
            break;
         }
         switch (*current) {
         case '\\':
            ast_str_append(&str, 0, "\\");
            break;
         case 'r':
            ast_str_append(&str, 0, "\r");
            break;
         case 'n':
#ifdef IMAP_STORAGE
            if (!str->used || str->str[str->used - 1] != '\r') {
               ast_str_append(&str, 0, "\r");
            }
#endif
            ast_str_append(&str, 0, "\n");
            break;
         case 't':
            ast_str_append(&str, 0, "\t");
            break;
         default:
            ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
            break;
         }
      } else {
         ast_str_append(&str, 0, "%c", *current);
      }
   }

   return ast_str_buffer(str);
}
static int unload_module ( void  ) [static]

Definition at line 14199 of file app_voicemail.c.

References ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_manager_unregister(), AST_PTHREADT_NULL, ast_taskprocessor_unreference(), AST_TEST_UNREGISTER, ast_uninstall_vm_functions(), ast_unload_realtime(), ast_unregister_application(), free_vm_users(), free_vm_zones(), and stop_poll_thread().

{
   int res;

   res = ast_unregister_application(app);
   res |= ast_unregister_application(app2);
   res |= ast_unregister_application(app3);
   res |= ast_unregister_application(app4);
   res |= ast_unregister_application(playmsg_app);
   res |= ast_unregister_application(sayname_app);
   res |= ast_custom_function_unregister(&mailbox_exists_acf);
   res |= ast_custom_function_unregister(&vm_info_acf);
   res |= ast_manager_unregister("VoicemailUsersList");
   res |= ast_data_unregister(NULL);
#ifdef TEST_FRAMEWORK
   res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
   res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
   res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
   res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
   res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
   res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
#endif
   ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
   ast_uninstall_vm_functions();
#ifdef TEST_FRAMEWORK
   ast_uninstall_vm_test_functions();
#endif
   ao2_ref(inprocess_container, -1);

   if (poll_thread != AST_PTHREADT_NULL)
      stop_poll_thread();

   mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
   ast_unload_realtime("voicemail");
   ast_unload_realtime("voicemail_data");

   free_vm_users();
   free_vm_zones();
   return res;
}
static int valid_config ( const struct ast_config cfg) [inline, static]

Check if configuration file is valid.

Definition at line 1683 of file app_voicemail.c.

References CONFIG_STATUS_FILEINVALID.

Referenced by advanced_options(), make_email_file(), play_message(), prep_email_sub_vars(), read_password_from_file(), vm_change_password(), and vm_forwardoptions().

{
   return cfg && cfg != CONFIG_STATUS_FILEINVALID;
}
static int vm_allocate_dh ( struct vm_state vms,
struct ast_vm_user vmu,
int  count_msg 
) [static]

Definition at line 1931 of file app_voicemail.c.

References ast_calloc, ast_free, vm_state::deleted, vm_state::dh_arraysize, vm_state::heard, and ast_vm_user::maxmsg.

Referenced by open_mailbox().

                                                                                        {

   int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);

   /* remove old allocation */
   if (vms->deleted) {
      ast_free(vms->deleted);
      vms->deleted = NULL;
   }
   if (vms->heard) {
      ast_free(vms->heard);
      vms->heard = NULL;
   }
   vms->dh_arraysize = 0;

   if (arraysize > 0) {
      if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
         return -1;
      }
      if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
         ast_free(vms->deleted);
         vms->deleted = NULL;
         return -1;
      }
      vms->dh_arraysize = arraysize;
   }

   return 0;
}
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]

Definition at line 10524 of file app_voicemail.c.

References adsi_begin(), adsi_login(), adsi_password(), ast_channel_caller(), ast_channel_context(), ast_channel_language(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_log(), AST_LOG_WARNING, AST_MAX_EXTENSION, ast_play_and_wait(), ast_readstring(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_test_suite_event_notify, ast_verb, ast_waitstream(), find_user(), ast_vm_user::password, and S_COR.

Referenced by vm_execmain(), and vmauthenticate().

{
   int useadsi = 0, valid = 0, logretries = 0;
   char password[AST_MAX_EXTENSION]="", *passptr;
   struct ast_vm_user vmus, *vmu = NULL;

   /* If ADSI is supported, setup login screen */
   adsi_begin(chan, &useadsi);
   if (!skipuser && useadsi)
      adsi_login(chan);
   ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
   if (!silent && !skipuser && ast_streamfile(chan, "vm-login", ast_channel_language(chan))) {
      ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
      return -1;
   }

   /* Authenticate them and get their mailbox/password */

   while (!valid && (logretries < max_logins)) {
      /* Prompt for, and read in the username */
      if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
         ast_log(AST_LOG_WARNING, "Couldn't read username\n");
         return -1;
      }
      if (ast_strlen_zero(mailbox)) {
         if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
            ast_copy_string(mailbox, ast_channel_caller(chan)->id.number.str, mailbox_size);
         } else {
            ast_verb(3, "Username not entered\n"); 
            return -1;
         }
      } else if (mailbox[0] == '*') {
         /* user entered '*' */
         ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
         if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
            S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
            return -1;
         }
         ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
         mailbox[0] = '\0';
      }

      if (useadsi)
         adsi_password(chan);

      if (!ast_strlen_zero(prefix)) {
         char fullusername[80] = "";
         ast_copy_string(fullusername, prefix, sizeof(fullusername));
         strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
         ast_copy_string(mailbox, fullusername, mailbox_size);
      }

      ast_debug(1, "Before find user for mailbox %s\n", mailbox);
      vmu = find_user(&vmus, context, mailbox);
      if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
         /* saved password is blank, so don't bother asking */
         password[0] = '\0';
      } else {
         ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
         if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
            ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
            return -1;
         }
         if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
            ast_log(AST_LOG_WARNING, "Unable to read password\n");
            return -1;
         } else if (password[0] == '*') {
            /* user entered '*' */
            ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
            if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
               mailbox[0] = '*';
               return -1;
            }
            ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
            mailbox[0] = '\0';
            /* if the password entered was '*', do not let a user mailbox be created if the extension 'a' is not defined */
            vmu = NULL;
         }
      }

      if (vmu) {
         passptr = vmu->password;
         if (passptr[0] == '-') passptr++;
      }
      if (vmu && !strcmp(passptr, password))
         valid++;
      else {
         ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
         if (!ast_strlen_zero(prefix))
            mailbox[0] = '\0';
      }
      logretries++;
      if (!valid) {
         if (skipuser || logretries >= max_logins) {
            ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
            if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) {
               ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
               return -1;
            }
         } else {
            ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
            if (useadsi)
               adsi_login(chan);
            if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) {
               ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
               return -1;
            }
         }
         if (ast_waitstream(chan, "")) /* Channel is hung up */
            return -1;
      }
   }
   if (!valid && (logretries >= max_logins)) {
      ast_stopstream(chan);
      ast_play_and_wait(chan, "vm-goodbye");
      return -1;
   }
   if (vmu && !skipuser) {
      memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
   }
   return 0;
}
static int vm_box_exists ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 11930 of file app_voicemail.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, AST_STANDARD_APP_ARGS, ast_strlen_zero(), context, find_user(), mbox(), and pbx_builtin_setvar_helper().

Referenced by load_module().

{
   struct ast_vm_user svm;
   char *context, *box;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(mbox);
      AST_APP_ARG(options);
   );
   static int dep_warning = 0;

   if (ast_strlen_zero(data)) {
      ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
      return -1;
   }

   if (!dep_warning) {
      dep_warning = 1;
      ast_log(AST_LOG_WARNING, "MailboxExists is deprecated.  Please use ${VM_INFO(%s,exists)} instead.\n", data);
   }

   box = ast_strdupa(data);

   AST_STANDARD_APP_ARGS(args, box);

   if (args.options) {
   }

   if ((context = strchr(args.mbox, '@'))) {
      *context = '\0';
      context++;
   }

   if (find_user(&svm, context, args.mbox)) {
      pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
   } else
      pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");

   return 0;
}
static int vm_browse_messages ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Top level method to invoke the language variant vm_browse_messages_XX function.

Parameters:
chanThe channel for the current user. We read the language property from this.
vmspassed into the language-specific vm_browse_messages function.
vmupassed into the language-specific vm_browse_messages function.

The method to be invoked is determined by the value of language code property in the user's channel. The default (when unable to match) is to use english.

Returns:
zero on success, -1 on error.

Definition at line 10503 of file app_voicemail.c.

References ast_channel_language(), vm_browse_messages_en(), vm_browse_messages_es(), vm_browse_messages_gr(), vm_browse_messages_he(), vm_browse_messages_it(), vm_browse_messages_pt(), vm_browse_messages_vi(), and vm_browse_messages_zh().

Referenced by vm_execmain().

{
   if (!strncasecmp(ast_channel_language(chan), "es", 2)) {         /* SPANISH */
      return vm_browse_messages_es(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {  /* GREEK */
      return vm_browse_messages_gr(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {  /* HEBREW */
      return vm_browse_messages_he(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {  /* ITALIAN */
      return vm_browse_messages_it(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {  /* PORTUGUESE */
      return vm_browse_messages_pt(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {  /* VIETNAMESE */
      return vm_browse_messages_vi(chan, vms, vmu);
   } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {  /* CHINESE (Taiwan) */
      return vm_browse_messages_zh(chan, vms, vmu);
   } else {                                             /* Default to English syntax */
      return vm_browse_messages_en(chan, vms, vmu);
   }
}
static int vm_browse_messages_en ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Default English syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10342 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd = 0;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-youhave");
      if (!cmd) 
         cmd = ast_play_and_wait(chan, "vm-no");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
      if (!cmd)
         cmd = ast_play_and_wait(chan, "vm-messages");
   }
   return cmd;
}
static int vm_browse_messages_es ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Spanish syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10396 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-youhaveno");
      if (!cmd)
         cmd = ast_play_and_wait(chan, "vm-messages");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
   }
   return cmd;
}
static int vm_browse_messages_gr ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Greek syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10290 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, play_message(), and vm_state::vmbox.

Referenced by vm_browse_messages().

{
   int cmd = 0;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-youhaveno");
      if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
         if (!cmd) {
            snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
            cmd = ast_play_and_wait(chan, vms->fn);
         }
         if (!cmd)
            cmd = ast_play_and_wait(chan, "vm-messages");
      } else {
         if (!cmd)
            cmd = ast_play_and_wait(chan, "vm-messages");
         if (!cmd) {
            snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
            cmd = ast_play_and_wait(chan, vms->fn);
         }
      }
   } 
   return cmd;
}
static int vm_browse_messages_he ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Definition at line 10318 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd = 0;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      if (!strcasecmp(vms->fn, "INBOX")) {
         cmd = ast_play_and_wait(chan, "vm-nonewmessages");
      } else {
         cmd = ast_play_and_wait(chan, "vm-nomessages");
      }
   }
   return cmd;
}
static int vm_browse_messages_it ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Italian syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10370 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-no");
      if (!cmd)
         cmd = ast_play_and_wait(chan, "vm-message");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
   }
   return cmd;
}
static int vm_browse_messages_pt ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Portuguese syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10422 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-no");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
      if (!cmd)
         cmd = ast_play_and_wait(chan, "vm-messages");
   }
   return cmd;
}
static int vm_browse_messages_vi ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Vietnamese syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10476 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd = 0;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-no");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
   }
   return cmd;
}
static int vm_browse_messages_zh ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
) [static]

Chinese (Taiwan)syntax for 'You have N messages' greeting.

Parameters:
chan
vms
vmu
Returns:
zero on success, -1 on error.

Definition at line 10448 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::curbox, vm_state::fn, vm_state::lastmsg, and play_message().

Referenced by vm_browse_messages().

{
   int cmd;

   if (vms->lastmsg > -1) {
      cmd = play_message(chan, vmu, vms);
   } else {
      cmd = ast_play_and_wait(chan, "vm-you");
      if (!cmd) 
         cmd = ast_play_and_wait(chan, "vm-haveno");
      if (!cmd)
         cmd = ast_play_and_wait(chan, "vm-messages");
      if (!cmd) {
         snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
         cmd = ast_play_and_wait(chan, vms->fn);
      }
   }
   return cmd;
}
static void vm_change_password ( struct ast_vm_user vmu,
const char *  newpassword 
) [static]

The handler for the change password option.

Parameters:
vmuThe voicemail user to work with.
newpasswordThe new password (that has been gathered from the appropriate prompting). This is called when a new user logs in for the first time and the option to force them to change their password is set. It is also called when the user wants to change their password from menu option '5' on the mailbox options menu.

Definition at line 1695 of file app_voicemail.c.

References ast_alloca, ast_category_browse(), ast_category_get(), ast_config_destroy(), ast_config_load, ast_config_text_file_save(), ast_copy_string(), ast_debug, ast_free, ast_log(), AST_LOG_WARNING, ast_test_suite_event_notify, ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), ast_variable_update(), ast_verb, change_password_realtime(), CONFIG_FLAG_WITHCOMMENTS, ast_vm_user::context, ast_vm_user::mailbox, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_USERSCONF, OPT_PWLOC_VOICEMAILCONF, ast_vm_user::password, ast_vm_user::passwordlocation, reset_user_pw(), valid_config(), value, var, VOICEMAIL_CONFIG, and write_password_to_file().

Referenced by vm_newuser(), and vm_options().

{
   struct ast_config   *cfg = NULL;
   struct ast_variable *var = NULL;
   struct ast_category *cat = NULL;
   char *category = NULL, *value = NULL, *new = NULL;
   const char *tmp = NULL;
   struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
   char secretfn[PATH_MAX] = "";
   int found = 0;

   if (!change_password_realtime(vmu, newpassword))
      return;

   /* check if we should store the secret in the spool directory next to the messages */
   switch (vmu->passwordlocation) {
   case OPT_PWLOC_SPOOLDIR:
      snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
      if (write_password_to_file(secretfn, newpassword) == 0) {
         ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
         ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
         reset_user_pw(vmu->context, vmu->mailbox, newpassword);
         ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
         break;
      } else {
         ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
      }
      /* Fall-through */
   case OPT_PWLOC_VOICEMAILCONF:
      if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
         while ((category = ast_category_browse(cfg, category))) {
            if (!strcasecmp(category, vmu->context)) {
               if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
                  ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
                  break;
               }
               value = strstr(tmp, ",");
               if (!value) {
                  new = ast_alloca(strlen(newpassword)+1);
                  sprintf(new, "%s", newpassword);
               } else {
                  new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
                  sprintf(new, "%s%s", newpassword, value);
               }
               if (!(cat = ast_category_get(cfg, category))) {
                  ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
                  break;
               }
               ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
               found = 1;
            }
         }
         /* save the results */
         if (found) {
            ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
            reset_user_pw(vmu->context, vmu->mailbox, newpassword);
            ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
            ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
            ast_config_destroy(cfg);
            break;
         }

         ast_config_destroy(cfg);
      }
      /* Fall-through */
   case OPT_PWLOC_USERSCONF:
      /* check users.conf and update the password stored for the mailbox */
      /* if no vmsecret entry exists create one. */
      if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
         ast_debug(4, "we are looking for %s\n", vmu->mailbox);
         for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
            ast_debug(4, "users.conf: %s\n", category);
            if (!strcasecmp(category, vmu->mailbox)) {
               if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
                  ast_debug(3, "looks like we need to make vmsecret!\n");
                  var = ast_variable_new("vmsecret", newpassword, "");
               } else {
                  var = NULL;
               }
               new = ast_alloca(strlen(newpassword) + 1);
               sprintf(new, "%s", newpassword);
               if (!(cat = ast_category_get(cfg, category))) {
                  ast_debug(4, "failed to get category!\n");
                  ast_free(var);
                  break;
               }
               if (!var) {
                  ast_variable_update(cat, "vmsecret", new, NULL, 0);
               } else {
                  ast_variable_append(cat, var);
               }
               found = 1;
               break;
            }
         }
         /* save the results and clean things up */
         if (found) {
            ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
            reset_user_pw(vmu->context, vmu->mailbox, newpassword);
            ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
            ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
         }

         ast_config_destroy(cfg);
      }
   }
}
static void vm_change_password_shell ( struct ast_vm_user vmu,
char *  newpassword 
) [static]

Definition at line 1803 of file app_voicemail.c.

References ast_copy_string(), ast_debug, ast_safe_system(), ast_test_suite_event_notify, ast_vm_user::context, ast_vm_user::mailbox, ast_vm_user::password, and reset_user_pw().

Referenced by vm_newuser(), and vm_options().

{
   char buf[255];
   snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
   ast_debug(1, "External password: %s\n",buf);
   if (!ast_safe_system(buf)) {
      ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
      ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
      /* Reset the password in memory, too */
      reset_user_pw(vmu->context, vmu->mailbox, newpassword);
   }
}
static char* vm_check_password_shell ( char *  command,
char *  buf,
size_t  len 
) [static]

Definition at line 1348 of file app_voicemail.c.

References AST_APP_ARG, ast_close_fds_above_n(), AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_safe_fork(), errno, and LOG_WARNING.

Referenced by check_password().

{
   int fds[2], pid = 0;

   memset(buf, 0, len);

   if (pipe(fds)) {
      snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
   } else {
      /* good to go*/
      pid = ast_safe_fork(0);

      if (pid < 0) {
         /* ok maybe not */
         close(fds[0]);
         close(fds[1]);
         snprintf(buf, len, "FAILURE: Fork failed");
      } else if (pid) {
         /* parent */
         close(fds[1]);
         if (read(fds[0], buf, len) < 0) {
            ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
         }
         close(fds[0]);
      } else {
         /*  child */
         AST_DECLARE_APP_ARGS(arg,
            AST_APP_ARG(v)[20];
         );
         char *mycmd = ast_strdupa(command);

         close(fds[0]);
         dup2(fds[1], STDOUT_FILENO);
         close(fds[1]);
         ast_close_fds_above_n(STDOUT_FILENO);

         AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');

         execv(arg.v[0], arg.v); 
         printf("FAILURE: %s", strerror(errno));
         _exit(0);
      }
   }
   return buf;
}
static int vm_delete ( char *  file) [static]

Removes the voicemail sound and information file.

Parameters:
fileThe path to the sound file. This will be the the folder and message index, without the extension.

This is used by the DELETE macro when voicemails are stored on the file system.

Returns:
zero on success, -1 on error.

Definition at line 4510 of file app_voicemail.c.

References ast_alloca, ast_check_realtime(), ast_destroy_realtime(), ast_filedelete(), and SENTINEL.

Referenced by copy_message(), and notify_new_message().

{
   char *txt;
   int txtsize = 0;

   txtsize = (strlen(file) + 5)*sizeof(char);
   txt = ast_alloca(txtsize);
   /* Sprintf here would safe because we alloca'd exactly the right length,
    * but trying to eliminate all sprintf's anyhow
    */
   if (ast_check_realtime("voicemail_data")) {
      ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
   }
   snprintf(txt, txtsize, "%s.txt", file);
   unlink(txt);
   return ast_filedelete(file, NULL);
}
static int vm_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 11548 of file app_voicemail.c.

References args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_copy_flags, AST_DECLARE_APP_ARGS, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, ast_play_and_wait(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, ERROR_LOCK_PATH, leave_vm_options::exitcontext, leave_voicemail(), OPERATOR_EXIT, OPT_ARG_ARRAY_SIZE, OPT_ARG_DTMFEXIT, OPT_ARG_RECORDGAIN, OPT_BUSY_GREETING, OPT_DTMFEXIT, OPT_MESSAGE_PRIORITY, OPT_MESSAGE_Urgent, OPT_RECORDGAIN, OPT_SILENT, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), leave_vm_options::record_gain, and vm_app_options.

Referenced by load_module(), and play_record_review().

{
   int res = 0;
   char *tmp;
   struct leave_vm_options leave_options;
   struct ast_flags flags = { 0 };
   char *opts[OPT_ARG_ARRAY_SIZE];
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(argv0);
      AST_APP_ARG(argv1);
   );
   
   memset(&leave_options, 0, sizeof(leave_options));

   if (ast_channel_state(chan) != AST_STATE_UP)
      ast_answer(chan);

   if (!ast_strlen_zero(data)) {
      tmp = ast_strdupa(data);
      AST_STANDARD_APP_ARGS(args, tmp);
      if (args.argc == 2) {
         if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
            return -1;
         ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
         if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
            int gain;

            if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
               ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
               return -1;
            } else {
               leave_options.record_gain = (signed char) gain;
            }
         }
         if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
            if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
               leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
         }
      }
   } else {
      char temp[256];
      res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
      if (res < 0)
         return res;
      if (ast_strlen_zero(temp))
         return 0;
      args.argv0 = ast_strdupa(temp);
   }

   res = leave_voicemail(chan, args.argv0, &leave_options);
   if (res == 't') {
      ast_play_and_wait(chan, "vm-goodbye");
      res = 0;
   }

   if (res == OPERATOR_EXIT) {
      res = 0;
   }

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

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

Definition at line 10791 of file app_voicemail.c.

References adsi_begin(), adsi_delete(), adsi_folders(), adsi_goodbye(), adsi_message(), adsi_status(), adsi_status2(), advanced_options(), args, ast_adsi_unload_session(), ast_answer(), AST_APP_ARG, ast_app_inboxcount2(), ast_app_parse_options(), ast_channel_context(), ast_channel_language(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_LOG_WARNING, ast_manager_event, ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strlen_zero(), ast_test_flag, ast_test_suite_assert, ast_test_suite_event_notify, ast_verb, ast_waitfordigit(), ast_vm_user::callback, close_mailbox(), ast_vm_user::context, vm_state::context, vm_state::curdir, vm_state::curmsg, vm_state::deleted, ast_vm_user::dialout, dialout(), ERROR_LOCK_PATH, EVENT_FLAG_CALL, find_user(), vm_state::fn, forward_message(), free_user(), get_folder2(), get_folder_by_name(), has_voicemail(), vm_state::heard, ast_vm_user::language, vm_state::lastmsg, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, mbox(), NEW_FOLDER, vm_state::newmessages, OLD_FOLDER, vm_state::oldmessages, open_mailbox(), OPERATOR_EXIT, OPT_ARG_ARRAY_SIZE, OPT_ARG_PLAYFOLDER, OPT_ARG_RECORDGAIN, OPT_AUTOPLAY, OPT_PREPEND_MAILBOX, OPT_RECORDGAIN, OPT_SILENT, parse(), ast_vm_user::password, play_message(), queue_mwi_event(), vm_state::repeats, run_externnotify(), save_to_folder(), say_and_wait(), vm_state::starting, vm_state::urgentmessages, vm_state::username, vm_app_options, vm_authenticate(), vm_browse_messages(), VM_FORCEGREET, VM_FORCENAME, vm_instructions(), vm_intro(), VM_MESSAGEWRAP, vm_newuser(), vm_options(), vm_play_folder_name(), VM_SKIPAFTERCMD, VM_SVMAIL, and vm_state::vmbox.

Referenced by load_module().

{
   /* XXX This is, admittedly, some pretty horrendous code.  For some
      reason it just seemed a lot easier to do with GOTO's.  I feel
      like I'm back in my GWBASIC days. XXX */
   int res = -1;
   int cmd = 0;
   int valid = 0;
   char prefixstr[80] ="";
   char ext_context[256]="";
   int box;
   int useadsi = 0;
   int skipuser = 0;
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   char *context = NULL;
   int silentexit = 0;
   struct ast_flags flags = { 0 };
   signed char record_gain = 0;
   int play_auto = 0;
   int play_folder = 0;
   int in_urgent = 0;
#ifdef IMAP_STORAGE
   int deleted = 0;
#endif

   /* Add the vm_state to the active list and keep it active */
   memset(&vms, 0, sizeof(vms));

   vms.lastmsg = -1;

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

   ast_test_suite_event_notify("START", "Message: vm_execmain started");
   if (ast_channel_state(chan) != AST_STATE_UP) {
      ast_debug(1, "Before ast_answer\n");
      ast_answer(chan);
   }

   if (!ast_strlen_zero(data)) {
      char *opts[OPT_ARG_ARRAY_SIZE];
      char *parse;
      AST_DECLARE_APP_ARGS(args,
         AST_APP_ARG(argv0);
         AST_APP_ARG(argv1);
      );

      parse = ast_strdupa(data);

      AST_STANDARD_APP_ARGS(args, parse);

      if (args.argc == 2) {
         if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
            return -1;
         if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
            int gain;
            if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
               if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
                  ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
                  return -1;
               } else {
                  record_gain = (signed char) gain;
               }
            } else {
               ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
            }
         }
         if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
            play_auto = 1;
            if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
               /* See if it is a folder name first */
               if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
                  if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
                     play_folder = -1;
                  }
               } else {
                  play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
               }
            } else {
               ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
            }
            if (play_folder > 9 || play_folder < 0) {
               ast_log(AST_LOG_WARNING,
                  "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
                  opts[OPT_ARG_PLAYFOLDER]);
               play_folder = 0;
            }
         }
      } else {
         /* old style options parsing */
         while (*(args.argv0)) {
            if (*(args.argv0) == 's')
               ast_set_flag(&flags, OPT_SILENT);
            else if (*(args.argv0) == 'p')
               ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
            else 
               break;
            (args.argv0)++;
         }

      }

      valid = ast_test_flag(&flags, OPT_SILENT);

      if ((context = strchr(args.argv0, '@')))
         *context++ = '\0';

      if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
         ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
      else
         ast_copy_string(vms.username, args.argv0, sizeof(vms.username));

      if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
         skipuser++;
      else
         valid = 0;
   }

   if (!valid)
      res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);

   ast_debug(1, "After vm_authenticate\n");

   if (vms.username[0] == '*') {
      ast_debug(1, "user pressed * in context '%s'\n", ast_channel_context(chan));

      /* user entered '*' */
      if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
         ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
         res = 0; /* prevent hangup */
         goto out;
      }
   }

   if (!res) {
      valid = 1;
      if (!skipuser)
         vmu = &vmus;
   } else {
      res = 0;
   }

   /* If ADSI is supported, setup login screen */
   adsi_begin(chan, &useadsi);

   ast_test_suite_assert(valid);
   if (!valid) {
      goto out;
   }
   ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");

#ifdef IMAP_STORAGE
   pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
   pthread_setspecific(ts_vmstate.key, &vms);

   vms.interactive = 1;
   vms.updated = 1;
   if (vmu)
      ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
   vmstate_insert(&vms);
   init_vm_state(&vms);
#endif

   /* Set language from config to override channel language */
   if (!ast_strlen_zero(vmu->language))
      ast_channel_language_set(chan, vmu->language);

   /* Retrieve urgent, old and new message counts */
   ast_debug(1, "Before open_mailbox\n");
   res = open_mailbox(&vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
   if (res < 0)
      goto out;
   vms.oldmessages = vms.lastmsg + 1;
   ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
   /* check INBOX */
   res = open_mailbox(&vms, vmu, NEW_FOLDER);
   if (res < 0)
      goto out;
   vms.newmessages = vms.lastmsg + 1;
   ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
   /* Start in Urgent */
   in_urgent = 1;
   res = open_mailbox(&vms, vmu, 11); /*11 is the Urgent folder */
   if (res < 0)
      goto out;
   vms.urgentmessages = vms.lastmsg + 1;
   ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);

   /* Select proper mailbox FIRST!! */
   if (play_auto) {
      ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
      if (vms.urgentmessages) {
         in_urgent = 1;
         res = open_mailbox(&vms, vmu, 11);
      } else {
         in_urgent = 0;
         res = open_mailbox(&vms, vmu, play_folder);
      }
      if (res < 0)
         goto out;

      /* If there are no new messages, inform the user and hangup */
      if (vms.lastmsg == -1) {
         in_urgent = 0;
         cmd = vm_browse_messages(chan, &vms, vmu);
         res = 0;
         goto out;
      }
   } else {
      if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
         /* If we only have old messages start here */
         res = open_mailbox(&vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
         in_urgent = 0;
         play_folder = 1;
         if (res < 0)
            goto out;
      } else if (!vms.urgentmessages && vms.newmessages) {
         /* If we have new messages but none are urgent */
         in_urgent = 0;
         res = open_mailbox(&vms, vmu, NEW_FOLDER);
         if (res < 0)
            goto out;
      }
   }

   if (useadsi)
      adsi_status(chan, &vms);
   res = 0;

   /* Check to see if this is a new user */
   if (!strcasecmp(vmu->mailbox, vmu->password) && 
      (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
      if (ast_play_and_wait(chan, "vm-newuser") == -1)
         ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
      cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
      if ((cmd == 't') || (cmd == '#')) {
         /* Timeout */
         ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
         res = 0;
         goto out;
      } else if (cmd < 0) {
         /* Hangup */
         ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
         res = -1;
         goto out;
      }
   }
#ifdef IMAP_STORAGE
      ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
      if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
         ast_debug(1, "*** QUOTA EXCEEDED!!\n");
         cmd = ast_play_and_wait(chan, "vm-mailboxfull");
      }
      ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
      if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
         ast_log(AST_LOG_WARNING, "No more messages possible.  User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
         cmd = ast_play_and_wait(chan, "vm-mailboxfull");
      }
#endif

   ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
   if (play_auto) {
      cmd = '1';
   } else {
      cmd = vm_intro(chan, vmu, &vms);
   }
   ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);

   vms.repeats = 0;
   vms.starting = 1;
   while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
      /* Run main menu */
      switch (cmd) {
      case '1': /* First message */
         vms.curmsg = 0;
         /* Fall through */
      case '5': /* Play current message */
         ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
         cmd = vm_browse_messages(chan, &vms, vmu);
         break;
      case '2': /* Change folders */
         ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
         if (useadsi)
            adsi_folders(chan, 0, "Change to folder...");

         cmd = get_folder2(chan, "vm-changeto", 0);
         ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
         if (cmd == '#') {
            cmd = 0;
         } else if (cmd > 0) {
            cmd = cmd - '0';
            res = close_mailbox(&vms, vmu);
            if (res == ERROR_LOCK_PATH)
               goto out;
            /* If folder is not urgent, set in_urgent to zero! */
            if (cmd != 11) in_urgent = 0;
            res = open_mailbox(&vms, vmu, cmd);
            if (res < 0)
               goto out;
            play_folder = cmd;
            cmd = 0;
         }
         if (useadsi)
            adsi_status2(chan, &vms);

         if (!cmd) {
            cmd = vm_play_folder_name(chan, vms.vmbox);
         }

         vms.starting = 1;
         vms.curmsg = 0;
         break;
      case '3': /* Advanced options */
         ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
         cmd = 0;
         vms.repeats = 0;
         while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
            switch (cmd) {
            case '1': /* Reply */
               if (vms.lastmsg > -1 && !vms.starting) {
                  cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
                  if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
                     res = cmd;
                     goto out;
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-sorry");
               }
               cmd = 't';
               break;
            case '2': /* Callback */
               if (!vms.starting)
                  ast_verb(3, "Callback Requested\n");
               if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
                  cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
                  if (cmd == 9) {
                     silentexit = 1;
                     goto out;
                  } else if (cmd == ERROR_LOCK_PATH) {
                     res = cmd;
                     goto out;
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-sorry");
               }
               cmd = 't';
               break;
            case '3': /* Envelope */
               if (vms.lastmsg > -1 && !vms.starting) {
                  cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
                  if (cmd == ERROR_LOCK_PATH) {
                     res = cmd;
                     goto out;
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-sorry");
               }
               cmd = 't';
               break;
            case '4': /* Dialout */
               if (!ast_strlen_zero(vmu->dialout)) {
                  cmd = dialout(chan, vmu, NULL, vmu->dialout);
                  if (cmd == 9) {
                     silentexit = 1;
                     goto out;
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-sorry");
               }
               cmd = 't';
               break;

            case '5': /* Leave VoiceMail */
               if (ast_test_flag(vmu, VM_SVMAIL)) {
                  cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
                  if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
                     res = cmd;
                     goto out;
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-sorry");
               }
               cmd = 't';
               break;

            case '*': /* Return to main menu */
               cmd = 't';
               break;

            default:
               cmd = 0;
               if (!vms.starting) {
                  cmd = ast_play_and_wait(chan, "vm-toreply");
               }
               if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
                  cmd = ast_play_and_wait(chan, "vm-tocallback");
               }
               if (!cmd && !vms.starting) {
                  cmd = ast_play_and_wait(chan, "vm-tohearenv");
               }
               if (!ast_strlen_zero(vmu->dialout) && !cmd) {
                  cmd = ast_play_and_wait(chan, "vm-tomakecall");
               }
               if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
                  cmd = ast_play_and_wait(chan, "vm-leavemsg");
               }
               if (!cmd) {
                  cmd = ast_play_and_wait(chan, "vm-starmain");
               }
               if (!cmd) {
                  cmd = ast_waitfordigit(chan, 6000);
               }
               if (!cmd) {
                  vms.repeats++;
               }
               if (vms.repeats > 3) {
                  cmd = 't';
               }
               ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
            }
         }
         if (cmd == 't') {
            cmd = 0;
            vms.repeats = 0;
         }
         break;
      case '4': /* Go to the previous message */
         ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
         if (vms.curmsg > 0) {
            vms.curmsg--;
            cmd = play_message(chan, vmu, &vms);
         } else {
            /* Check if we were listening to new
               messages.  If so, go to Urgent messages
               instead of saying "no more messages"
            */
            if (in_urgent == 0 && vms.urgentmessages > 0) {
               /* Check for Urgent messages */
               in_urgent = 1;
               res = close_mailbox(&vms, vmu);
               if (res == ERROR_LOCK_PATH)
                  goto out;
               res = open_mailbox(&vms, vmu, 11);  /* Open Urgent folder */
               if (res < 0)
                  goto out;
               ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
               vms.curmsg = vms.lastmsg;
               if (vms.lastmsg < 0) {
                  cmd = ast_play_and_wait(chan, "vm-nomore");
               }
            } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
               vms.curmsg = vms.lastmsg;
               cmd = play_message(chan, vmu, &vms);
            } else {
               cmd = ast_play_and_wait(chan, "vm-nomore");
            }
         }
         break;
      case '6': /* Go to the next message */
         ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
         if (vms.curmsg < vms.lastmsg) {
            vms.curmsg++;
            cmd = play_message(chan, vmu, &vms);
         } else {
            if (in_urgent && vms.newmessages > 0) {
               /* Check if we were listening to urgent
                * messages.  If so, go to regular new messages
                * instead of saying "no more messages"
                */
               in_urgent = 0;
               res = close_mailbox(&vms, vmu);
               if (res == ERROR_LOCK_PATH)
                  goto out;
               res = open_mailbox(&vms, vmu, NEW_FOLDER);
               if (res < 0)
                  goto out;
               ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
               vms.curmsg = -1;
               if (vms.lastmsg < 0) {
                  cmd = ast_play_and_wait(chan, "vm-nomore");
               }
            } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
               vms.curmsg = 0;
               cmd = play_message(chan, vmu, &vms);
            } else {
               cmd = ast_play_and_wait(chan, "vm-nomore");
            }
         }
         break;
      case '7': /* Delete the current message */
         if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
            vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
            if (useadsi)
               adsi_delete(chan, &vms);
            if (vms.deleted[vms.curmsg]) {
               if (play_folder == 0) {
                  if (in_urgent) {
                     vms.urgentmessages--;
                  } else {
                     vms.newmessages--;
                  }
               }
               else if (play_folder == 1)
                  vms.oldmessages--;
               cmd = ast_play_and_wait(chan, "vm-deleted");
            } else {
               if (play_folder == 0) {
                  if (in_urgent) {
                     vms.urgentmessages++;
                  } else {
                     vms.newmessages++;
                  }
               }
               else if (play_folder == 1)
                  vms.oldmessages++;
               cmd = ast_play_and_wait(chan, "vm-undeleted");
            }
            if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
               if (vms.curmsg < vms.lastmsg) {
                  vms.curmsg++;
                  cmd = play_message(chan, vmu, &vms);
               } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
                  vms.curmsg = 0;
                  cmd = play_message(chan, vmu, &vms);
               } else {
                  /* Check if we were listening to urgent
                     messages.  If so, go to regular new messages
                     instead of saying "no more messages"
                  */
                  if (in_urgent == 1) {
                     /* Check for new messages */
                     in_urgent = 0;
                     res = close_mailbox(&vms, vmu);
                     if (res == ERROR_LOCK_PATH)
                        goto out;
                     res = open_mailbox(&vms, vmu, NEW_FOLDER);
                     if (res < 0)
                        goto out;
                     ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
                     vms.curmsg = -1;
                     if (vms.lastmsg < 0) {
                        cmd = ast_play_and_wait(chan, "vm-nomore");
                     }
                  } else {
                     cmd = ast_play_and_wait(chan, "vm-nomore");
                  }
               }
            }
         } else /* Delete not valid if we haven't selected a message */
            cmd = 0;
#ifdef IMAP_STORAGE
         deleted = 1;
#endif
         break;

      case '8': /* Forward the current message */
         if (vms.lastmsg > -1) {
            cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
            if (cmd == ERROR_LOCK_PATH) {
               res = cmd;
               goto out;
            }
         } else {
            /* Check if we were listening to urgent
               messages.  If so, go to regular new messages
               instead of saying "no more messages"
            */
            if (in_urgent == 1 && vms.newmessages > 0) {
               /* Check for new messages */
               in_urgent = 0;
               res = close_mailbox(&vms, vmu);
               if (res == ERROR_LOCK_PATH)
                  goto out;
               res = open_mailbox(&vms, vmu, NEW_FOLDER);
               if (res < 0)
                  goto out;
               ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
               vms.curmsg = -1;
               if (vms.lastmsg < 0) {
                  cmd = ast_play_and_wait(chan, "vm-nomore");
               }
            } else {
               cmd = ast_play_and_wait(chan, "vm-nomore");
            }
         }
         break;
      case '9': /* Save message to folder */
         ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
         if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
            /* No message selected */
            cmd = 0;
            break;
         }
         if (useadsi)
            adsi_folders(chan, 1, "Save to folder...");
         cmd = get_folder2(chan, "vm-savefolder", 1);
         ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
         box = 0; /* Shut up compiler */
         if (cmd == '#') {
            cmd = 0;
            break;
         } else if (cmd > 0) {
            box = cmd = cmd - '0';
            cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd, NULL, 0);
            if (cmd == ERROR_LOCK_PATH) {
               res = cmd;
               goto out;
#ifndef IMAP_STORAGE
            } else if (!cmd) {
               vms.deleted[vms.curmsg] = 1;
#endif
            } else {
               vms.deleted[vms.curmsg] = 0;
               vms.heard[vms.curmsg] = 0;
            }
         }
         make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
         if (useadsi)
            adsi_message(chan, &vms);
         snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
         if (!cmd) {
            cmd = ast_play_and_wait(chan, "vm-message");
            if (!cmd) 
               cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
            if (!cmd)
               cmd = ast_play_and_wait(chan, "vm-savedto");
            if (!cmd)
               cmd = vm_play_folder_name(chan, vms.fn);
         } else {
            cmd = ast_play_and_wait(chan, "vm-mailboxfull");
         }
         if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
            if (vms.curmsg < vms.lastmsg) {
               vms.curmsg++;
               cmd = play_message(chan, vmu, &vms);
            } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
               vms.curmsg = 0;
               cmd = play_message(chan, vmu, &vms);
            } else {
               /* Check if we were listening to urgent
                  messages.  If so, go to regular new messages
                  instead of saying "no more messages"
               */
               if (in_urgent == 1 && vms.newmessages > 0) {
                  /* Check for new messages */
                  in_urgent = 0;
                  res = close_mailbox(&vms, vmu);
                  if (res == ERROR_LOCK_PATH)
                     goto out;
                  res = open_mailbox(&vms, vmu, NEW_FOLDER);
                  if (res < 0)
                     goto out;
                  ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
                  vms.curmsg = -1;
                  if (vms.lastmsg < 0) {
                     cmd = ast_play_and_wait(chan, "vm-nomore");
                  }
               } else {
                  cmd = ast_play_and_wait(chan, "vm-nomore");
               }
            }
         }
         break;
      case '*': /* Help */
         if (!vms.starting) {
            cmd = ast_play_and_wait(chan, "vm-onefor");
            if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
               cmd = ast_play_and_wait(chan, "vm-for");
            }
            if (!cmd)
               cmd = vm_play_folder_name(chan, vms.vmbox);
            if (!cmd)
               cmd = ast_play_and_wait(chan, "vm-opts");
            if (!cmd)
               cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
         } else
            cmd = 0;
         break;
      case '0': /* Mailbox options */
         cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
         if (useadsi)
            adsi_status(chan, &vms);
         break;
      default: /* Nothing */
         ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
         cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
         break;
      }
   }
   if ((cmd == 't') || (cmd == '#')) {
      /* Timeout */
      res = 0;
   } else {
      /* Hangup */
      res = -1;
   }

out:
   if (res > -1) {
      ast_stopstream(chan);
      adsi_goodbye(chan);
      if (valid && res != OPERATOR_EXIT) {
         if (silentexit)
            res = ast_play_and_wait(chan, "vm-dialout");
         else 
            res = ast_play_and_wait(chan, "vm-goodbye");
      }
      if ((valid && res > 0) || res == OPERATOR_EXIT) {
         res = 0;
      }
      if (useadsi)
         ast_adsi_unload_session(chan);
   }
   if (vmu)
      close_mailbox(&vms, vmu);
   if (valid) {
      int new = 0, old = 0, urgent = 0;
      snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
      /*** DOCUMENTATION
         <managerEventInstance>
            <synopsis>Raised when a user has finished listening to their messages.</synopsis>
         </managerEventInstance>
      ***/
      ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
      /* Urgent flag not passwd to externnotify here */
      run_externnotify(vmu->context, vmu->mailbox, NULL);
      ast_app_inboxcount2(ext_context, &urgent, &new, &old);
      queue_mwi_event(ext_context, urgent, new, old);
   }
#ifdef IMAP_STORAGE
   /* expunge message - use UID Expunge if supported on IMAP server*/
   ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
   if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
      ast_mutex_lock(&vms.lock);
#ifdef HAVE_IMAP_TK2006
      if (LEVELUIDPLUS (vms.mailstream)) {
         mail_expunge_full(vms.mailstream, NIL, EX_UID);
      } else
#endif
         mail_expunge(vms.mailstream);
      ast_mutex_unlock(&vms.lock);
   }
   /*  before we delete the state, we should copy pertinent info
    *  back to the persistent model */
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif
   if (vmu)
      free_user(vmu);

#ifdef IMAP_STORAGE
   pthread_setspecific(ts_vmstate.key, NULL);
#endif
   return res;
}
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 
) [static]

presents the option to prepend to an existing message when forwarding it.

Parameters:
chan
vmu
curdir
curmsg
vm_fmts
context
record_gain
duration
vms
flag

Presents a prompt for 1 to prepend the current message, 2 to forward the message without prepending, or * to return to the main menu.

This is invoked from forward_message() when performing a forward operation (option 8 from main menu).

Returns:
zero on success, -1 on error.

Definition at line 7541 of file app_voicemail.c.

References ast_category_get(), ast_channel_setoption(), ast_config_destroy(), ast_config_load, ast_config_text_file_save(), ast_filecopy(), ast_filerename(), AST_OPTION_RXGAIN, ast_play_and_prepend(), ast_play_and_wait(), ast_stream_and_wait(), ast_test_suite_event_notify, ast_variable_retrieve(), ast_variable_update(), ast_waitfordigit(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, copy(), INTRO, make_file(), ast_vm_user::maxsecs, play_record_review(), and valid_config().

Referenced by forward_message().

{
   int cmd = 0;
   int retries = 0, prepend_duration = 0, already_recorded = 0;
   char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
   char textfile[PATH_MAX];
   struct ast_config *msg_cfg;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
#ifndef IMAP_STORAGE
   signed char zero_gain = 0;
#else
   const char *msg_id = NULL;
#endif
   const char *duration_str;

   /* Must always populate duration correctly */
   make_file(msgfile, sizeof(msgfile), curdir, curmsg);
   strcpy(textfile, msgfile);
   strcpy(backup, msgfile);
   strcpy(backup_textfile, msgfile);
   strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
   strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
   strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);

   if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
      *duration = atoi(duration_str);
   } else {
      *duration = 0;
   }

   while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
      if (cmd)
         retries = 0;
      switch (cmd) {
      case '1': 

#ifdef IMAP_STORAGE
         /* Record new intro file */
         if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
            msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
         }
         make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
         strncat(vms->introfn, "intro", sizeof(vms->introfn));
         ast_play_and_wait(chan, INTRO);
         ast_play_and_wait(chan, "beep");
         cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag, msg_id);
         if (cmd == -1) {
            break;
         }
         cmd = 't';
#else

         /* prepend a message to the current message, update the metadata and return */

         make_file(msgfile, sizeof(msgfile), curdir, curmsg);
         strcpy(textfile, msgfile);
         strncat(textfile, ".txt", sizeof(textfile) - 1);
         *duration = 0;

         /* if we can't read the message metadata, stop now */
         if (!valid_config(msg_cfg)) {
            cmd = 0;
            break;
         }

         /* Back up the original file, so we can retry the prepend and restore it after forward. */
#ifndef IMAP_STORAGE
         if (already_recorded) {
            ast_filecopy(backup, msgfile, NULL);
            copy(backup_textfile, textfile);
         }
         else {
            ast_filecopy(msgfile, backup, NULL);
            copy(textfile, backup_textfile);
         }
#endif
         already_recorded = 1;

         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);

         cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);

         if (cmd == 'S') { /* If we timed out, tell the user it didn't work properly and clean up the files */
            ast_stream_and_wait(chan, vm_pls_try_again, ""); /* this might be removed if a proper vm_prepend_timeout is ever recorded */
            ast_stream_and_wait(chan, vm_prepend_timeout, "");
            ast_filerename(backup, msgfile, NULL);
         }

         if (record_gain)
            ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);

         
         if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
            *duration = atoi(duration_str);

         if (prepend_duration) {
            struct ast_category *msg_cat;
            /* need enough space for a maximum-length message duration */
            char duration_buf[12];

            *duration += prepend_duration;
            msg_cat = ast_category_get(msg_cfg, "message");
            snprintf(duration_buf, 11, "%ld", *duration);
            if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
               ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
            }
         }

#endif
         break;
      case '2': 
         /* NULL out introfile so we know there is no intro! */
#ifdef IMAP_STORAGE
         *vms->introfn = '\0';
#endif
         cmd = 't';
         break;
      case '*':
         cmd = '*';
         break;
      default: 
         /* If time_out and return to menu, reset already_recorded */
         already_recorded = 0;

         cmd = ast_play_and_wait(chan, "vm-forwardoptions");
            /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
         if (!cmd) {
            cmd = ast_play_and_wait(chan, "vm-starmain");
            /* "press star to return to the main menu" */
         }
         if (!cmd) {
            cmd = ast_waitfordigit(chan, 6000);
         }
         if (!cmd) {
            retries++;
         }
         if (retries > 3) {
            cmd = '*'; /* Let's cancel this beast */
         }
         ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
      }
   }

   if (valid_config(msg_cfg))
      ast_config_destroy(msg_cfg);
   if (prepend_duration)
      *duration = prepend_duration;

   if (already_recorded && cmd == -1) {
      /* restore original message if prepention cancelled */
      ast_filerename(backup, msgfile, NULL);
      rename(backup_textfile, textfile);
   }

   if (cmd == 't' || cmd == 'S') /* XXX entering this block with a value of 'S' is probably no longer possible. */
      cmd = 0;
   return cmd;
}
static const char* vm_index_to_foldername ( int  id) [static]

Definition at line 1898 of file app_voicemail.c.

References mbox().

Referenced by load_module().

{
   return mbox(NULL, id);
}
static int vm_instructions ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
int  skipadvanced,
int  in_urgent 
) [static]

Definition at line 9965 of file app_voicemail.c.

References ast_channel_language(), vm_state::starting, vm_instructions_en(), and vm_instructions_zh().

Referenced by vm_execmain().

{
   if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
      return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
   } else {             /* Default to ENGLISH */
      return vm_instructions_en(chan, vmu, vms, skipadvanced, 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]

Definition at line 9853 of file app_voicemail.c.

References ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_test_flag, ast_waitfordigit(), vm_state::curmsg, vm_state::deleted, vm_state::lastmsg, vm_state::newmessages, vm_state::repeats, vm_state::starting, vm_state::urgentmessages, VM_MESSAGEWRAP, vm_play_folder_name(), and vm_state::vmbox.

Referenced by vm_instructions(), and vm_instructions_zh().

{
   int res = 0;
   /* Play instructions and wait for new command */
   while (!res) {
      if (vms->starting) {
         if (vms->lastmsg > -1) {
            if (skipadvanced)
               res = ast_play_and_wait(chan, "vm-onefor-full");
            else
               res = ast_play_and_wait(chan, "vm-onefor");
            if (!res)
               res = vm_play_folder_name(chan, vms->vmbox);
         }
         if (!res) {
            if (skipadvanced)
               res = ast_play_and_wait(chan, "vm-opts-full");
            else
               res = ast_play_and_wait(chan, "vm-opts");
         }
      } else {
         /* Added for additional help */
         if (skipadvanced) {
            res = ast_play_and_wait(chan, "vm-onefor-full");
            if (!res)
               res = vm_play_folder_name(chan, vms->vmbox);
            res = ast_play_and_wait(chan, "vm-opts-full");
         }
         /* Logic:
          * If the current message is not the first OR
          * if we're listening to the first new message and there are
          * also urgent messages, then prompt for navigation to the
          * previous message
          */
         if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
            res = ast_play_and_wait(chan, "vm-prev");
         }
         if (!res && !skipadvanced)
            res = ast_play_and_wait(chan, "vm-advopts");
         if (!res)
            res = ast_play_and_wait(chan, "vm-repeat");
         /* Logic:
          * If we're not listening to the last message OR
          * we're listening to the last urgent message and there are
          * also new non-urgent messages, then prompt for navigation
          * to the next message
          */
         if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
            (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
            res = ast_play_and_wait(chan, "vm-next");
         }
         if (!res) {
            int curmsg_deleted;
#ifdef IMAP_STORAGE
            ast_mutex_lock(&vms->lock);
#endif
            curmsg_deleted = vms->deleted[vms->curmsg];
#ifdef IMAP_STORAGE
            ast_mutex_unlock(&vms->lock);
#endif
            if (!curmsg_deleted) {
               res = ast_play_and_wait(chan, "vm-delete");
            } else {
               res = ast_play_and_wait(chan, "vm-undelete");
            }
            if (!res) {
               res = ast_play_and_wait(chan, "vm-toforward");
            }
            if (!res) {
               res = ast_play_and_wait(chan, "vm-savemessage");
            }
         }
      }
      if (!res) {
         res = ast_play_and_wait(chan, "vm-helpexit");
      }
      if (!res)
         res = ast_waitfordigit(chan, 6000);
      if (!res) {
         vms->repeats++;
         if (vms->repeats > 2) {
            res = 't';
         }
      }
   }
   return res;
}
static int vm_instructions_zh ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
int  skipadvanced,
int  in_urgent 
) [static]

Definition at line 9941 of file app_voicemail.c.

References ast_play_and_wait(), vm_state::lastmsg, vm_state::starting, vm_instructions_en(), vm_play_folder_name(), and vm_state::vmbox.

Referenced by vm_instructions().

{
   int res = 0;
   /* Play instructions and wait for new command */
   while (!res) {
      if (vms->lastmsg > -1) {
         res = ast_play_and_wait(chan, "vm-listen");
         if (!res)
            res = vm_play_folder_name(chan, vms->vmbox);
         if (!res)
            res = ast_play_and_wait(chan, "press");
         if (!res)
            res = ast_play_and_wait(chan, "digits/1");
      }
      if (!res)
         res = ast_play_and_wait(chan, "vm-opts");
      if (!res) {
         vms->starting = 0;
         return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
      }
   }
   return res;
}
static int vm_intro ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms 
) [static]

Definition at line 9791 of file app_voicemail.c.

References ast_channel_language(), ast_fileexists(), ast_log(), ast_play_and_wait(), ast_test_flag, ast_vm_user::context, DISPOSE, LOG_WARNING, ast_vm_user::mailbox, RETRIEVE, vm_state::username, vm_intro_cs(), vm_intro_de(), vm_intro_en(), vm_intro_es(), vm_intro_fr(), vm_intro_gr(), vm_intro_he(), vm_intro_it(), vm_intro_multilang(), vm_intro_nl(), vm_intro_no(), vm_intro_pl(), vm_intro_pt(), vm_intro_pt_BR(), vm_intro_se(), vm_intro_vi(), vm_intro_zh(), and VM_TEMPGREETWARN.

Referenced by vm_execmain().

{
   char prefile[256];
   
   /* Notify the user that the temp greeting is set and give them the option to remove it */
   snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
   if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
      RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
      if (ast_fileexists(prefile, NULL, NULL) > 0) {
         ast_play_and_wait(chan, "vm-tempgreetactive");
      }
      DISPOSE(prefile, -1);
   }

   /* Play voicemail intro - syntax is different for different languages */
   if (0) {
      return 0;
   } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) {  /* CZECH syntax */
      return vm_intro_cs(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "cz", 2)) {  /* deprecated CZECH syntax */
      static int deprecation_warning = 0;
      if (deprecation_warning++ % 10 == 0) {
         ast_log(LOG_WARNING, "cz is not a standard language code.  Please switch to using cs instead.\n");
      }
      return vm_intro_cs(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {  /* GERMAN syntax */
      return vm_intro_de(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) {  /* SPANISH syntax */
      return vm_intro_es(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) {  /* FRENCH syntax */
      return vm_intro_fr(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {  /* GREEK syntax */
      return vm_intro_gr(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {  /* HEBREW syntax */
      return vm_intro_he(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {  /* ITALIAN syntax */
      return vm_intro_it(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {  /* DUTCH syntax */
      return vm_intro_nl(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {  /* NORWEGIAN syntax */
      return vm_intro_no(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {  /* POLISH syntax */
      return vm_intro_pl(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {  /* BRAZILIAN PORTUGUESE syntax */
      return vm_intro_pt_BR(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {  /* PORTUGUESE syntax */
      return vm_intro_pt(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) {  /* RUSSIAN syntax */
      return vm_intro_multilang(chan, vms, "n");
   } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {  /* SWEDISH syntax */
      return vm_intro_se(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {  /* UKRAINIAN syntax */
      return vm_intro_multilang(chan, vms, "n");
   } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
      return vm_intro_vi(chan, vms);
   } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
      return vm_intro_zh(chan, vms);
   } else {                                             /* Default to ENGLISH */
      return vm_intro_en(chan, vms);
   }
}
static int vm_intro_cs ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9661 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   int res;
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         if (vms->newmessages == 1) {
            res = ast_play_and_wait(chan, "digits/jednu");
         } else {
            res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         }
         if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-novou");
            if ((vms->newmessages) > 1 && (vms->newmessages < 5))
               res = ast_play_and_wait(chan, "vm-nove");
            if (vms->newmessages > 4)
               res = ast_play_and_wait(chan, "vm-novych");
         }
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
         else if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-zpravu");
            if ((vms->newmessages) > 1 && (vms->newmessages < 5))
               res = ast_play_and_wait(chan, "vm-zpravy");
            if (vms->newmessages > 4)
               res = ast_play_and_wait(chan, "vm-zprav");
         }
      }
      if (!res && vms->oldmessages) {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res) {
            if ((vms->oldmessages == 1))
               res = ast_play_and_wait(chan, "vm-starou");
            if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
               res = ast_play_and_wait(chan, "vm-stare");
            if (vms->oldmessages > 4)
               res = ast_play_and_wait(chan, "vm-starych");
         }
         if (!res) {
            if ((vms->oldmessages == 1))
               res = ast_play_and_wait(chan, "vm-zpravu");
            if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
               res = ast_play_and_wait(chan, "vm-zpravy");
            if (vms->oldmessages > 4)
               res = ast_play_and_wait(chan, "vm-zprav");
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-zpravy");
         }
      }
   }
   return res;
}
static int vm_intro_de ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9357 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         if ((vms->newmessages == 1))
            res = ast_play_and_wait(chan, "digits/1F");
         else
            res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOX");
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
         else if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
            
      }
      if (!res && vms->oldmessages) {
         if (vms->oldmessages == 1)
            res = ast_play_and_wait(chan, "digits/1F");
         else
            res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-Old");
         if (!res) {
            if (vms->oldmessages == 1)
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   }
   return res;
}
static int vm_intro_en ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9106 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   int res;

   /* Introduce messages they have */
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->urgentmessages) {
         res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-Urgent");
         if ((vms->oldmessages || vms->newmessages) && !res) {
            res = ast_play_and_wait(chan, "vm-and");
         } else if (!res) {
            if ((vms->urgentmessages == 1))
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
      if (vms->newmessages) {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOX");
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
         else if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
            
      }
      if (!res && vms->oldmessages) {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-Old");
         if (!res) {
            if (vms->oldmessages == 1)
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
      if (!res) {
         if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   }
   return res;
}
static int vm_intro_es ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9406 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
      res = ast_play_and_wait(chan, "vm-youhaveno");
      if (!res)
         res = ast_play_and_wait(chan, "vm-messages");
   } else {
      res = ast_play_and_wait(chan, "vm-youhave");
   }
   if (!res) {
      if (vms->newmessages) {
         if (!res) {
            if ((vms->newmessages == 1)) {
               res = ast_play_and_wait(chan, "digits/1M");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-message");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-INBOXs");
            } else {
               res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
               if (!res)
                  res = ast_play_and_wait(chan, "vm-messages");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-INBOX");
            }
         }
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
      }
      if (vms->oldmessages) {
         if (!res) {
            if (vms->oldmessages == 1) {
               res = ast_play_and_wait(chan, "digits/1M");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-message");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-Olds");
            } else {
               res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
               if (!res)
                  res = ast_play_and_wait(chan, "vm-messages");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-Old");
            }
         }
      }
   }
return res;
}
static int vm_intro_fr ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9504 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOX");
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
         else if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
            
      }
      if (!res && vms->oldmessages) {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-Old");
         if (!res) {
            if (vms->oldmessages == 1)
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   }
   return res;
}
static int vm_intro_gr ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 8905 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_intro().

{
   int res = 0;

   if (vms->newmessages) {
      res = ast_play_and_wait(chan, "vm-youhave");
      if (!res) 
         res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
      if (!res) {
         if ((vms->newmessages == 1)) {
            res = ast_play_and_wait(chan, "vm-INBOX");
            if (!res)
               res = ast_play_and_wait(chan, "vm-message");
         } else {
            res = ast_play_and_wait(chan, "vm-INBOXs");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   } else if (vms->oldmessages){
      res = ast_play_and_wait(chan, "vm-youhave");
      if (!res)
         res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
      if ((vms->oldmessages == 1)){
         res = ast_play_and_wait(chan, "vm-Old");
         if (!res)
            res = ast_play_and_wait(chan, "vm-message");
      } else {
         res = ast_play_and_wait(chan, "vm-Olds");
         if (!res)
            res = ast_play_and_wait(chan, "vm-messages");
      }
   } else if (!vms->oldmessages && !vms->newmessages) 
      res = ast_play_and_wait(chan, "vm-denExeteMynhmata"); 
   return res;
}
static int vm_intro_he ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9039 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_intro().

{
   int res = 0;

   /* Introduce messages they have */
   if (!res) {
      if ((vms->newmessages) || (vms->oldmessages)) {
         res = ast_play_and_wait(chan, "vm-youhave");
      }
      /*
       * The word "shtei" refers to the number 2 in hebrew when performing a count
       * of elements. In Hebrew, there are 6 forms of enumerating the number 2 for
       * an element, this is one of them.
       */
      if (vms->newmessages) {
         if (!res) {
            if (vms->newmessages == 1) {
               res = ast_play_and_wait(chan, "vm-INBOX1");
            } else {
               if (vms->newmessages == 2) {
                  res = ast_play_and_wait(chan, "vm-shtei");
               } else {
                  res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
               }
               res = ast_play_and_wait(chan, "vm-INBOX");
            }
         }
         if (vms->oldmessages && !res) {
            res = ast_play_and_wait(chan, "vm-and");
            if (vms->oldmessages == 1) {
               res = ast_play_and_wait(chan, "vm-Old1");
            } else {
               if (vms->oldmessages == 2) {
                  res = ast_play_and_wait(chan, "vm-shtei");
               } else {
                  res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
               }
               res = ast_play_and_wait(chan, "vm-Old");
            }
         }
      }
      if (!res && vms->oldmessages && !vms->newmessages) {
         if (!res) {
            if (vms->oldmessages == 1) {
               res = ast_play_and_wait(chan, "vm-Old1");
            } else {
               if (vms->oldmessages == 2) {
                  res = ast_play_and_wait(chan, "vm-shtei");
               } else {
                  res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");            
               }
               res = ast_play_and_wait(chan, "vm-Old");
            }
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages) {
            if (!res) {
               res = ast_play_and_wait(chan, "vm-nomessages");
            }
         }
      }
   }
   return res;
}
static int vm_intro_it ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9163 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
      res = ast_play_and_wait(chan, "vm-no") ||
         ast_play_and_wait(chan, "vm-message");
   else
      res = ast_play_and_wait(chan, "vm-youhave");
   if (!res && vms->newmessages) {
      res = (vms->newmessages == 1) ?
         ast_play_and_wait(chan, "digits/un") ||
         ast_play_and_wait(chan, "vm-nuovo") ||
         ast_play_and_wait(chan, "vm-message") :
         /* 2 or more new messages */
         say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
         ast_play_and_wait(chan, "vm-nuovi") ||
         ast_play_and_wait(chan, "vm-messages");
      if (!res && vms->oldmessages)
         res = ast_play_and_wait(chan, "vm-and");
   }
   if (!res && vms->oldmessages) {
      res = (vms->oldmessages == 1) ?
         ast_play_and_wait(chan, "digits/un") ||
         ast_play_and_wait(chan, "vm-vecchio") ||
         ast_play_and_wait(chan, "vm-message") :
         /* 2 or more old messages */
         say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
         ast_play_and_wait(chan, "vm-vecchi") ||
         ast_play_and_wait(chan, "vm-messages");
   }
   return res;
}
static int vm_intro_multilang ( struct ast_channel chan,
struct vm_state vms,
const char  message_gender[] 
) [static]

Definition at line 8999 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_counted_adjective(), ast_say_counted_noun(), ast_say_number(), vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_intro().

{
   int res;
   int lastnum = 0;

   res = ast_play_and_wait(chan, "vm-youhave");

   if (!res && vms->newmessages) {
      lastnum = vms->newmessages;

      if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
         res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
      }

      if (!res && vms->oldmessages) {
         res = ast_play_and_wait(chan, "vm-and");
      }
   }

   if (!res && vms->oldmessages) {
      lastnum = vms->oldmessages;

      if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
         res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
      }
   }

   if (!res) {
      if (lastnum == 0) {
         res = ast_play_and_wait(chan, "vm-no");
      }
      if (!res) {
         res = ast_say_counted_noun(chan, lastnum, "vm-message");
      }
   }

   return res;
}
static int vm_intro_nl ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9547 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         if (!res) {
            if (vms->newmessages == 1)
               res = ast_play_and_wait(chan, "vm-INBOXs");
            else
               res = ast_play_and_wait(chan, "vm-INBOX");
         }
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
         else if (!res) {
            if ((vms->newmessages == 1))
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
            
      }
      if (!res && vms->oldmessages) {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res) {
            if (vms->oldmessages == 1)
               res = ast_play_and_wait(chan, "vm-Olds");
            else
               res = ast_play_and_wait(chan, "vm-Old");
         }
         if (!res) {
            if (vms->oldmessages == 1)
               res = ast_play_and_wait(chan, "vm-message");
            else
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   }
   return res;
}
static int vm_intro_no ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9313 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;

   res = ast_play_and_wait(chan, "vm-youhave");
   if (res)
      return res;

   if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
      res = ast_play_and_wait(chan, "vm-no");
      res = res ? res : ast_play_and_wait(chan, "vm-messages");
      return res;
   }

   if (vms->newmessages) {
      if ((vms->newmessages == 1)) {
         res = ast_play_and_wait(chan, "digits/1");
         res = res ? res : ast_play_and_wait(chan, "vm-ny");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-nye");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
      if (!res && vms->oldmessages)
         res = ast_play_and_wait(chan, "vm-and");
   }
   if (!res && vms->oldmessages) {
      if (vms->oldmessages == 1) {
         res = ast_play_and_wait(chan, "digits/1");
         res = res ? res : ast_play_and_wait(chan, "vm-gamel");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-gamle");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
   }

   return res;
}
static int vm_intro_pl ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9198 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   div_t num;

   if (!vms->oldmessages && !vms->newmessages) {
      res = ast_play_and_wait(chan, "vm-no");
      res = res ? res : ast_play_and_wait(chan, "vm-messages");
      return res;
   } else {
      res = ast_play_and_wait(chan, "vm-youhave");
   }

   if (vms->newmessages) {
      num = div(vms->newmessages, 10);
      if (vms->newmessages == 1) {
         res = ast_play_and_wait(chan, "digits/1-a");
         res = res ? res : ast_play_and_wait(chan, "vm-new-a");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
         if (num.rem == 2) {
            if (!num.quot) {
               res = ast_play_and_wait(chan, "digits/2-ie");
            } else {
               res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
               res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
            }
         } else {
            res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         }
         res = res ? res : ast_play_and_wait(chan, "vm-new-e");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      } else {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
      if (!res && vms->oldmessages)
         res = ast_play_and_wait(chan, "vm-and");
   }
   if (!res && vms->oldmessages) {
      num = div(vms->oldmessages, 10);
      if (vms->oldmessages == 1) {
         res = ast_play_and_wait(chan, "digits/1-a");
         res = res ? res : ast_play_and_wait(chan, "vm-old-a");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
         if (num.rem == 2) {
            if (!num.quot) {
               res = ast_play_and_wait(chan, "digits/2-ie");
            } else {
               res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
               res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
            }
         } else {
            res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         }
         res = res ? res : ast_play_and_wait(chan, "vm-old-e");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      } else {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
   }

   return res;
}
static int vm_intro_pt ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9598 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, vm_state::oldmessages, and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
         if (!res) {
            if ((vms->newmessages == 1)) {
               res = ast_play_and_wait(chan, "vm-message");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-INBOXs");
            } else {
               res = ast_play_and_wait(chan, "vm-messages");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-INBOX");
            }
         }
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
      }
      if (!res && vms->oldmessages) {
         res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
         if (!res) {
            if (vms->oldmessages == 1) {
               res = ast_play_and_wait(chan, "vm-message");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-Olds");
            } else {
               res = ast_play_and_wait(chan, "vm-messages");
               if (!res)
                  res = ast_play_and_wait(chan, "vm-Old");
            }
         }
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-messages");
         }
      }
   }
   return res;
}
static int vm_intro_pt_BR ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9459 of file app_voicemail.c.

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, vm_state::oldmessages, and vm_state::urgentmessages.

Referenced by vm_intro().

                                                                          {
   /* Introduce messages they have */
   int res;
   if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
      res = ast_play_and_wait(chan, "vm-nomessages");
      return res;
   } else {
      res = ast_play_and_wait(chan, "vm-youhave");
   }
   if (vms->newmessages) {
      if (!res)
         res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
      if ((vms->newmessages == 1)) {
         if (!res)
            res = ast_play_and_wait(chan, "vm-message");
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOXs");
      } else {
         if (!res)
            res = ast_play_and_wait(chan, "vm-messages");
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOX");
      }
      if (vms->oldmessages && !res)
         res = ast_play_and_wait(chan, "vm-and");
   }
   if (vms->oldmessages) {
      if (!res)
         res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
      if (vms->oldmessages == 1) {
         if (!res)
            res = ast_play_and_wait(chan, "vm-message");
         if (!res)
            res = ast_play_and_wait(chan, "vm-Olds");
      } else {
         if (!res)
            res = ast_play_and_wait(chan, "vm-messages");
         if (!res)
            res = ast_play_and_wait(chan, "vm-Old");
      }
   }
   return res;
}
static int vm_intro_se ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9269 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

{
   /* Introduce messages they have */
   int res;

   res = ast_play_and_wait(chan, "vm-youhave");
   if (res)
      return res;

   if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
      res = ast_play_and_wait(chan, "vm-no");
      res = res ? res : ast_play_and_wait(chan, "vm-messages");
      return res;
   }

   if (vms->newmessages) {
      if ((vms->newmessages == 1)) {
         res = ast_play_and_wait(chan, "digits/ett");
         res = res ? res : ast_play_and_wait(chan, "vm-nytt");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-nya");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
      if (!res && vms->oldmessages)
         res = ast_play_and_wait(chan, "vm-and");
   }
   if (!res && vms->oldmessages) {
      if (vms->oldmessages == 1) {
         res = ast_play_and_wait(chan, "digits/ett");
         res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
         res = res ? res : ast_play_and_wait(chan, "vm-message");
      } else {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         res = res ? res : ast_play_and_wait(chan, "vm-gamla");
         res = res ? res : ast_play_and_wait(chan, "vm-messages");
      }
   }

   return res;
}
static int vm_intro_vi ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9761 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

{
   int res;

   /* Introduce messages they have */
   res = ast_play_and_wait(chan, "vm-youhave");
   if (!res) {
      if (vms->newmessages) {
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-INBOX");
         if (vms->oldmessages && !res)
            res = ast_play_and_wait(chan, "vm-and");
      }
      if (!res && vms->oldmessages) {
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
         if (!res)
            res = ast_play_and_wait(chan, "vm-Old");        
      }
      if (!res) {
         if (!vms->oldmessages && !vms->newmessages) {
            res = ast_play_and_wait(chan, "vm-no");
            if (!res)
               res = ast_play_and_wait(chan, "vm-message");
         }
      }
   }
   return res;
}
static int vm_intro_zh ( struct ast_channel chan,
struct vm_state vms 
) [static]

Definition at line 9722 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

{
   int res;
   /* Introduce messages they have */
   res = ast_play_and_wait(chan, "vm-you");

   if (!res && vms->newmessages) {
      res = ast_play_and_wait(chan, "vm-have");
      if (!res)
         res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
      if (!res)
         res = ast_play_and_wait(chan, "vm-tong");
      if (!res)
         res = ast_play_and_wait(chan, "vm-INBOX");
      if (vms->oldmessages && !res)
         res = ast_play_and_wait(chan, "vm-and");
      else if (!res) 
         res = ast_play_and_wait(chan, "vm-messages");
   }
   if (!res && vms->oldmessages) {
      res = ast_play_and_wait(chan, "vm-have");
      if (!res)
         res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
      if (!res)
         res = ast_play_and_wait(chan, "vm-tong");
      if (!res)
         res = ast_play_and_wait(chan, "vm-Old");
      if (!res)
         res = ast_play_and_wait(chan, "vm-messages");
   }
   if (!res && !vms->oldmessages && !vms->newmessages) {
      res = ast_play_and_wait(chan, "vm-haveno");
      if (!res)
         res = ast_play_and_wait(chan, "vm-messages");
   }
   return res;
}
static int vm_lock_path ( const char *  path) [static]

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

Definition at line 3536 of file app_voicemail.c.

References ast_lock_path(), and AST_LOCK_TIMEOUT.

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

{
   switch (ast_lock_path(path)) {
   case AST_LOCK_TIMEOUT:
      return -1;
   default:
      return 0;
   }
}
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_create ( const char *  mailbox,
const char *  context,
const char *  folder,
int  descending,
enum ast_vm_snapshot_sort_val  sort_val,
int  combine_INBOX_and_OLD 
) [static, read]

Definition at line 14984 of file app_voicemail.c.

References ARRAY_LEN, ast_calloc, ast_copy_string(), ast_free, ast_log(), AST_LOG_ERROR, AST_LOG_WARNING, ast_strlen_zero(), close_mailbox(), ERROR_LOCK_PATH, find_user(), ast_vm_mailbox_snapshot::folders, get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, open_mailbox(), ast_vm_mailbox_snapshot::snapshots, vm_state::username, and vm_msg_snapshot_create().

Referenced by load_module().

{
   struct ast_vm_mailbox_snapshot *mailbox_snapshot;
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   int res;
   int i;
   int this_index_only = -1;
   int open = 0;
   int inbox_index = get_folder_by_name("INBOX");
   int old_index = get_folder_by_name("Old");
   int urgent_index = get_folder_by_name("Urgent");

   if (ast_strlen_zero(mailbox)) {
      ast_log(LOG_WARNING, "Cannot create a mailbox snapshot since no mailbox was specified\n");
      return NULL;
   }

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

   if (!(ast_strlen_zero(folder))) {
      /* find the folder index */
      for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
         if (!strcasecmp(mailbox_folders[i], folder)) {
            this_index_only = i;
            break;
         }
      }
      if (this_index_only == -1) {
         /* Folder was specified and it did not match any folder in our list */
         return NULL;
      }
   }

   if (!(vmu = find_user(&vmus, context, mailbox))) {
      ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot for unknown voicemail user %s@%s\n", mailbox, context);
      return NULL;
   }

   if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot)))) {
      ast_log(AST_LOG_ERROR, "Failed to allocate memory for mailbox snapshot\n");
      return NULL;
   }

   if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots)))) {
      ast_free(mailbox_snapshot);
      return NULL;
   }

   mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders);

   for (i = 0; i < mailbox_snapshot->folders; i++) {
      int msg_folder_index = i;

      /* We want this message in the snapshot if any of the following:
       *   No folder was specified.
       *   The specified folder matches the current folder.
       *   The specified folder is INBOX AND we were asked to combine messages AND the current folder is either Old or Urgent.
       */
      if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
         continue;
      }

      /* Make sure that Old or Urgent messages are marked as being in INBOX. */
      if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
         msg_folder_index = inbox_index;
      }

      memset(&vms, 0, sizeof(vms));
      ast_copy_string(vms.username, mailbox, sizeof(vms.username));
      vms.lastmsg = -1;
      open = 0;

      /* open the mailbox state */
      if ((res = open_mailbox(&vms, vmu, i)) < 0) {
         ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
         goto snapshot_cleanup;
      }
      open = 1;

      /* Iterate through each msg, storing off info */
      if (vms.lastmsg != -1) {
         if ((vm_msg_snapshot_create(vmu, &vms, mailbox_snapshot, msg_folder_index, i, descending, sort_val))) {
            ast_log(LOG_WARNING, "Failed to create msg snapshots for %s@%s\n", mailbox, context);
            goto snapshot_cleanup;
         }
      }

      /* close mailbox */
      if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
         goto snapshot_cleanup;
      }
      open = 0;
   }

snapshot_cleanup:
   if (vmu && open) {
      close_mailbox(&vms, vmu);
   }

#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif

   return mailbox_snapshot;
}
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_destroy ( struct ast_vm_mailbox_snapshot mailbox_snapshot) [static, read]

Definition at line 15098 of file app_voicemail.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_vm_mailbox_snapshot::folders, ast_vm_mailbox_snapshot::snapshots, and vm_msg_snapshot_destroy().

Referenced by load_module().

{
   int i;
   struct ast_vm_msg_snapshot *msg_snapshot;

   for (i = 0; i < mailbox_snapshot->folders; i++) {
      while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg))) {
         msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
      }
   }
   ast_free(mailbox_snapshot->snapshots);
   ast_free(mailbox_snapshot);
   return NULL;
}
static FILE* vm_mkftemp ( char *  template) [static]

Definition at line 1852 of file app_voicemail.c.

References VOICEMAIL_FILE_MODE.

Referenced by sendmail(), and sendpage().

{
   FILE *p = NULL;
   int pfd = mkstemp(template);
   chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
   if (pfd > -1) {
      p = fdopen(pfd, "w+");
      if (!p) {
         close(pfd);
         pfd = -1;
      }
   }
   return p;
}
static int vm_msg_forward ( const char *  from_mailbox,
const char *  from_context,
const char *  from_folder,
const char *  to_mailbox,
const char *  to_context,
const char *  to_folder,
size_t  num_msgs,
const char *  msg_ids[],
int  delete_old 
) [static]

Definition at line 15191 of file app_voicemail.c.

References ast_alloca, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log(), ast_strlen_zero(), ast_variable_retrieve(), close_mailbox(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, copy_message(), vm_state::curdir, vm_state::deleted, DISPOSE, ERROR_LOCK_PATH, find_user(), vm_state::fn, get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), message_range_and_existence_check(), notify_new_state(), open_mailbox(), RETRIEVE, vm_state::username, and value.

Referenced by load_module().

{
   struct vm_state from_vms;
   struct ast_vm_user *vmu = NULL, vmus;
   struct ast_vm_user *to_vmu = NULL, to_vmus;
   struct ast_config *msg_cfg;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
   char filename[PATH_MAX];
   int from_folder_index;
   int open = 0;
   int res = 0;
   int i;
   int *msg_nums;

   if (ast_strlen_zero(from_mailbox) || ast_strlen_zero(to_mailbox)) {
      ast_log(LOG_WARNING, "Cannot forward message because either the from or to mailbox was not specified\n");
      return -1;
   }

   if (!num_msgs) {
      ast_log(LOG_WARNING, "Invalid number of messages specified to forward: %zu\n", num_msgs);
      return -1;
   }

   if (ast_strlen_zero(from_folder) || ast_strlen_zero(to_folder)) {
      ast_log(LOG_WARNING, "Cannot forward message because the from_folder or to_folder was not specified\n");
      return -1;
   }

   memset(&vmus, 0, sizeof(vmus));
   memset(&to_vmus, 0, sizeof(to_vmus));
   memset(&from_vms, 0, sizeof(from_vms));

   from_folder_index = get_folder_by_name(from_folder);
   if (from_folder_index == -1) {
      return -1;
   }

   if (get_folder_by_name(to_folder) == -1) {
      return -1;
   }

   if (!(vmu = find_user(&vmus, from_context, from_mailbox))) {
      ast_log(LOG_WARNING, "Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
      return -1;
   }

   if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) {
      ast_log(LOG_WARNING, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
      return -1;
   }

   ast_copy_string(from_vms.username, from_mailbox, sizeof(from_vms.username));
   from_vms.lastmsg = -1;
   open = 0;

   /* open the mailbox state */
   if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
      ast_log(LOG_WARNING, "Could not open mailbox %s\n", from_mailbox);
      res = -1;
      goto vm_forward_cleanup;
   }

   open = 1;

   if ((from_vms.lastmsg + 1) < num_msgs) {
      ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", from_folder, num_msgs);
      res = -1;
      goto vm_forward_cleanup;
   }

   msg_nums = ast_alloca(sizeof(int) * num_msgs);

   if ((res = message_range_and_existence_check(&from_vms, msg_ids, num_msgs, msg_nums, vmu) < 0)) {
      goto vm_forward_cleanup;
   }

   /* Now we actually forward the messages */
   for (i = 0; i < num_msgs; i++) {
      int cur_msg = msg_nums[i];
      int duration = 0;
      const char *value;

      make_file(from_vms.fn, sizeof(from_vms.fn), from_vms.curdir, cur_msg);
      snprintf(filename, sizeof(filename), "%s.txt", from_vms.fn);
      RETRIEVE(from_vms.curdir, cur_msg, vmu->mailbox, vmu->context);
      msg_cfg = ast_config_load(filename, config_flags);
      /* XXX This likely will not fail since we previously ensured that the
       * message we are looking for exists. However, there still could be some
       * circumstance where this fails, so atomicity is not guaranteed.
       */
      if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
         DISPOSE(from_vms.curdir, cur_msg);
         continue;
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
         duration = atoi(value);
      }

      copy_message(NULL, vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir, "", to_folder);

      if (delete_old) {
         from_vms.deleted[cur_msg] = 1;
      }
      ast_config_destroy(msg_cfg);
      DISPOSE(from_vms.curdir, cur_msg);
   }

   /* close mailbox */
   if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH)) {
      res = -1;
      goto vm_forward_cleanup;
   }
   open = 0;

vm_forward_cleanup:
   if (vmu && open) {
      close_mailbox(&from_vms, vmu);
   }
#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&from_vms);
   }
#endif

   if (!res) {
      notify_new_state(to_vmu);
   }

   return res;
}
static int vm_msg_move ( const char *  mailbox,
const char *  context,
size_t  num_msgs,
const char *  oldfolder,
const char *  old_msg_ids[],
const char *  newfolder 
) [static]

Definition at line 15331 of file app_voicemail.c.

References ast_alloca, ast_copy_string(), ast_log(), ast_strlen_zero(), close_mailbox(), vm_state::deleted, ERROR_LOCK_PATH, find_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, message_range_and_existence_check(), notify_new_state(), open_mailbox(), save_to_folder(), and vm_state::username.

Referenced by load_module().

{
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   int old_folder_index;
   int new_folder_index;
   int open = 0;
   int res = 0;
   int i;
   int *old_msg_nums;

   if (ast_strlen_zero(mailbox)) {
      ast_log(LOG_WARNING, "Cannot move message because no mailbox was specified\n");
      return -1;
   }

   if (!num_msgs) {
      ast_log(LOG_WARNING, "Invalid number of messages specified to move: %zu\n", num_msgs);
      return -1;
   }

   if (ast_strlen_zero(oldfolder) || ast_strlen_zero(newfolder)) {
      ast_log(LOG_WARNING, "Cannot move message because either oldfolder or newfolder was not specified\n");
      return -1;
   }

   old_folder_index = get_folder_by_name(oldfolder);
   new_folder_index = get_folder_by_name(newfolder);

   memset(&vmus, 0, sizeof(vmus));
   memset(&vms, 0, sizeof(vms));

   if (old_folder_index == -1 || new_folder_index == -1) {
      return -1;
   }

   if (!(vmu = find_user(&vmus, context, mailbox))) {
      return -1;
   }

   ast_copy_string(vms.username, mailbox, sizeof(vms.username));
   vms.lastmsg = -1;
   open = 0;

   /* open the mailbox state */
   if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
      ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
      res = -1;
      goto vm_move_cleanup;
   }

   open = 1;

   if ((vms.lastmsg + 1) < num_msgs) {
      ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", oldfolder, num_msgs);
      res = -1;
      goto vm_move_cleanup;
   }

   old_msg_nums = ast_alloca(sizeof(int) * num_msgs);

   if ((res = message_range_and_existence_check(&vms, old_msg_ids, num_msgs, old_msg_nums, vmu)) < 0) {
      goto vm_move_cleanup;
   }

   /* Now actually move the message */
   for (i = 0; i < num_msgs; ++i) {
      if (save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, NULL, 0)) {
         res = -1;
         goto vm_move_cleanup;
      }
      vms.deleted[old_msg_nums[i]] = 1;
   }

   /* close mailbox */
   if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
      res = -1;
      goto vm_move_cleanup;
   }
   open = 0;

vm_move_cleanup:
   if (vmu && open) {
      close_mailbox(&vms, vmu);
   }
#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif

   if (!res) {
      notify_new_state(vmu);
   }

   return res;
}
static int vm_msg_play ( struct ast_channel chan,
const char *  mailbox,
const char *  context,
const char *  folder,
const char *  msg_num,
ast_vm_msg_play_cb  cb 
) [static]

Definition at line 15531 of file app_voicemail.c.

References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_fileexists(), ast_log(), AST_LOG_WARNING, ast_strlen_zero(), ast_variable_retrieve(), close_mailbox(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, find_user(), vm_state::fn, get_folder_by_name(), vm_state::heard, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), message_range_and_existence_check(), notify_new_state(), open_mailbox(), RETRIEVE, vm_state::username, value, and wait_file().

Referenced by load_module().

{
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   int res = 0;
   int open = 0;
   int i;
   char filename[PATH_MAX];
   struct ast_config *msg_cfg;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
   int duration = 0;
   const char *value;

   if (ast_strlen_zero(mailbox)) {
      ast_log(LOG_WARNING, "Cannot play message because no mailbox was specified\n");
      return -1;
   }

   if (ast_strlen_zero(folder)) {
      ast_log(LOG_WARNING, "Cannot play message because no folder was specified\n");
      return -1;
   }

   if (ast_strlen_zero(msg_id)) {
      ast_log(LOG_WARNING, "Cannot play message because no message number was specified\n");
      return -1;
   }

   memset(&vmus, 0, sizeof(vmus));
   memset(&vms, 0, sizeof(vms));

   if (ast_strlen_zero(context)) {
      context = "default";
   }

   if (!(vmu = find_user(&vmus, context, mailbox))) {
      return -1;
   }

   i = get_folder_by_name(folder);
   ast_copy_string(vms.username, mailbox, sizeof(vms.username));
   vms.lastmsg = -1;
   if ((res = open_mailbox(&vms, vmu, i)) < 0) {
      ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
      goto play2_msg_cleanup;
   }
   open = 1;

   if (message_range_and_existence_check(&vms, &msg_id, 1, &vms.curmsg, vmu)) {
      res = -1;
      goto play2_msg_cleanup;
   }

   /* Find the msg */
   make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
   snprintf(filename, sizeof(filename), "%s.txt", vms.fn);
   RETRIEVE(vms.curdir, vms.curmsg, vmu->mailbox, vmu->context);

   msg_cfg = ast_config_load(filename, config_flags);
   if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
      DISPOSE(vms.curdir, vms.curmsg);
      res = -1;
      goto play2_msg_cleanup;
   }
   if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
      duration = atoi(value);
   }
   ast_config_destroy(msg_cfg);

#ifdef IMAP_STORAGE
   /*IMAP storage stores any prepended message from a forward
    * as a separate file from the rest of the message
    */
   if (!ast_strlen_zero(vms.introfn) && ast_fileexists(vms.introfn, NULL, NULL) > 0) {
      wait_file(chan, &vms, vms.introfn);
   }
#endif
   if (cb) {
      cb(chan, vms.fn, duration);
   } else if ((wait_file(chan, &vms, vms.fn)) < 0) {
      ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms.fn);
   } else {
      res = 0;
   }

   vms.heard[vms.curmsg] = 1;

   /* cleanup configs and msg */
   DISPOSE(vms.curdir, vms.curmsg);

play2_msg_cleanup:
   if (vmu && open) {
      close_mailbox(&vms, vmu);
   }

#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif

   if (!res) {
      notify_new_state(vmu);
   }

   return res;
}
static int vm_msg_remove ( const char *  mailbox,
const char *  context,
size_t  num_msgs,
const char *  folder,
const char *  msgs[] 
) [static]

Definition at line 15434 of file app_voicemail.c.

References ast_alloca, ast_copy_string(), ast_log(), AST_LOG_ERROR, ast_strlen_zero(), close_mailbox(), vm_state::deleted, ERROR_LOCK_PATH, find_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, message_range_and_existence_check(), notify_new_state(), open_mailbox(), and vm_state::username.

Referenced by load_module().

{
   struct vm_state vms;
   struct ast_vm_user *vmu = NULL, vmus;
   int folder_index;
   int open = 0;
   int res = 0;
   int i;
   int *msg_nums;

   if (ast_strlen_zero(mailbox)) {
      ast_log(LOG_WARNING, "Cannot remove message because no mailbox was specified\n");
      return -1;
   }

   if (!num_msgs) {
      ast_log(LOG_WARNING, "Invalid number of messages specified to remove: %zu\n", num_msgs);
      return -1;
   }

   if (ast_strlen_zero(folder)) {
      ast_log(LOG_WARNING, "Cannot remove message because no folder was specified\n");
      return -1;
   }

   memset(&vmus, 0, sizeof(vmus));
   memset(&vms, 0, sizeof(vms));

   folder_index = get_folder_by_name(folder);
   if (folder_index == -1) {
      ast_log(LOG_WARNING, "Could not remove msgs from unknown folder %s\n", folder);
      return -1;
   }

   if (!(vmu = find_user(&vmus, context, mailbox))) {
      ast_log(LOG_WARNING, "Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
      return -1;
   }

   ast_copy_string(vms.username, mailbox, sizeof(vms.username));
   vms.lastmsg = -1;
   open = 0;

   /* open the mailbox state */
   if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
      ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
      res = -1;
      goto vm_remove_cleanup;
   }

   open = 1;

   if ((vms.lastmsg + 1) < num_msgs) {
      ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", folder, num_msgs);
      res = -1;
      goto vm_remove_cleanup;
   }

   msg_nums = ast_alloca(sizeof(int) * num_msgs);

   if ((res = message_range_and_existence_check(&vms, msgs, num_msgs, msg_nums, vmu)) < 0) {
      goto vm_remove_cleanup;
   }

   for (i = 0; i < num_msgs; i++) {
      vms.deleted[msg_nums[i]] = 1;
   }

   /* close mailbox */
   if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
      res = -1;
      ast_log(AST_LOG_ERROR, "Failed to close mailbox folder %s while removing msgs\n", folder);
      goto vm_remove_cleanup;
   }
   open = 0;

vm_remove_cleanup:
   if (vmu && open) {
      close_mailbox(&vms, vmu);
   }
#ifdef IMAP_STORAGE
   if (vmu) {
      vmstate_delete(&vms);
   }
#endif

   if (!res) {
      notify_new_state(vmu);
   }

   return res;
}
static struct ast_vm_msg_snapshot* vm_msg_snapshot_alloc ( void  ) [static, read]

Definition at line 14801 of file app_voicemail.c.

References ast_calloc, ast_free, and ast_string_field_init.

Referenced by vm_msg_snapshot_create().

{
   struct ast_vm_msg_snapshot *msg_snapshot;

   if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot)))) {
      return NULL;
   }

   if (ast_string_field_init(msg_snapshot, 512)) {
      ast_free(msg_snapshot);
      return NULL;
   }

   return msg_snapshot;
}
static int vm_msg_snapshot_create ( struct ast_vm_user vmu,
struct vm_state vms,
struct ast_vm_mailbox_snapshot mailbox_snapshot,
int  snapshot_index,
int  mailbox_index,
int  descending,
enum ast_vm_snapshot_sort_val  sort_val 
) [static]

Create and store off all the msgs in an open mailbox.

Note:
TODO XXX This function should work properly for all voicemail storage options, but is far more expensive for ODBC at the moment. This is because the RETRIEVE macro not only pulls out the message's meta data file from the database, but also the actual audio for each message, temporarily writing it to the file system. This is an area that needs to be made more efficient.

Definition at line 14869 of file app_voicemail.c.

References add_message_id(), ast_config_destroy(), ast_config_load, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_string_field_set, ast_variable_retrieve(), AST_VM_SNAPSHOT_SORT_BY_ID, AST_VM_SNAPSHOT_SORT_BY_TIME, CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, exten, vm_state::fn, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), MSG_ID_LEN, ast_vm_msg_snapshot::msg_number, ast_vm_msg_snapshot::origtime, RETRIEVE, ast_vm_mailbox_snapshot::snapshots, ast_vm_mailbox_snapshot::total_msg_num, value, and vm_msg_snapshot_alloc().

Referenced by vm_mailbox_snapshot_create().

{
   struct ast_vm_msg_snapshot *msg_snapshot;
   struct ast_vm_msg_snapshot *msg_snapshot_tmp;
   struct ast_config *msg_cfg;
   struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
   char filename[PATH_MAX];
   const char *value;

   for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
      int inserted = 0;
      /* Find the msg */
      make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
      snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
      RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
      msg_cfg = ast_config_load(filename, config_flags);
      if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
         DISPOSE(vms->curdir, vms->curmsg);
         continue;
      }

      /* Create the snapshot object */
      if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
         ast_config_destroy(msg_cfg);
         return -1;
      }

      /* Fill in the snapshot object */
      if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
         ast_string_field_set(msg_snapshot, msg_id, value);
      } else {
         /* Message snapshots *really* should have a
          * message ID. Add one to the message config
          * if it does not already exist
          */
         char id[MSG_ID_LEN];
         if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
                     filename, id, sizeof(id), vmu, mailbox_index))) {
            ast_string_field_set(msg_snapshot, msg_id, id);
         } else {
            ast_log(LOG_WARNING, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
         }
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
         ast_string_field_set(msg_snapshot, callerid, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
         ast_string_field_set(msg_snapshot, callerchan, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
         ast_string_field_set(msg_snapshot, exten, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
         ast_string_field_set(msg_snapshot, origdate, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
         ast_string_field_set(msg_snapshot, origtime, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
         ast_string_field_set(msg_snapshot, duration, value);
      }
      if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
         ast_string_field_set(msg_snapshot, flag, value);
      }
      msg_snapshot->msg_number = vms->curmsg;
      ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);

      /* store msg snapshot in mailbox snapshot */
      switch (sort_val) {
      default:
      case AST_VM_SNAPSHOT_SORT_BY_ID:
         if (descending) {
            AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
         } else {
            AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
         }
         inserted = 1;
         break;
      case AST_VM_SNAPSHOT_SORT_BY_TIME:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
            int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
            if (descending && val >= 0) {
               AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
               inserted = 1;
               break;
            } else if (!descending && val <= 0) {
               AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
               inserted = 1;
               break;
            }
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      }

      if (!inserted) {
         AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
      }

      mailbox_snapshot->total_msg_num++;

      /* cleanup configs and msg */
      ast_config_destroy(msg_cfg);
      DISPOSE(vms->curdir, vms->curmsg);
   }

   return 0;
}
static struct ast_vm_msg_snapshot* vm_msg_snapshot_destroy ( struct ast_vm_msg_snapshot msg_snapshot) [static, read]

Definition at line 14817 of file app_voicemail.c.

References ast_free, and ast_string_field_free_memory.

Referenced by vm_mailbox_snapshot_destroy().

{
   ast_string_field_free_memory(msg_snapshot);
   ast_free(msg_snapshot);

   return NULL;
}
static int vm_newuser ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
char *  fmtc,
signed char  record_gain 
) [static]

Definition at line 9975 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_debug, ast_fileexists(), ast_log(), AST_LOG_NOTICE, ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, check_password(), ast_vm_user::context, play_record_review(), PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, vm_state::username, vm_change_password(), vm_change_password_shell(), VM_FORCEGREET, and VM_FORCENAME.

Referenced by vm_execmain().

{
   int cmd = 0;
   int duration = 0;
   int tries = 0;
   char newpassword[80] = "";
   char newpassword2[80] = "";
   char prefile[PATH_MAX] = "";
   unsigned char buf[256];
   int bytes = 0;

   ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
   if (ast_adsi_available(chan)) {
      bytes += adsi_logo(buf + bytes);
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
      bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
      bytes += ast_adsi_voice_mode(buf + bytes, 0);
      ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
   }

   /* If forcename is set, have the user record their name */
   if (ast_test_flag(vmu, VM_FORCENAME)) {
      snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
      if (ast_fileexists(prefile, NULL, NULL) < 1) {
         cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         if (cmd < 0 || cmd == 't' || cmd == '#')
            return cmd;
      }
   }

   /* If forcegreetings is set, have the user record their greetings */
   if (ast_test_flag(vmu, VM_FORCEGREET)) {
      snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
      if (ast_fileexists(prefile, NULL, NULL) < 1) {
         cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         if (cmd < 0 || cmd == 't' || cmd == '#')
            return cmd;
      }

      snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
      if (ast_fileexists(prefile, NULL, NULL) < 1) {
         cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         if (cmd < 0 || cmd == 't' || cmd == '#')
            return cmd;
      }
   }

   /*
    * Change the password last since new users will be able to skip over any steps this one comes before
    * by hanging up and calling back to voicemail main since the password is used to verify new user status.
    */
   for (;;) {
      newpassword[1] = '\0';
      newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
      if (cmd == '#')
         newpassword[0] = '\0';
      if (cmd < 0 || cmd == 't' || cmd == '#')
         return cmd;
      cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
      if (cmd < 0 || cmd == 't' || cmd == '#')
         return cmd;
      cmd = check_password(vmu, newpassword); /* perform password validation */
      if (cmd != 0) {
         ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
         cmd = ast_play_and_wait(chan, vm_invalid_password);
      } else {
         newpassword2[1] = '\0';
         newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
         if (cmd == '#')
            newpassword2[0] = '\0';
         if (cmd < 0 || cmd == 't' || cmd == '#')
            return cmd;
         cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
         if (cmd < 0 || cmd == 't' || cmd == '#')
            return cmd;
         if (!strcmp(newpassword, newpassword2))
            break;
         ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
         cmd = ast_play_and_wait(chan, vm_mismatch);
      }
      if (++tries == 3)
         return -1;
      if (cmd != 0) {
         cmd = ast_play_and_wait(chan, vm_pls_try_again);
      }
   }
   if (pwdchange & PWDCHANGE_INTERNAL)
      vm_change_password(vmu, newpassword);
   if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
      vm_change_password_shell(vmu, newpassword);

   ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
   cmd = ast_play_and_wait(chan, vm_passchanged);

   return cmd;
}
static int vm_options ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
char *  fmtc,
signed char  record_gain 
) [static]

Definition at line 10073 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_debug, ast_fileexists(), ast_log(), AST_LOG_NOTICE, ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_test_suite_event_notify, ast_waitfordigit(), check_password(), ast_vm_user::context, DISPOSE, ast_vm_user::mailbox, ast_vm_user::password, play_record_review(), PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, RETRIEVE, vm_state::username, vm_change_password(), vm_change_password_shell(), and vm_tempgreeting().

Referenced by vm_execmain().

{
   int cmd = 0;
   int retries = 0;
   int duration = 0;
   char newpassword[80] = "";
   char newpassword2[80] = "";
   char prefile[PATH_MAX] = "";
   unsigned char buf[256];
   int bytes = 0;

   ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
   if (ast_adsi_available(chan)) {
      bytes += adsi_logo(buf + bytes);
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
      bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
      bytes += ast_adsi_voice_mode(buf + bytes, 0);
      ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
   }
   while ((cmd >= 0) && (cmd != 't')) {
      if (cmd)
         retries = 0;
      switch (cmd) {
      case '1': /* Record your unavailable message */
         snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
         cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         break;
      case '2':  /* Record your busy message */
         snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
         cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         break;
      case '3': /* Record greeting */
         snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
         cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         break;
      case '4':  /* manage the temporary greeting */
         cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
         break;
      case '5': /* change password */
         if (vmu->password[0] == '-') {
            cmd = ast_play_and_wait(chan, "vm-no");
            break;
         }
         newpassword[1] = '\0';
         newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
         if (cmd == '#')
            newpassword[0] = '\0';
         else {
            if (cmd < 0)
               break;
            if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
               break;
            }
         }
         cmd = check_password(vmu, newpassword); /* perform password validation */
         if (cmd != 0) {
            ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
            cmd = ast_play_and_wait(chan, vm_invalid_password);
            if (!cmd) {
               cmd = ast_play_and_wait(chan, vm_pls_try_again);
            }
            break;
         }
         newpassword2[1] = '\0';
         newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
         if (cmd == '#')
            newpassword2[0] = '\0';
         else {
            if (cmd < 0)
               break;

            if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
               break;
            }
         }
         if (strcmp(newpassword, newpassword2)) {
            ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
            cmd = ast_play_and_wait(chan, vm_mismatch);
            if (!cmd) {
               cmd = ast_play_and_wait(chan, vm_pls_try_again);
            }
            break;
         }

         if (pwdchange & PWDCHANGE_INTERNAL) {
            vm_change_password(vmu, newpassword);
         }
         if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
            vm_change_password_shell(vmu, newpassword);
         }

         ast_debug(1, "User %s set password to %s of length %d\n",
            vms->username, newpassword, (int) strlen(newpassword));
         cmd = ast_play_and_wait(chan, vm_passchanged);
         break;
      case '*':
         cmd = 't';
         break;
      default:
         cmd = 0;
         snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
         RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
         if (ast_fileexists(prefile, NULL, NULL)) {
            cmd = ast_play_and_wait(chan, "vm-tmpexists");
         }
         DISPOSE(prefile, -1);
         if (!cmd) {
            cmd = ast_play_and_wait(chan, "vm-options");
         }
         if (!cmd) {
            cmd = ast_waitfordigit(chan, 6000);
         }
         if (!cmd) {
            retries++;
         }
         if (retries > 3) {
            cmd = 't';
         }
         ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
      }
   }
   if (cmd == 't')
      cmd = 0;
   return cmd;
}
static int vm_play_folder_name ( struct ast_channel chan,
char *  mbox 
) [static]

Definition at line 8868 of file app_voicemail.c.

References ast_channel_language(), ast_play_and_wait(), vm_play_folder_name_gr(), vm_play_folder_name_pl(), and vm_play_folder_name_ua().

Referenced by get_folder(), vm_execmain(), vm_instructions_en(), and vm_instructions_zh().

{
   int cmd;

   if (  !strncasecmp(ast_channel_language(chan), "it", 2) ||
        !strncasecmp(ast_channel_language(chan), "es", 2) ||
        !strncasecmp(ast_channel_language(chan), "pt", 2)) { /* Italian, Spanish, or Portuguese syntax */
      cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
      return cmd ? cmd : ast_play_and_wait(chan, box);
   } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
      return vm_play_folder_name_gr(chan, box);
   } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {  /* Hebrew syntax */
      return ast_play_and_wait(chan, box);
   } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
      return vm_play_folder_name_pl(chan, box);
   } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {  /* Ukrainian syntax */
      return vm_play_folder_name_ua(chan, box);
   } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
      return ast_play_and_wait(chan, box);
   } else {  /* Default English */
      cmd = ast_play_and_wait(chan, box);
      return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages */
   }
}
static int vm_play_folder_name_gr ( struct ast_channel chan,
char *  box 
) [static]

Definition at line 8821 of file app_voicemail.c.

References ast_alloca, and ast_play_and_wait().

Referenced by vm_play_folder_name().

{
   int cmd;
   char *buf;

   buf = ast_alloca(strlen(box) + 2);
   strcpy(buf, box);
   strcat(buf, "s");

   if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
      cmd = ast_play_and_wait(chan, buf); /* "NEA / PALIA" */
      return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
   } else {
      cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
      return cmd ? cmd : ast_play_and_wait(chan, box); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
   }
}
static int vm_play_folder_name_pl ( struct ast_channel chan,
char *  box 
) [static]

Definition at line 8839 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_play_folder_name().

{
   int cmd;

   if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
      if (!strcasecmp(box, "vm-INBOX"))
         cmd = ast_play_and_wait(chan, "vm-new-e");
      else
         cmd = ast_play_and_wait(chan, "vm-old-e");
      return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
   } else {
      cmd = ast_play_and_wait(chan, "vm-messages");
      return cmd ? cmd : ast_play_and_wait(chan, box);
   }
}
static int vm_play_folder_name_ua ( struct ast_channel chan,
char *  box 
) [static]

Definition at line 8855 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_play_folder_name().

{
   int cmd;

   if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
      cmd = ast_play_and_wait(chan, "vm-messages");
      return cmd ? cmd : ast_play_and_wait(chan, box);
   } else {
      cmd = ast_play_and_wait(chan, box);
      return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
   }
}
static int vm_playmsgexec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 10752 of file app_voicemail.c.

References args, ast_answer(), AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strlen_zero(), parse(), pbx_builtin_setvar_helper(), and play_message_by_id().

Referenced by load_module().

{
   char *parse;
   char *mailbox = NULL;
   char *context = NULL;
   int res;

   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(mailbox);
      AST_APP_ARG(msg_id);
   );

   if (ast_channel_state(chan) != AST_STATE_UP) {
      ast_debug(1, "Before ast_answer\n");
      ast_answer(chan);
   }

   if (ast_strlen_zero(data)) {
      return -1;
   }

   parse = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, parse);

   if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
      return -1;
   }

   if ((context = strchr(args.mailbox, '@'))) {
      *context++ = '\0';
   }
   mailbox = args.mailbox;

   res = play_message_by_id(chan, mailbox, context, args.msg_id);
   pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");

   return 0;
}
static int vm_tempgreeting ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
char *  fmtc,
signed char  record_gain 
) [static]

The handler for 'record a temporary greeting'.

Parameters:
chan
vmu
vms
fmtc
record_gainThis is option 4 from the mailbox options menu. This function manages the following promptings: 1: play / record / review the temporary greeting. : invokes play_record_review(). 2: remove (delete) the temporary greeting. *: return to the main menu.
Returns:
zero on success, -1 on error.

Definition at line 10216 of file app_voicemail.c.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_fileexists(), ast_play_and_wait(), ast_test_suite_event_notify, ast_waitfordigit(), ast_vm_user::context, DELETE, DISPOSE, ast_vm_user::mailbox, play_record_review(), RETRIEVE, and vm_state::username.

Referenced by vm_options().

{
   int cmd = 0;
   int retries = 0;
   int duration = 0;
   char prefile[PATH_MAX] = "";
   unsigned char buf[256];
   int bytes = 0;

   if (ast_adsi_available(chan)) {
      bytes += adsi_logo(buf + bytes);
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
      bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
      bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
      bytes += ast_adsi_voice_mode(buf + bytes, 0);
      ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
   }

   ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
   snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
   while ((cmd >= 0) && (cmd != 't')) {
      if (cmd)
         retries = 0;
      RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
      if (ast_fileexists(prefile, NULL, NULL) <= 0) {
         cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
         if (cmd == -1) {
            break;
         }
         cmd = 't';  
      } else {
         switch (cmd) {
         case '1':
            cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
            break;
         case '2':
            DELETE(prefile, -1, prefile, vmu);
            ast_play_and_wait(chan, "vm-tempremoved");
            cmd = 't';  
            break;
         case '*': 
            cmd = 't';
            break;
         default:
            cmd = ast_play_and_wait(chan,
               ast_fileexists(prefile, NULL, NULL) > 0 ? /* XXX always true ? */
                  "vm-tempgreeting2" : "vm-tempgreeting");
            if (!cmd) {
               cmd = ast_waitfordigit(chan, 6000);
            }
            if (!cmd) {
               retries++;
            }
            if (retries > 3) {
               cmd = 't';
            }
            ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
         }
      }
      DISPOSE(prefile, -1);
   }
   if (cmd == 't')
      cmd = 0;
   return cmd;
}
static int vm_users_data_provider_get ( const struct ast_data_search search,
struct ast_data data_root 
) [static]
static int vm_users_data_provider_get_helper ( const struct ast_data_search search,
struct ast_data data_root,
struct ast_vm_user user 
) [static]

Definition at line 12396 of file app_voicemail.c.

References ast_data_add_int(), ast_data_add_node(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_vm_user::context, inboxcount2(), ast_vm_user::mailbox, vm_zone::name, and ast_vm_user::zonetag.

Referenced by vm_users_data_provider_get().

{
   struct ast_data *data_user, *data_zone;
   struct ast_data *data_state;
   struct vm_zone *zone = NULL;
   int urgentmsg = 0, newmsg = 0, oldmsg = 0;
   char ext_context[256] = "";

   data_user = ast_data_add_node(data_root, "user");
   if (!data_user) {
      return -1;
   }

   ast_data_add_structure(ast_vm_user, data_user, user);

   AST_LIST_LOCK(&zones);
   AST_LIST_TRAVERSE(&zones, zone, list) {
      if (!strcmp(zone->name, user->zonetag)) {
         break;
      }
   }
   AST_LIST_UNLOCK(&zones);

   /* state */
   data_state = ast_data_add_node(data_user, "state");
   if (!data_state) {
      return -1;
   }
   snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
   inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
   ast_data_add_int(data_state, "urgentmsg", urgentmsg);
   ast_data_add_int(data_state, "newmsg", newmsg);
   ast_data_add_int(data_state, "oldmsg", oldmsg);

   if (zone) {
      data_zone = ast_data_add_node(data_user, "zone");
      ast_data_add_structure(vm_zone, data_zone, zone);
   }

   if (!ast_data_search_match(search, data_user)) {
      ast_data_remove_node(data_root, data_user);
   }

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

Definition at line 12082 of file app_voicemail.c.

References ast_channel_context(), ast_copy_string(), ast_goto_if_exists(), AST_MAX_EXTENSION, ast_play_and_wait(), ast_strlen_zero(), ast_vm_user::context, pbx_builtin_setvar_helper(), user, and vm_authenticate().

Referenced by load_module().

{
   char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
   struct ast_vm_user vmus;
   char *options = NULL;
   int silent = 0, skipuser = 0;
   int res = -1;
   
   if (data) {
      s = ast_strdupa(data);
      user = strsep(&s, ",");
      options = strsep(&s, ",");
      if (user) {
         s = user;
         user = strsep(&s, "@");
         context = strsep(&s, "");
         if (!ast_strlen_zero(user))
            skipuser++;
         ast_copy_string(mailbox, user, sizeof(mailbox));
      }
   }

   if (options) {
      silent = (strchr(options, 's')) != NULL;
   }

   if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
      pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
      pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
      ast_play_and_wait(chan, "auth-thankyou");
      res = 0;
   } else if (mailbox[0] == '*') {
      /* user entered '*' */
      if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
         res = 0; /* prevent hangup */
      }
   }

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

Definition at line 13629 of file app_voicemail.c.

References ast_channel_language(), ast_debug, AST_DIGIT_ANY, ast_log(), ast_say_character_str(), ast_stream_and_wait(), ast_strlen_zero(), context, LOG_WARNING, and sayname().

Referenced by load_module().

{
   char *context;
   char *args_copy;
   int res;

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
      return -1;
   }

   args_copy = ast_strdupa(data);
   if ((context = strchr(args_copy, '@'))) {
      *context++ = '\0';
   } else {
      context = "default";
   }

   if ((res = sayname(chan, args_copy, context)) < 0) {
      ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
      res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
      if (!res) {
         res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan));
      }
   }

   return res;
}
static struct ast_tm* vmu_tm ( const struct ast_vm_user vmu,
struct ast_tm tm 
) [static, read]

fill in *tm for current time according to the proper timezone, if any.

Returns:
tm so it can be used as a function argument.

Definition at line 4740 of file app_voicemail.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_strlen_zero(), ast_tvnow(), vm_zone::name, vm_zone::timezone, and ast_vm_user::zonetag.

Referenced by make_email_file(), and sendpage().

{
   const struct vm_zone *z = NULL;
   struct timeval t = ast_tvnow();

   /* Does this user have a timezone specified? */
   if (!ast_strlen_zero(vmu->zonetag)) {
      /* Find the zone in the list */
      AST_LIST_LOCK(&zones);
      AST_LIST_TRAVERSE(&zones, z, list) {
         if (!strcmp(z->name, vmu->zonetag))
            break;
      }
      AST_LIST_UNLOCK(&zones);
   }
   ast_localtime(&t, tm, z ? z->timezone : NULL);
   return tm;
}
static int wait_file ( struct ast_channel chan,
struct vm_state vms,
char *  file 
) [static]
static int wait_file2 ( struct ast_channel chan,
struct vm_state vms,
char *  file 
) [static]

Definition at line 8196 of file app_voicemail.c.

References AST_DIGIT_ANY, ast_log(), AST_LOG_WARNING, and ast_stream_and_wait().

Referenced by play_message(), play_message_callerid(), and play_message_duration().

{
   int res;
   if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0) 
      ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file); 
   return res;
}
static int write_password_to_file ( const char *  secretfn,
const char *  password 
) [static]

Definition at line 13596 of file app_voicemail.c.

References ast_category_append(), ast_category_destroy(), ast_category_new(), ast_config_destroy(), ast_config_new(), ast_config_text_file_save(), ast_log(), ast_variable_append(), ast_variable_new(), LOG_ERROR, and var.

Referenced by vm_change_password().

                                                                              {
   struct ast_config *conf;
   struct ast_category *cat;
   struct ast_variable *var;
   int res = -1;

   if (!(conf = ast_config_new())) {
      ast_log(LOG_ERROR, "Error creating new config structure\n");
      return res;
   }
   if (!(cat = ast_category_new("general", "", 1))) {
      ast_log(LOG_ERROR, "Error creating new category structure\n");
      ast_config_destroy(conf);
      return res;
   }
   if (!(var = ast_variable_new("password", password, ""))) {
      ast_log(LOG_ERROR, "Error creating new variable structure\n");
      ast_config_destroy(conf);
      ast_category_destroy(cat);
      return res;
   }
   ast_category_append(conf, cat);
   ast_variable_append(cat, var);
   if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
      res = 0;
   } else {
      ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
   }

   ast_config_destroy(conf);
   return res;
}

Variable Documentation

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, .nonoptreq = "res_adsi,res_smdi", } [static]

Definition at line 15653 of file app_voicemail.c.

char* addesc = "Comedian Mail" [static]

Definition at line 890 of file app_voicemail.c.

unsigned char adsifdn[4] = "\x00\x00\x00\x0F" [static]

Definition at line 1019 of file app_voicemail.c.

unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC" [static]

Definition at line 1020 of file app_voicemail.c.

int adsiver = 1 [static]

Definition at line 1021 of file app_voicemail.c.

char* app = "VoiceMail" [static]

Definition at line 893 of file app_voicemail.c.

char* app2 = "VoiceMailMain" [static]

Definition at line 896 of file app_voicemail.c.

char* app3 = "MailboxExists" [static]

Definition at line 898 of file app_voicemail.c.

char* app4 = "VMAuthenticate" [static]

Definition at line 899 of file app_voicemail.c.

Definition at line 15653 of file app_voicemail.c.

char callcontext[AST_MAX_CONTEXT] = "" [static]

Definition at line 1005 of file app_voicemail.c.

char charset[32] = "ISO-8859-1" [static]

Definition at line 1017 of file app_voicemail.c.

Definition at line 1008 of file app_voicemail.c.

struct ast_cli_entry cli_voicemail[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
   AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
   AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
}

Definition at line 12321 of file app_voicemail.c.

char dialcontext[AST_MAX_CONTEXT] = "" [static]

Definition at line 1004 of file app_voicemail.c.

Referenced by directory_exec().

char* emailbody = NULL [static]

Definition at line 1011 of file app_voicemail.c.

Referenced by make_email_file(), and message_template_parse_emailbody().

char emaildateformat[32] = "%A, %B %d, %Y at %r" [static]

Definition at line 1022 of file app_voicemail.c.

char* emailsubject = NULL [static]

Definition at line 1012 of file app_voicemail.c.

Referenced by make_email_file().

char exitcontext[AST_MAX_CONTEXT] = "" [static]

Definition at line 1006 of file app_voicemail.c.

Referenced by common_exec(), and conf_run().

char ext_pass_check_cmd[128] [static]

Definition at line 870 of file app_voicemail.c.

char ext_pass_cmd[128] [static]

Definition at line 869 of file app_voicemail.c.

char externnotify[160] [static]

Definition at line 915 of file app_voicemail.c.

char fromstring[100] [static]

Definition at line 1015 of file app_voicemail.c.

struct ast_flags globalflags = {0} [static]

Definition at line 1000 of file app_voicemail.c.

Definition at line 1073 of file app_voicemail.c.

char listen_control_forward_key[12] [static]

Definition at line 973 of file app_voicemail.c.

char listen_control_pause_key[12] [static]

Definition at line 975 of file app_voicemail.c.

char listen_control_restart_key[12] [static]

Definition at line 976 of file app_voicemail.c.

char listen_control_reverse_key[12] [static]

Definition at line 974 of file app_voicemail.c.

char listen_control_stop_key[12] [static]

Definition at line 977 of file app_voicemail.c.

char locale[20] [static]

Definition at line 908 of file app_voicemail.c.

Initial value:
 {
   .name = "MAILBOX_EXISTS",
   .read = acf_mailbox_exists,
}

Definition at line 12072 of file app_voicemail.c.

const char* const mailbox_folders[] [static]

Definition at line 628 of file app_voicemail.c.

char mailcmd[160] [static]

Definition at line 914 of file app_voicemail.c.

int maxdeletedmsg [static]

Definition at line 911 of file app_voicemail.c.

Referenced by populate_defaults().

int maxgreet [static]

Definition at line 921 of file app_voicemail.c.

int maxlogins [static]

Definition at line 923 of file app_voicemail.c.

int maxmsg [static]

Definition at line 910 of file app_voicemail.c.

Referenced by populate_defaults().

int maxsilence [static]

Definition at line 909 of file app_voicemail.c.

Referenced by ast_record_review().

int minpassword [static]

Definition at line 924 of file app_voicemail.c.

int msg_id_incrementor [static]

Definition at line 3549 of file app_voicemail.c.

struct ast_event_sub* mwi_sub_sub [static]

Subscription to ... MWI event subscriptions

Definition at line 942 of file app_voicemail.c.

struct mwi_subs mwi_subs [static]

Definition at line 968 of file app_voicemail.c.

struct ast_event_sub* mwi_unsub_sub [static]

Subscription to ... MWI event un-subscriptions

Definition at line 944 of file app_voicemail.c.

int my_umask [static]

Definition at line 872 of file app_voicemail.c.

char* pagerbody = NULL [static]

Definition at line 1013 of file app_voicemail.c.

char pagerdateformat[32] = "%A, %B %d, %Y at %r" [static]

Definition at line 1023 of file app_voicemail.c.

char pagerfromstring[100] [static]

Definition at line 1016 of file app_voicemail.c.

char* pagersubject = NULL [static]

Definition at line 1014 of file app_voicemail.c.

int passwordlocation [static]

Definition at line 925 of file app_voicemail.c.

Referenced by populate_defaults().

char* playmsg_app = "VoiceMailPlayMsg" [static]

Definition at line 901 of file app_voicemail.c.

ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER [static]

Definition at line 937 of file app_voicemail.c.

unsigned int poll_freq [static]

Polling frequency

Definition at line 932 of file app_voicemail.c.

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

Definition at line 936 of file app_voicemail.c.

Referenced by mb_poll_thread(), and stop_poll_thread().

unsigned int poll_mailboxes [static]

Poll mailboxes for changes since there is something external to app_voicemail that may change them.

Definition at line 929 of file app_voicemail.c.

pthread_t poll_thread = AST_PTHREADT_NULL [static]

Definition at line 938 of file app_voicemail.c.

unsigned char poll_thread_run [static]

Definition at line 939 of file app_voicemail.c.

int pwdchange = PWDCHANGE_INTERNAL [static]

Definition at line 876 of file app_voicemail.c.

int saydurationminfo [static]

Definition at line 1002 of file app_voicemail.c.

Referenced by populate_defaults().

char* sayname_app = "VMSayName" [static]

Definition at line 903 of file app_voicemail.c.

char serveremail[80] [static]

Definition at line 913 of file app_voicemail.c.

Referenced by forward_message(), and notify_new_message().

int silencethreshold = 128 [static]

Definition at line 912 of file app_voicemail.c.

Referenced by ast_record_review(), and setup_privacy_args().

int skipms [static]

Definition at line 922 of file app_voicemail.c.

Referenced by controlplayback_exec(), and handle_controlstreamfile().

struct ast_smdi_interface* smdi_iface = NULL [static]

Definition at line 916 of file app_voicemail.c.

struct users users [static]
char userscontext[AST_MAX_EXTENSION] = "default" [static]

Definition at line 888 of file app_voicemail.c.

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]

Definition at line 626 of file app_voicemail.c.

Referenced by vm_exec(), and vm_execmain().

struct ast_data_entry vm_data_providers[] [static]
Initial value:
 {

}

Definition at line 12462 of file app_voicemail.c.

Initial value:
 {
   .name = "VM_INFO",
   .read = acf_vm_info,
}

Definition at line 12077 of file app_voicemail.c.

char vm_invalid_password[80] = "vm-invalid-password" [static]

Definition at line 985 of file app_voicemail.c.

char vm_mismatch[80] = "vm-mismatch" [static]

Definition at line 984 of file app_voicemail.c.

char vm_newpassword[80] = "vm-newpassword" [static]

Definition at line 981 of file app_voicemail.c.

char vm_passchanged[80] = "vm-passchanged" [static]

Definition at line 982 of file app_voicemail.c.

char vm_password[80] = "vm-password" [static]

Definition at line 980 of file app_voicemail.c.

char vm_pls_try_again[80] = "vm-pls-try-again" [static]

Definition at line 986 of file app_voicemail.c.

char vm_prepend_timeout[80] = "vm-then-pound" [static]

Definition at line 998 of file app_voicemail.c.

char vm_reenterpassword[80] = "vm-reenterpassword" [static]

Definition at line 983 of file app_voicemail.c.

char VM_SPOOL_DIR[PATH_MAX] [static]

Definition at line 867 of file app_voicemail.c.

Initial value:

Definition at line 12457 of file app_voicemail.c.

char vmfmts[80] [static]

Definition at line 917 of file app_voicemail.c.

int vmmaxsecs [static]

Definition at line 920 of file app_voicemail.c.

Referenced by apply_option(), and populate_defaults().

int vmminsecs [static]

Definition at line 919 of file app_voicemail.c.

Referenced by apply_option(), and populate_defaults().

double volgain [static]

Definition at line 918 of file app_voicemail.c.

Referenced by populate_defaults().

struct zones zones [static]
char zonetag[80] [static]

Definition at line 907 of file app_voicemail.c.

Referenced by build_peer().