Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
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/mwi.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/taskprocessor.h"
#include "asterisk/test.h"
#include "asterisk/format_cache.h"

Go to the source code of this file.

Data Structures

struct  alias_mailbox_mapping
 
struct  ast_vm_user
 
struct  inprocess
 
struct  leave_vm_options
 Options for leaving voicemail with the voicemail() application. More...
 
struct  mailbox_alias_mapping
 
struct  users
 list of users found in the config file More...
 
struct  vm_state
 
struct  vm_zone
 
struct  zones
 

Macros

#define ALIASES_OUTPUT_FORMAT   "%-32s %-32s\n"
 
#define ASTERISK_USERNAME   "asterisk"
 
#define CHUNKSIZE   65536
 
#define COMMAND_TIMEOUT   5000
 
#define COPY(a, b, c, d, e, f, g, h)   (copy_plain_file(g,h));
 
#define COUNT(a, b)   count_messages(a,b)
 
#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 ERROR_MAX_MSGS   -101
 
#define EXISTS(a, b, c, d)   (ast_fileexists(c,NULL,d) > 0)
 
#define force_reload_config()   load_config_force(1, 1)
 Forcibly reload voicemail.conf, even if it has not changed. This is necessary after running unit tests.
 
#define HVSU_OUTPUT_FORMAT   "%-10s %-5s %-25s %-10s %6s\n"
 
#define HVSZ_OUTPUT_FORMAT   "%-15s %-20s %-45s\n"
 
#define INTRO   "vm-intro"
 
#define LAST_MSG_INDEX(a)   last_message_index(a)
 
#define MAPPING_BUCKETS   511
 
#define MAX_DATETIME_FORMAT   512
 
#define MAX_MAIL_BODY_CONTENT_SIZE   134217728L
 
#define MAX_NUM_CID_CONTEXTS   10
 
#define MAX_VM_CONTEXT_LEN   (AST_MAX_CONTEXT)
 
#define MAX_VM_MAILBOX_LEN   (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
 
#define MAX_VM_MBOX_ID_LEN   (AST_MAX_EXTENSION)
 
#define MAXMSG   100
 
#define MAXMSGLIMIT   9999
 
#define MINPASSWORD   0
 
#define MSG_ID_LEN   256
 
#define MSGFILE_LEN   (7)
 
#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_DIRECTFORWARD   (1 << 10)
 
#define VM_EMAIL_EXT_RECS   (1 << 19)
 
#define VM_ENVELOPE   (1 << 4)
 
#define VM_FORCEGREET   (1 << 8)
 
#define VM_FORCENAME   (1 << 7)
 
#define VM_FWDURGAUTO   (1 << 18)
 
#define VM_MARK_URGENT   (1 << 20)
 
#define VM_MESSAGEWRAP   (1 << 17)
 
#define VM_MOVEHEARD   (1 << 16)
 
#define VM_ODBC_AUDIO_ON_DISK   (1 << 21)
 
#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_STRING_HEADER_FORMAT   "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
 
#define VM_SVMAIL   (1 << 3)
 
#define VM_TEMPGREETWARN   (1 << 15)
 
#define VMBOX_STRING_DATA_FORMAT   "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
 
#define VMBOX_STRING_HEADER_FORMAT   "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
 
#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 = 0, OLD_FOLDER = 1, WORK_FOLDER = 2, FAMILY_FOLDER = 3,
  FRIENDS_FOLDER = 4, GREETINGS_FOLDER = -1
}
 
enum  vm_option_args {
  OPT_ARG_RECORDGAIN = 0, OPT_ARG_PLAYFOLDER = 1, OPT_ARG_DTMFEXIT = 2, OPT_ARG_BEEP_TONE = 3,
  OPT_ARG_ARRAY_SIZE = 4
}
 
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), OPT_EARLYM_GREETING = (1 << 10), OPT_BEEP = (1 << 11), OPT_SILENT_IF_GREET = (1 << 12),
  OPT_READONLY = (1 << 13)
}
 
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_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. More...
 
static struct alias_mailbox_mappingalias_mailbox_mapping_create (const char *alias, const char *mailbox)
 
 AO2_STRING_FIELD_CMP_FN (alias_mailbox_mapping, alias)
 
 AO2_STRING_FIELD_CMP_FN (mailbox_alias_mapping, mailbox)
 
 AO2_STRING_FIELD_HASH_FN (alias_mailbox_mapping, alias)
 
 AO2_STRING_FIELD_HASH_FN (mailbox_alias_mapping, mailbox)
 
static int append_mailbox (const char *context, const char *box, const char *data)
 
static int append_vmbox_info_astman (struct mansession *s, const struct message *m, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
 Append vmbox info string into given astman with event_name. More...
 
static int append_vmu_info_astman (struct mansession *s, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
 Append vmu info string into given astman with event_name. More...
 
static void apply_option (struct ast_vm_user *vmu, const char *var, const char *value)
 Sets a specific property value. More...
 
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. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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. More...
 
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. More...
 
static int change_password_realtime (struct ast_vm_user *vmu, const char *password)
 Performs a change of the voicemail passowrd in the realtime engine. More...
 
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. More...
 
static int close_mailbox (struct vm_state *vms, struct ast_vm_user *vmu)
 
static char * complete_voicemail_move_message (struct ast_cli_args *a, int maxpos)
 
static char * complete_voicemail_show_mailbox (struct ast_cli_args *a)
 
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. More...
 
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. More...
 
static void copy_plain_file (char *frompath, char *topath)
 Copies a voicemail information (envelope) file. More...
 
static int count_messages (struct ast_vm_user *vmu, char *dir)
 Find all .txt files - even if they are not in sequence from 0000. More...
 
static int create_dirpath (char *dest, int len, const char *context, const char *ext, const char *folder)
 basically mkdir -p $dest/$context/$ext/$folder More...
 
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. More...
 
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. More...
 
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. More...
 
static int forward_message_from_mailbox (struct ast_cli_args *a)
 
static void free_user (struct ast_vm_user *vmu)
 
static void free_user_final (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. More...
 
static int get_date (char *s, int len)
 Gets the current date and time, as formatted string. More...
 
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. More...
 
static int get_folder_by_name (const char *name)
 
static int get_folder_ja (struct ast_channel *chan, int start)
 
static char * handle_voicemail_forward_message (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_voicemail_move_message (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
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_remove_message (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_voicemail_show_aliases (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show a list of voicemail zones in the CLI.
 
static char * handle_voicemail_show_mailbox (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
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. More...
 
static int inboxcount (const char *mailbox, int *newmsgs, int *oldmsgs)
 
static int inboxcount2 (const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
 Check the given mailbox's message count. More...
 
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. More...
 
static int last_message_index (char *dir)
 Determines the highest message number in use for a given user and mailbox folder. More...
 
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. More...
 
static void load_aliases (struct ast_config *cfg)
 
static int load_config (int reload)
 
static int load_config_force (int reload, int force)
 Reload voicemail.conf. More...
 
static int load_module (void)
 Load the module. More...
 
static void load_users (struct ast_config *cfg)
 
static void load_zonemessages (struct ast_config *cfg)
 
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. More...
 
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. More...
 
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. More...
 
static int manager_get_mailbox_summary (struct mansession *s, const struct message *m)
 
static int manager_list_voicemail_users (struct mansession *s, const struct message *m)
 Manager list voicemail users command.
 
static int manager_match_mailbox (struct ast_mwi_state *mwi_state, void *data)
 
static int manager_status_voicemail_user (struct mansession *s, const struct message *m)
 
static int manager_voicemail_forward (struct mansession *s, const struct message *m)
 
static int manager_voicemail_move (struct mansession *s, const struct message *m)
 
static int manager_voicemail_refresh (struct mansession *s, const struct message *m)
 
static int manager_voicemail_remove (struct mansession *s, const struct message *m)
 
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. More...
 
static int messagecount (const char *mailbox_id, const char *folder)
 
static int move_message_from_mailbox (struct ast_cli_args *a)
 
static int msg_create_from_file (struct ast_vm_recording_data *recdata)
 
static void mwi_handle_subscribe (const char *id, struct ast_mwi_subscriber *sub)
 
static int mwi_handle_subscribe2 (void *data)
 
static void mwi_handle_unsubscribe (const char *id, struct ast_mwi_subscriber *sub)
 
static int mwi_handle_unsubscribe2 (void *data)
 
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. More...
 
static void notify_new_state (struct ast_vm_user *vmu)
 
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. More...
 
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, int forwardintro)
 
static int poll_subscribed_mailbox (struct ast_mwi_state *mwi_state, void *data)
 
static void populate_defaults (struct ast_vm_user *vmu)
 Sets default voicemail system options to a voicemail user. More...
 
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 print_mappings (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void queue_mwi_event (const char *channel_id, 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 int remove_message_from_mailbox (struct ast_cli_args *a)
 
static void rename_file (char *sfn, char *dfn)
 Renames a message in a mailbox folder. More...
 
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. More...
 
static void run_externnotify (const char *context, const 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 int separate_mailbox (char *mailbox_id, char **mailbox, char **context)
 
static int show_mailbox_details (struct ast_cli_args *a)
 
static int show_mailbox_snapshot (struct ast_cli_args *a)
 
static int show_messages_for_mailbox (struct ast_cli_args *a)
 
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. More...
 
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_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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static int vm_browse_messages_ja (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Japanese syntax for 'You have N messages' greeting. More...
 
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. More...
 
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. More...
 
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. More...
 
static void vm_change_password (struct ast_vm_user *vmu, const char *newpassword)
 The handler for the change password option. More...
 
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. More...
 
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. More...
 
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, int nodelete)
 
static int vm_instructions_en (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_instructions_ja (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_instructions_zh (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
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_da (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_is (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_ja (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_snapshotvm_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_snapshotvm_mailbox_snapshot_destroy (struct ast_vm_mailbox_snapshot *mailbox_snapshot)
 
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. More...
 
static struct ast_vm_msg_snapshotvm_msg_snapshot_destroy (struct ast_vm_msg_snapshot *msg_snapshot)
 
static int vm_newuser_setup (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_ja (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_sayname (struct ast_channel *chan, const char *mailbox_id)
 
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'. More...
 
static int vmauthenticate (struct ast_channel *chan, const char *data)
 
static int vmsayname_exec (struct ast_channel *chan, const char *data)
 
static const 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. More...
 
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 = "da6642af068ee5e6490c5b1d2cc1d238" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .optional_modules = "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 struct ao2_containeralias_mailbox_mappings
 
static char aliasescontext [MAX_VM_CONTEXT_LEN]
 
static const 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
 
static char emaildateformat [32] = "%A, %B %d, %Y at %r"
 
static char * emailsubject
 
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 ao2_containermailbox_alias_mappings
 
static const char *const mailbox_folders []
 
static char mailcmd [160] = SENDMAIL
 
static int maxdeletedmsg
 
static int maxgreet
 
static int maxlogins = 3
 
static int maxmsg = MAXMSG
 
static int maxsilence
 
static int minpassword = MINPASSWORD
 
static int msg_id_incrementor
 
struct ast_mwi_observer mwi_observer
 
static struct ast_taskprocessormwi_subscription_tps
 
static int my_umask
 
static char * pagerbody
 
static char pagerdateformat [32] = "%A, %B %d, %Y at %r"
 
static char pagerfromstring [100]
 
static char * pagersubject
 
static int passwordlocation
 
static char * playmsg_app = "VoiceMailPlayMsg"
 
static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER
 
static unsigned int poll_freq = DEFAULT_POLL_FREQ
 
static ast_mutex_t poll_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
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 = 2
 
static char * sayname_app = "VMSayName"
 
static char serveremail [80] = ASTERISK_USERNAME
 
static int silencethreshold = 128
 
static int skipms = 3000
 
static struct ast_smdi_interfacesmdi_iface = NULL
 
static struct users users = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static char userscontext [AST_MAX_EXTENSION] = "default"
 
static const struct ast_app_option vm_app_options [128] = { [ 's' ] = { .flag = OPT_SILENT }, [ 'S' ] = { .flag = OPT_SILENT_IF_GREET }, [ '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 }, [ 'e' ] = { .flag = OPT_EARLYM_GREETING }, [ 't' ] = { .flag = OPT_BEEP , .arg_index = OPT_ARG_BEEP_TONE + 1 }, [ 'r' ] = { .flag = OPT_READONLY }, }
 
static const struct ast_vm_greeter_functions vm_greeter_table
 
static struct ast_custom_function vm_info_acf
 
static char vm_invalid_password [80] = "vm-invalid-password"
 
static char vm_login [80] = "vm-login"
 
static char vm_mismatch [80] = "vm-mismatch"
 
static char vm_newpassword [80] = "vm-newpassword"
 
static char vm_newuser [80] = "vm-newuser"
 
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 const struct ast_vm_functions vm_table
 
static char * vmauthenticate_app = "VMAuthenticate"
 
static char vmfmts [80] = "wav"
 
static int vmmaxsecs
 
static int vmminsecs
 
static char * voicemail_app = "VoiceMail"
 
static char * voicemailmain_app = "VoiceMailMain"
 
static double volgain
 
static struct zones zones = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static char zonetag [80]
 

Detailed Description

Comedian Mail - Voicemail System.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m unixODBC (http://www.unixodbc.org/) 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://docs.asterisk.org/Configuration/Applications/Voicemail/IMAP-Voicemail-Storage/
Todo:
This module requires res_adsi to load. This needs to be optional during compilation.
Todo:
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.

Macro Definition Documentation

#define DEFAULT_POLL_FREQ   30

By default, poll every 30 seconds

Definition at line 1085 of file app_voicemail.c.

#define MINPASSWORD   0

Default minimum mailbox password length

Definition at line 660 of file app_voicemail.c.

#define MSGFILE_LEN   (7)

Length of the message file name: msgXXXX

Definition at line 698 of file app_voicemail.c.

#define VM_ALLOCED   (1 << 13)

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

Definition at line 684 of file app_voicemail.c.

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

#define VM_ATTACH   (1 << 11)

Attach message to voicemail notifications?

Definition at line 682 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), apply_option(), forward_message(), and notify_new_message().

#define VM_DELETE   (1 << 12)

Delete message after sending notification

Definition at line 683 of file app_voicemail.c.

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

#define VM_DIRECTFORWARD   (1 << 10)

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

Definition at line 681 of file app_voicemail.c.

Referenced by forward_message().

#define VM_EMAIL_EXT_RECS   (1 << 19)

Send voicemail emails when an external recording is added to a mailbox

Definition at line 690 of file app_voicemail.c.

Referenced by apply_option().

#define VM_ENVELOPE   (1 << 4)

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

Definition at line 675 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), and apply_option().

#define VM_FORCEGREET   (1 << 8)

Have new users record their greetings

Definition at line 679 of file app_voicemail.c.

Referenced by apply_option().

#define VM_FORCENAME   (1 << 7)

Have new users record their name

Definition at line 678 of file app_voicemail.c.

Referenced by apply_option().

#define VM_FWDURGAUTO   (1 << 18)

Autoset of Urgent flag on forwarded Urgent messages set globally

Definition at line 689 of file app_voicemail.c.

Referenced by forward_message().

#define VM_MARK_URGENT   (1 << 20)

After recording, permit the caller to mark the message as urgent

Definition at line 691 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), and apply_option().

#define VM_MESSAGEWRAP   (1 << 17)

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

Definition at line 688 of file app_voicemail.c.

Referenced by apply_option().

#define VM_MOVEHEARD   (1 << 16)

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

Definition at line 687 of file app_voicemail.c.

Referenced by apply_option().

#define VM_ODBC_AUDIO_ON_DISK   (1 << 21)

When using ODBC, leave the message and greeting recordings on disk instead of moving them into the table

Definition at line 692 of file app_voicemail.c.

#define VM_OPERATOR   (1 << 1)

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

Definition at line 672 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), apply_option(), and leave_voicemail().

#define VM_PBXSKIP   (1 << 9)

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

Definition at line 680 of file app_voicemail.c.

Referenced by make_email_file().

#define VM_REVIEW   (1 << 0)

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

Definition at line 671 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), and apply_option().

#define VM_SAYCID   (1 << 2)

Repeat the CallerID info during envelope playback

Definition at line 673 of file app_voicemail.c.

Referenced by append_vmu_info_astman(), and apply_option().

#define VM_SAYDURATION   (1 << 5)

Play the length of the message during envelope playback

Definition at line 676 of file app_voicemail.c.

Referenced by apply_option().

#define VM_SEARCH   (1 << 14)

Search all contexts for a matching mailbox

Definition at line 685 of file app_voicemail.c.

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

Referenced by apply_option().

#define VM_SVMAIL   (1 << 3)

Allow the user to compose a new VM from within VoicemailMain

Definition at line 674 of file app_voicemail.c.

Referenced by apply_option().

#define VM_TEMPGREETWARN   (1 << 15)

Remind user tempgreeting is set

Definition at line 686 of file app_voicemail.c.

Referenced by apply_option().

Function Documentation

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 16486 of file app_voicemail.c.

References ast_callerid_parse(), ast_config_destroy(), ast_config_load, AST_MAX_EXTENSION, ast_play_and_wait(), ast_strdupa, ast_test_suite_event_notify, ast_waitfordigit(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, find_user(), leave_voicemail(), ast_vm_user::mailbox, make_file(), and valid_config().

16487 {
16488  int res = 0;
16489  char filename[PATH_MAX];
16490  struct ast_config *msg_cfg = NULL;
16491  const char *origtime, *context;
16492  char *name, *num;
16493  int retries = 0;
16494  char *cid;
16495  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
16496 
16497  vms->starting = 0;
16498 
16499  make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
16500 
16501  /* Retrieve info from VM attribute file */
16502  snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
16503  RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
16504  msg_cfg = ast_config_load(filename, config_flags);
16505  DISPOSE(vms->curdir, vms->curmsg);
16506  if (!valid_config(msg_cfg)) {
16507  ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
16508  return 0;
16509  }
16510 
16511  if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
16512  ast_config_destroy(msg_cfg);
16513  return 0;
16514  }
16515 
16516  cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
16517 
16518  context = ast_variable_retrieve(msg_cfg, "message", "context");
16519  switch (option) {
16520  case 3: /* Play message envelope */
16521  if (!res) {
16522  res = play_message_datetime(chan, vmu, origtime, filename);
16523  }
16524  if (!res) {
16525  res = play_message_callerid(chan, vms, cid, context, 0, 1);
16526  }
16527 
16528  res = 't';
16529  break;
16530 
16531  case 2: /* Call back */
16532 
16533  if (ast_strlen_zero(cid))
16534  break;
16535 
16536  ast_callerid_parse(cid, &name, &num);
16537  while ((res > -1) && (res != 't')) {
16538  switch (res) {
16539  case '1':
16540  if (num) {
16541  /* Dial the CID number */
16542  res = dialout(chan, vmu, num, vmu->callback);
16543  if (res) {
16544  ast_config_destroy(msg_cfg);
16545  return 9;
16546  }
16547  } else {
16548  res = '2';
16549  }
16550  break;
16551 
16552  case '2':
16553  /* Want to enter a different number, can only do this if there's a dialout context for this user */
16554  if (!ast_strlen_zero(vmu->dialout)) {
16555  res = dialout(chan, vmu, NULL, vmu->dialout);
16556  if (res) {
16557  ast_config_destroy(msg_cfg);
16558  return 9;
16559  }
16560  } else {
16561  ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
16562  res = ast_play_and_wait(chan, "vm-sorry");
16563  }
16564  ast_config_destroy(msg_cfg);
16565  return res;
16566  case '*':
16567  res = 't';
16568  break;
16569  case '3':
16570  case '4':
16571  case '5':
16572  case '6':
16573  case '7':
16574  case '8':
16575  case '9':
16576  case '0':
16577 
16578  res = ast_play_and_wait(chan, "vm-sorry");
16579  retries++;
16580  break;
16581  default:
16582  if (num) {
16583  ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
16584  res = ast_play_and_wait(chan, "vm-num-i-have");
16585  if (!res)
16586  res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
16587  if (!res)
16588  res = ast_play_and_wait(chan, "vm-tocallnum");
16589  /* Only prompt for a caller-specified number if there is a dialout context specified */
16590  if (!ast_strlen_zero(vmu->dialout)) {
16591  if (!res)
16592  res = ast_play_and_wait(chan, "vm-calldiffnum");
16593  }
16594  } else {
16595  res = ast_play_and_wait(chan, "vm-nonumber");
16596  if (!ast_strlen_zero(vmu->dialout)) {
16597  if (!res)
16598  res = ast_play_and_wait(chan, "vm-toenternumber");
16599  }
16600  }
16601  if (!res) {
16602  res = ast_play_and_wait(chan, "vm-star-cancel");
16603  }
16604  if (!res) {
16605  res = ast_waitfordigit(chan, 6000);
16606  }
16607  if (!res) {
16608  retries++;
16609  if (retries > 3) {
16610  res = 't';
16611  }
16612  }
16613  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
16614  isprint(res) ? res : '?', isprint(res) ? res : '?');
16615  break;
16616 
16617  }
16618  if (res == 't')
16619  res = 0;
16620  else if (res == '*')
16621  res = -1;
16622  }
16623  break;
16624 
16625  case 1: /* Reply */
16626  /* Send reply directly to sender */
16627  if (ast_strlen_zero(cid))
16628  break;
16629 
16630  ast_callerid_parse(cid, &name, &num);
16631  if (!num) {
16632  ast_verb(3, "No CID number available, no reply sent\n");
16633  if (!res)
16634  res = ast_play_and_wait(chan, "vm-nonumber");
16635  ast_config_destroy(msg_cfg);
16636  return res;
16637  } else {
16638  struct ast_vm_user vmu2, *vmu3;
16639  memset(&vmu2, 0, sizeof(vmu2));
16640  vmu3 = find_user(&vmu2, vmu->context, num);
16641  if (vmu3) {
16642  struct leave_vm_options leave_options;
16643  char mailbox[AST_MAX_EXTENSION * 2 + 2];
16644  snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
16645 
16646  ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
16647 
16648  memset(&leave_options, 0, sizeof(leave_options));
16649  leave_options.record_gain = record_gain;
16650  leave_options.beeptone = "beep";
16651  res = leave_voicemail(chan, mailbox, &leave_options);
16652  if (!res)
16653  res = 't';
16654  ast_config_destroy(msg_cfg);
16655  free_user(vmu3);
16656  return res;
16657  } else {
16658  /* Sender has no mailbox, can't reply */
16659  ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
16660  ast_play_and_wait(chan, "vm-nobox");
16661  res = 't';
16662  ast_config_destroy(msg_cfg);
16663  return res;
16664  }
16665  }
16666  res = 0;
16667 
16668  break;
16669  }
16670 
16671  ast_config_destroy(msg_cfg);
16672 
16673 #ifndef IMAP_STORAGE
16674  if (!res) {
16675  make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
16676  vms->heard[msg] = 1;
16677  res = wait_file(chan, vms, vms->fn);
16678  }
16679 #endif
16680  return res;
16681 }
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
#define ast_config_load(filename, flags)
Load a config file.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_MAX_EXTENSION
Definition: channel.h:134
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
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 struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
Structure used to handle boolean flags.
Definition: utils.h:199
Options for leaving voicemail with the voicemail() application.
Definition: app_minivm.c:654
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
char mailbox[MAX_VM_MBOX_ID_LEN]
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1162
static int append_vmbox_info_astman ( struct mansession s,
const struct message m,
struct ast_vm_user vmu,
const char *  event_name,
const char *  actionid 
)
static

Append vmbox info string into given astman with event_name.

Returns
0 if unable to append details, 1 otherwise.

Definition at line 14277 of file app_voicemail.c.

References AST_LIST_TRAVERSE, ast_vm_mailbox_snapshot_create(), ast_vm_mailbox_snapshot_destroy(), astman_append(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_vm_user::context, and ast_vm_user::mailbox.

14283 {
14284  struct ast_vm_mailbox_snapshot *mailbox_snapshot;
14285  struct ast_vm_msg_snapshot *msg;
14286  int nummessages = 0;
14287  int i;
14288 
14289  /* Take a snapshot of the mailbox */
14290  mailbox_snapshot = ast_vm_mailbox_snapshot_create(vmu->mailbox, vmu->context, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
14291  if (!mailbox_snapshot) {
14292  ast_log(LOG_ERROR, "Could not append voicemail box info for box %s@%s.",
14293  vmu->mailbox, vmu->context);
14294  return 0;
14295  }
14296 
14297  astman_send_listack(s, m, "Voicemail box detail will follow", "start");
14298  /* walk through each folder's contents and append info for each message */
14299  for (i = 0; i < mailbox_snapshot->folders; i++) {
14300  AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
14301  astman_append(s,
14302  "Event: %s\r\n"
14303  "%s"
14304  "Folder: %s\r\n"
14305  "CallerID: %s\r\n"
14306  "Date: %s\r\n"
14307  "Duration: %s\r\n"
14308  "Flag: %s\r\n"
14309  "ID: %s\r\n"
14310  "\r\n",
14311  event_name,
14312  actionid,
14313  msg->folder_name,
14314  msg->callerid,
14315  msg->origdate,
14316  msg->duration,
14317  msg->flag,
14318  msg->msg_id
14319  );
14320  nummessages++;
14321  }
14322  }
14323 
14324  /* done, destroy. */
14325  mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
14326  astman_send_list_complete_start(s, m, "VoicemailBoxDetailComplete", nummessages);
14328 
14329  return 1;
14330 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
char context[MAX_VM_CONTEXT_LEN]
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
destroy a snapshot
Definition: main/app.c:675
struct ast_vm_mailbox_snapshot * ast_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)
Create a snapshot of a mailbox which contains information about every msg.
Definition: main/app.c:661
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
char mailbox[MAX_VM_MBOX_ID_LEN]
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431
static int append_vmu_info_astman ( struct mansession s,
struct ast_vm_user vmu,
const char *  event_name,
const char *  actionid 
)
static

Append vmu info string into given astman with event_name.

Returns
0 failed. 1 otherwise.

Definition at line 14153 of file app_voicemail.c.

References ast_asprintf, astman_append(), ast_vm_user::attachfmt, ast_vm_user::context, ast_vm_user::email, ast_vm_user::fromstring, ast_vm_user::fullname, ast_vm_user::language, ast_vm_user::mailbox, ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::pager, ast_vm_user::serveremail, ast_vm_user::uniqueid, VM_ATTACH, VM_DELETE, VM_ENVELOPE, VM_MARK_URGENT, VM_OPERATOR, VM_REVIEW, VM_SAYCID, ast_vm_user::volgain, and ast_vm_user::zonetag.

Referenced by manager_list_voicemail_users().

14159 {
14160  int new;
14161  int old;
14162  char *mailbox;
14163  int ret;
14164 
14165  if((s == NULL) || (vmu == NULL) || (event_name == NULL) || (actionid == NULL)) {
14166  ast_log(LOG_ERROR, "Wrong input parameter.");
14167  return 0;
14168  }
14169 
14170  /* create mailbox string */
14171  if (!ast_strlen_zero(vmu->context)) {
14172  ret = ast_asprintf(&mailbox, "%s@%s", vmu->mailbox, vmu->context);
14173  } else {
14174  ret = ast_asprintf(&mailbox, "%s", vmu->mailbox);
14175  }
14176  if (ret == -1) {
14177  ast_log(LOG_ERROR, "Could not create mailbox string. err[%s]\n", strerror(errno));
14178  return 0;
14179  }
14180 
14181  /* get mailbox count */
14182  ret = inboxcount(mailbox, &new, &old);
14183  ast_free(mailbox);
14184  if (ret == -1) {
14185  ast_log(LOG_ERROR, "Could not get mailbox count. user[%s], context[%s]\n",
14186  vmu->mailbox ?: "", vmu->context ?: "");
14187  return 0;
14188  }
14189 
14190  astman_append(s,
14191  "Event: %s\r\n"
14192  "%s"
14193  "VMContext: %s\r\n"
14194  "VoiceMailbox: %s\r\n"
14195  "Fullname: %s\r\n"
14196  "Email: %s\r\n"
14197  "Pager: %s\r\n"
14198  "ServerEmail: %s\r\n"
14199  "FromString: %s\r\n"
14200  "MailCommand: %s\r\n"
14201  "Language: %s\r\n"
14202  "TimeZone: %s\r\n"
14203  "Callback: %s\r\n"
14204  "Dialout: %s\r\n"
14205  "UniqueID: %s\r\n"
14206  "ExitContext: %s\r\n"
14207  "SayDurationMinimum: %d\r\n"
14208  "SayEnvelope: %s\r\n"
14209  "SayCID: %s\r\n"
14210  "AttachMessage: %s\r\n"
14211  "AttachmentFormat: %s\r\n"
14212  "DeleteMessage: %s\r\n"
14213  "VolumeGain: %.2f\r\n"
14214  "CanReview: %s\r\n"
14215  "CanMarkUrgent: %s\r\n"
14216  "CallOperator: %s\r\n"
14217  "MaxMessageCount: %d\r\n"
14218  "MaxMessageLength: %d\r\n"
14219  "NewMessageCount: %d\r\n"
14220  "OldMessageCount: %d\r\n"
14221 #ifdef IMAP_STORAGE
14222  "IMAPUser: %s\r\n"
14223  "IMAPServer: %s\r\n"
14224  "IMAPPort: %s\r\n"
14225  "IMAPFlags: %s\r\n"
14226 #endif
14227  "\r\n",
14228 
14229  event_name,
14230  actionid,
14231  vmu->context,
14232  vmu->mailbox,
14233  vmu->fullname,
14234  vmu->email,
14235  vmu->pager,
14236  ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
14237  ast_strlen_zero(vmu->fromstring) ? fromstring : vmu->fromstring,
14238  mailcmd,
14239  vmu->language,
14240  vmu->zonetag,
14241  vmu->callback,
14242  vmu->dialout,
14243  vmu->uniqueid,
14244  vmu->exit,
14245  vmu->saydurationm,
14246  ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
14247  ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
14248  ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
14249  vmu->attachfmt,
14250  ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
14251  vmu->volgain,
14252  ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
14253  ast_test_flag(vmu, VM_MARK_URGENT) ? "Yes" : "No",
14254  ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
14255  vmu->maxmsg,
14256  vmu->maxsecs,
14257  new,
14258  old
14259 #ifdef IMAP_STORAGE
14260  ,
14261  vmu->imapuser,
14262  vmu->imapserver,
14263  vmu->imapport,
14264  vmu->imapflags
14265 #endif
14266  );
14267 
14268  return 1;
14269 
14270 }
double volgain
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
#define VM_MARK_URGENT
#define VM_ATTACH
char pager[80]
char context[MAX_VM_CONTEXT_LEN]
#define VM_SAYCID
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define VM_ENVELOPE
#define VM_DELETE
char zonetag[80]
char fromstring[100]
#define VM_OPERATOR
#define VM_REVIEW
char language[MAX_LANGUAGE]
char serveremail[80]
char attachfmt[20]
char uniqueid[80]
char fullname[80]
char mailbox[MAX_VM_MBOX_ID_LEN]
static void apply_option ( struct ast_vm_user vmu,
const char *  var,
const char *  value 
)
static

Sets 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 1525 of file app_voicemail.c.

References apply_options(), ast_copy_string(), ast_strdup, ast_true(), ast_vm_user::attachfmt, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::fromstring, ast_vm_user::language, ast_vm_user::locale, ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, ast_vm_user::passwordlocation, ast_vm_user::serveremail, VM_ATTACH, VM_DELETE, VM_EMAIL_EXT_RECS, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_MARK_URGENT, 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.

Referenced by apply_options(), and apply_options_full().

1526 {
1527  int x;
1528  if (!strcasecmp(var, "attach")) {
1529  ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
1530  } else if (!strcasecmp(var, "attachfmt")) {
1531  ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
1532  } else if (!strcasecmp(var, "attachextrecs")) {
1533  ast_set2_flag(vmu, ast_true(value), VM_EMAIL_EXT_RECS);
1534  } else if (!strcasecmp(var, "serveremail")) {
1535  ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
1536  } else if (!strcasecmp(var, "fromstring")) {
1537  ast_copy_string(vmu->fromstring, value, sizeof(vmu->fromstring));
1538  } else if (!strcasecmp(var, "emailbody")) {
1539  ast_free(vmu->emailbody);
1540  vmu->emailbody = ast_strdup(substitute_escapes(value));
1541  } else if (!strcasecmp(var, "emailsubject")) {
1542  ast_free(vmu->emailsubject);
1543  vmu->emailsubject = ast_strdup(substitute_escapes(value));
1544  } else if (!strcasecmp(var, "language")) {
1545  ast_copy_string(vmu->language, value, sizeof(vmu->language));
1546  } else if (!strcasecmp(var, "tz")) {
1547  ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
1548  } else if (!strcasecmp(var, "locale")) {
1549  ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
1550 #ifdef IMAP_STORAGE
1551  } else if (!strcasecmp(var, "imapuser")) {
1552  ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
1553  vmu->imapversion = imapversion;
1554  } else if (!strcasecmp(var, "imapserver")) {
1555  ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
1556  vmu->imapversion = imapversion;
1557  } else if (!strcasecmp(var, "imapport")) {
1558  ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
1559  vmu->imapversion = imapversion;
1560  } else if (!strcasecmp(var, "imapflags")) {
1561  ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
1562  vmu->imapversion = imapversion;
1563  } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
1564  ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
1565  vmu->imapversion = imapversion;
1566  } else if (!strcasecmp(var, "imapfolder")) {
1567  ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
1568  vmu->imapversion = imapversion;
1569  } else if (!strcasecmp(var, "imapvmshareid")) {
1570  ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
1571  vmu->imapversion = imapversion;
1572 #endif
1573  } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
1574  ast_set2_flag(vmu, ast_true(value), VM_DELETE);
1575  } else if (!strcasecmp(var, "saycid")){
1576  ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
1577  } else if (!strcasecmp(var, "sendvoicemail")){
1578  ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
1579  } else if (!strcasecmp(var, "review")){
1580  ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
1581  } else if (!strcasecmp(var, "leaveurgent")){
1582  ast_set2_flag(vmu, ast_true(value), VM_MARK_URGENT);
1583  } else if (!strcasecmp(var, "tempgreetwarn")){
1584  ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
1585  } else if (!strcasecmp(var, "messagewrap")){
1586  ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
1587  } else if (!strcasecmp(var, "operator")) {
1588  ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
1589  } else if (!strcasecmp(var, "envelope")){
1590  ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
1591  } else if (!strcasecmp(var, "moveheard")){
1592  ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
1593  } else if (!strcasecmp(var, "sayduration")){
1594  ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
1595  } else if (!strcasecmp(var, "saydurationm")){
1596  if (sscanf(value, "%30d", &x) == 1) {
1597  vmu->saydurationm = x;
1598  } else {
1599  ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
1600  }
1601  } else if (!strcasecmp(var, "forcename")){
1602  ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
1603  } else if (!strcasecmp(var, "forcegreetings")){
1604  ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
1605  } else if (!strcasecmp(var, "callback")) {
1606  ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
1607  } else if (!strcasecmp(var, "dialout")) {
1608  ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
1609  } else if (!strcasecmp(var, "exitcontext")) {
1610  ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
1611  } else if (!strcasecmp(var, "minsecs")) {
1612  if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
1613  vmu->minsecs = x;
1614  } else {
1615  ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1616  vmu->minsecs = vmminsecs;
1617  }
1618  } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
1619  vmu->maxsecs = atoi(value);
1620  if (vmu->maxsecs <= 0) {
1621  ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1622  vmu->maxsecs = vmmaxsecs;
1623  } else {
1624  vmu->maxsecs = atoi(value);
1625  }
1626  if (!strcasecmp(var, "maxmessage"))
1627  ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1628  } else if (!strcasecmp(var, "maxmsg")) {
1629  vmu->maxmsg = atoi(value);
1630  /* Accept maxmsg=0 (Greetings only voicemail) */
1631  if (vmu->maxmsg < 0) {
1632  ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
1633  vmu->maxmsg = MAXMSG;
1634  } else if (vmu->maxmsg > MAXMSGLIMIT) {
1635  ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
1636  vmu->maxmsg = MAXMSGLIMIT;
1637  }
1638  } else if (!strcasecmp(var, "nextaftercmd")) {
1639  ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
1640  } else if (!strcasecmp(var, "backupdeleted")) {
1641  if (sscanf(value, "%30d", &x) == 1)
1642  vmu->maxdeletedmsg = x;
1643  else if (ast_true(value))
1644  vmu->maxdeletedmsg = MAXMSG;
1645  else
1646  vmu->maxdeletedmsg = 0;
1647 
1648  if (vmu->maxdeletedmsg < 0) {
1649  ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
1650  vmu->maxdeletedmsg = MAXMSG;
1651  } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
1652  ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
1653  vmu->maxdeletedmsg = MAXMSGLIMIT;
1654  }
1655  } else if (!strcasecmp(var, "volgain")) {
1656  sscanf(value, "%30lf", &vmu->volgain);
1657  } else if (!strcasecmp(var, "passwordlocation")) {
1658  if (!strcasecmp(value, "spooldir")) {
1659  vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
1660  } else {
1661  vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
1662  }
1663  } else if (!strcasecmp(var, "options")) {
1664  apply_options(vmu, value);
1665  }
1666 }
double volgain
#define VM_TEMPGREETWARN
#define VM_MARK_URGENT
#define VM_SAYDURATION
#define VM_MESSAGEWRAP
#define VM_ATTACH
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define VM_SAYCID
#define VM_SVMAIL
#define VM_ENVELOPE
char locale[20]
#define VM_FORCENAME
#define VM_DELETE
char zonetag[80]
#define VM_EMAIL_EXT_RECS
int passwordlocation
#define VM_MOVEHEARD
static void apply_options(struct ast_vm_user *vmu, const char *options)
Destructively Parse options and apply.
char fromstring[100]
#define VM_OPERATOR
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
char * emailbody
#define VM_REVIEW
char language[MAX_LANGUAGE]
char serveremail[80]
char attachfmt[20]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define VM_SKIPAFTERCMD
char * emailsubject
#define VM_FORCEGREET
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 1803 of file app_voicemail.c.

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

Referenced by find_user_realtime().

1804 {
1805  for (; var; var = var->next) {
1806  if (!strcasecmp(var->name, "vmsecret")) {
1807  ast_copy_string(retval->password, var->value, sizeof(retval->password));
1808  } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
1809  if (ast_strlen_zero(retval->password)) {
1810  if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
1811  ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
1812  "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
1813  } else {
1814  ast_copy_string(retval->password, var->value, sizeof(retval->password));
1815  }
1816  }
1817  } else if (!strcasecmp(var->name, "uniqueid")) {
1818  ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
1819  } else if (!strcasecmp(var->name, "pager")) {
1820  ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
1821  } else if (!strcasecmp(var->name, "email")) {
1822  ast_free(retval->email);
1823  retval->email = ast_strdup(var->value);
1824  } else if (!strcasecmp(var->name, "fullname")) {
1825  ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
1826  } else if (!strcasecmp(var->name, "context")) {
1827  ast_copy_string(retval->context, var->value, sizeof(retval->context));
1828  } else if (!strcasecmp(var->name, "emailsubject")) {
1829  ast_free(retval->emailsubject);
1830  retval->emailsubject = ast_strdup(substitute_escapes(var->value));
1831  } else if (!strcasecmp(var->name, "emailbody")) {
1832  ast_free(retval->emailbody);
1833  retval->emailbody = ast_strdup(substitute_escapes(var->value));
1834 #ifdef IMAP_STORAGE
1835  } else if (!strcasecmp(var->name, "imapuser")) {
1836  ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
1837  retval->imapversion = imapversion;
1838  } else if (!strcasecmp(var->name, "imapserver")) {
1839  ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
1840  retval->imapversion = imapversion;
1841  } else if (!strcasecmp(var->name, "imapport")) {
1842  ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
1843  retval->imapversion = imapversion;
1844  } else if (!strcasecmp(var->name, "imapflags")) {
1845  ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
1846  retval->imapversion = imapversion;
1847  } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
1848  ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
1849  retval->imapversion = imapversion;
1850  } else if (!strcasecmp(var->name, "imapfolder")) {
1851  ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
1852  retval->imapversion = imapversion;
1853  } else if (!strcasecmp(var->name, "imapvmshareid")) {
1854  ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
1855  retval->imapversion = imapversion;
1856 #endif
1857  } else
1858  apply_option(retval, var->name, var->value);
1859  }
1860 }
struct ast_variable * next
char pager[80]
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
char password[80]
char context[MAX_VM_CONTEXT_LEN]
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
Sets a specific property value.
char * emailbody
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char uniqueid[80]
char * emailsubject
char fullname[80]
char mailbox[MAX_VM_MBOX_ID_LEN]
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 5378 of file app_voicemail.c.

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

Referenced by make_email_file().

5379 {
5380  struct ast_str *tmp = ast_str_alloca(80);
5381  int first_section = 1;
5382 
5383  ast_str_reset(*end);
5384  ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5385  for (; *start; start++) {
5386  int need_encoding = 0;
5387  if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
5388  need_encoding = 1;
5389  }
5390  if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
5391  (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
5392  (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
5393  (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
5394  /* Start new line */
5395  ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
5396  ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5397  first_section = 0;
5398  }
5399  if (need_encoding && *start == ' ') {
5400  ast_str_append(&tmp, -1, "_");
5401  } else if (need_encoding) {
5402  ast_str_append(&tmp, -1, "=%hhX", *start);
5403  } else {
5404  ast_str_append(&tmp, -1, "%c", *start);
5405  }
5406  }
5407  ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
5408  return ast_str_buffer(*end);
5409 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Support for dynamic strings.
Definition: strings.h:623
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
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 5306 of file app_voicemail.c.

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

Referenced by make_email_file().

5307 {
5308  const char *ptr;
5309 
5310  /* We're only ever passing 0 to maxlen, so short output isn't possible */
5311  ast_str_set(buf, maxlen, "\"");
5312  for (ptr = from; *ptr; ptr++) {
5313  if (*ptr == '"' || *ptr == '\\') {
5314  ast_str_append(buf, maxlen, "\\%c", *ptr);
5315  } else {
5316  ast_str_append(buf, maxlen, "%c", *ptr);
5317  }
5318  }
5319  ast_str_append(buf, maxlen, "\"");
5320 
5321  return ast_str_buffer(*buf);
5322 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
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 1762 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, and ast_vm_user::password.

Referenced by vm_change_password().

1763 {
1764  int res = -1;
1765  if (!strcmp(vmu->password, password)) {
1766  /* No change (but an update would return 0 rows updated, so we opt out here) */
1767  return 0;
1768  }
1769 
1770  if (strlen(password) > 10) {
1771  ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
1772  }
1773  if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
1774  ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
1775  ast_copy_string(vmu->password, password, sizeof(vmu->password));
1776  res = 0;
1777  }
1778  return res;
1779 }
char password[80]
char context[MAX_VM_CONTEXT_LEN]
int ast_update2_realtime(const char *family,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3695
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3549
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char mailbox[MAX_VM_MBOX_ID_LEN]
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 1721 of file app_voicemail.c.

References ast_debug, ast_vm_user::context, ast_vm_user::mailbox, and ast_vm_user::password.

1722 {
1723  /* check minimum length */
1724  if (strlen(password) < minpassword)
1725  return 1;
1726  /* check that password does not contain '*' character */
1727  if (!ast_strlen_zero(password) && password[0] == '*')
1728  return 1;
1729  if (!ast_strlen_zero(ext_pass_check_cmd)) {
1730  char cmd[255], buf[255];
1731 
1732  ast_debug(1, "Verify password policies for %s\n", password);
1733 
1734  snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
1735  if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
1736  ast_debug(5, "Result: %s\n", buf);
1737  if (!strncasecmp(buf, "VALID", 5)) {
1738  ast_debug(3, "Passed password check: '%s'\n", buf);
1739  return 0;
1740  } else if (!strncasecmp(buf, "FAILURE", 7)) {
1741  ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
1742  return 0;
1743  } else {
1744  ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
1745  return 1;
1746  }
1747  }
1748  }
1749  return 0;
1750 }
char password[80]
char context[MAX_VM_CONTEXT_LEN]
#define ast_debug(level,...)
Log a DEBUG message.
char mailbox[MAX_VM_MBOX_ID_LEN]
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 5103 of file app_voicemail.c.

Referenced by ast_ari_asterisk_update_object(), ast_bucket_file_copy(), ast_func_read(), ast_func_read2(), ast_func_write(), ast_sorcery_copy(), ast_sorcery_object_set_copy_handler(), authenticate_api_key(), copy_plain_file(), handle_updates(), reload_followme(), and vm_forwardoptions().

5104 {
5105  int ifd;
5106  int ofd;
5107  int res = -1;
5108  int len;
5109  char buf[4096];
5110 
5111 #ifdef HARDLINK_WHEN_POSSIBLE
5112  /* Hard link if possible; saves disk space & is faster */
5113  if (!link(infile, outfile)) {
5114  return 0;
5115  }
5116 #endif
5117 
5118  if ((ifd = open(infile, O_RDONLY)) < 0) {
5119  ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
5120  return -1;
5121  }
5122 
5123  if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
5124  ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
5125  close(ifd);
5126  return -1;
5127  }
5128 
5129  for (;;) {
5130  int wrlen;
5131 
5132  len = read(ifd, buf, sizeof(buf));
5133  if (!len) {
5134  res = 0;
5135  break;
5136  }
5137 
5138  if (len < 0) {
5139  ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
5140  break;
5141  }
5142 
5143  wrlen = write(ofd, buf, len);
5144  if (errno == ENOMEM || errno == ENOSPC || wrlen != len) {
5145  ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, wrlen, len, strerror(errno));
5146  break;
5147  }
5148  }
5149 
5150  close(ifd);
5151  close(ofd);
5152  if (res) {
5153  unlink(outfile);
5154  }
5155 
5156  return res;
5157 }
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
flag,dest_folderThis is only used by file storage based mailboxes.
Returns
zero on success, -1 on error.

Definition at line 6337 of file app_voicemail.c.

References ast_copy_string(), ast_unlock_path(), ast_vm_user::context, copy_plain_file(), create_dirpath(), ast_party_caller::id, ast_vm_user::mailbox, make_dir(), make_file(), ast_party_id::name, notify_new_message(), ast_party_id::number, S_COR, 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(), and leave_voicemail().

6340 {
6341  char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
6342  const char *frombox = mbox(vmu, imbox);
6343  const char *userfolder;
6344  int recipmsgnum;
6345  int res = 0;
6346  SCOPE_ENTER(3, "mb: %s imb: %d msgnum: %d recip: %s dir: %s dest_folder: %s",
6347  vmu->mailbox, imbox, msgnum, recip->mailbox, dir, dest_folder);
6348 
6349  ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
6350 
6351  if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
6352  userfolder = "Urgent";
6353  } else if (!ast_strlen_zero(dest_folder)) {
6354  userfolder = dest_folder;
6355  } else {
6356  userfolder = "INBOX";
6357  }
6358 
6359  create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
6360  ast_trace(-1, "todir: %s\n", todir);
6361 
6362  if (!dir)
6363  make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
6364  else
6365  ast_copy_string(fromdir, dir, sizeof(fromdir));
6366 
6367  ast_trace(-1, "fromdir: %s\n", fromdir);
6368 
6369  make_file(frompath, sizeof(frompath), fromdir, msgnum);
6370  ast_trace(-1, "frompath: %s\n", frompath);
6371 
6372  make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
6373  ast_trace(-1, "todir: %s\n", todir);
6374 
6375  if (vm_lock_path(todir)) {
6376  SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH);
6377  }
6378 
6379  recipmsgnum = LAST_MSG_INDEX(todir) + 1;
6380  ast_trace(-1, "recip msgnum: %d\n", recipmsgnum);
6381 
6382  if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
6383  int exists = 0;
6384 
6385  make_file(topath, sizeof(topath), todir, recipmsgnum);
6386  ast_trace(-1, "topath: %s\n", topath);
6387 
6388  exists = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, fromdir, msgnum, frompath, chan ? ast_channel_language(chan) : "");
6389  if (exists) {
6390  SCOPE_CALL(-1, COPY, fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
6391  } else {
6392  SCOPE_CALL(-1, copy_plain_file,frompath, topath);
6393  SCOPE_CALL(-1, STORE, todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
6394  SCOPE_CALL(-1, vm_delete, topath);
6395 
6396  }
6397  } else {
6398  ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
6399  res = -1;
6400  }
6401  ast_unlock_path(todir);
6402  if (chan) {
6403  struct ast_party_caller *caller = ast_channel_caller(chan);
6404  notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
6405  S_COR(caller->id.number.valid, caller->id.number.str, NULL),
6406  S_COR(caller->id.name.valid, caller->id.name.str, NULL),
6407  flag);
6408  }
6409 
6410  SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d\n", res);
6411 }
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
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 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 appropria...
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
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 copy_plain_file(char *frompath, char *topath)
Copies a voicemail information (envelope) file.
char * str
Subscriber name (Malloced)
Definition: channel.h:264
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
struct ast_party_id id
Caller party ID.
Definition: channel.h:420
Caller Party information.
Definition: channel.h:418
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static int vm_delete(char *file)
Removes the voicemail sound and information file.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
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...
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char mailbox[MAX_VM_MBOX_ID_LEN]
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
static void copy_plain_file ( char *  frompath,
char *  topath 
)
static

Copies a voicemail information (envelope) file.

Parameters
frompath
topathEvery 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 5168 of file app_voicemail.c.

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

Referenced by copy_message().

5169 {
5170  char frompath2[PATH_MAX], topath2[PATH_MAX];
5171  struct ast_variable *tmp, *var = NULL;
5172  const char *origmailbox = "", *context = "", *exten = "";
5173  const char *priority = "", *callerchan = "", *callerid = "", *origdate = "";
5174  const char *origtime = "", *category = "", *duration = "";
5175 
5176  ast_filecopy(frompath, topath, NULL);
5177  snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
5178  snprintf(topath2, sizeof(topath2), "%s.txt", topath);
5179 
5180  if (ast_check_realtime("voicemail_data")) {
5181  var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
5182  /* This cycle converts ast_variable linked list, to va_list list of arguments, may be there is a better way to do it? */
5183  for (tmp = var; tmp; tmp = tmp->next) {
5184  if (!strcasecmp(tmp->name, "origmailbox")) {
5185  origmailbox = tmp->value;
5186  } else if (!strcasecmp(tmp->name, "context")) {
5187  context = tmp->value;
5188  } else if (!strcasecmp(tmp->name, "exten")) {
5189  exten = tmp->value;
5190  } else if (!strcasecmp(tmp->name, "priority")) {
5191  priority = tmp->value;
5192  } else if (!strcasecmp(tmp->name, "callerchan")) {
5193  callerchan = tmp->value;
5194  } else if (!strcasecmp(tmp->name, "callerid")) {
5195  callerid = tmp->value;
5196  } else if (!strcasecmp(tmp->name, "origdate")) {
5197  origdate = tmp->value;
5198  } else if (!strcasecmp(tmp->name, "origtime")) {
5199  origtime = tmp->value;
5200  } else if (!strcasecmp(tmp->name, "category")) {
5201  category = tmp->value;
5202  } else if (!strcasecmp(tmp->name, "duration")) {
5203  duration = tmp->value;
5204  }
5205  }
5206  ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
5207  }
5208  copy(frompath2, topath2);
5209  ast_variables_destroy(var);
5210 }
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
Definition: file.c:1151
struct ast_variable * next
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
Structure for variables, used for configurations and for channel variables.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
Definition: main/config.c:3740
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 5003 of file app_voicemail.c.

References ast_unlock_path(), and vm_lock_path().

5004 {
5005 
5006  int vmcount = 0;
5007  DIR *vmdir = NULL;
5008  struct dirent *vment = NULL;
5009 
5010  if (vm_lock_path(dir))
5011  return ERROR_LOCK_PATH;
5012 
5013  if ((vmdir = opendir(dir))) {
5014  while ((vment = readdir(vmdir))) {
5015  if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
5016  vmcount++;
5017  }
5018  }
5019  closedir(vmdir);
5020  }
5021  ast_unlock_path(dir);
5022 
5023  return vmcount;
5024 }
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
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...
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 2219 of file app_voicemail.c.

References ast_mkdir(), and make_dir().

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

2220 {
2221  mode_t mode = VOICEMAIL_DIR_MODE;
2222  int res;
2223 
2224  make_dir(dest, len, context, ext, folder);
2225  if ((res = ast_mkdir(dest, mode))) {
2226  ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
2227  return -1;
2228  }
2229  return 0;
2230 }
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 appropria...
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479
static struct ast_vm_user* find_user ( struct ast_vm_user ivm,
const char *  context,
const char *  mailbox 
)
static

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 1935 of file app_voicemail.c.

References ao2_ref, ast_alloca, ast_calloc, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, find_user_realtime(), OBJ_SEARCH_KEY, S_OR, VM_ALLOCED, and VM_SEARCH.

Referenced by advanced_options(), forward_message(), leave_voicemail(), and play_message_by_id().

1936 {
1937  /* This function could be made to generate one from a database, too */
1938  struct ast_vm_user *vmu = NULL, *cur;
1939  AST_LIST_LOCK(&users);
1940 
1941  if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
1942  context = "default";
1943 
1944  AST_LIST_TRAVERSE(&users, cur, list) {
1945 #ifdef IMAP_STORAGE
1946  if (cur->imapversion != imapversion) {
1947  continue;
1948  }
1949 #endif
1950  if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
1951  break;
1952  if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1953  break;
1954  }
1955  if (cur) {
1956  /* Make a copy, so that on a reload, we have no race */
1957  if ((vmu = (ivm ? ivm : ast_calloc(1, sizeof(*vmu))))) {
1958  ast_free(vmu->email);
1959  ast_free(vmu->emailbody);
1960  ast_free(vmu->emailsubject);
1961  *vmu = *cur;
1962  vmu->email = ast_strdup(cur->email);
1963  vmu->emailbody = ast_strdup(cur->emailbody);
1964  vmu->emailsubject = ast_strdup(cur->emailsubject);
1965  ast_set2_flag(vmu, !ivm, VM_ALLOCED);
1966  AST_LIST_NEXT(vmu, list) = NULL;
1967  }
1968  }
1970  if (!vmu) {
1971  vmu = find_user_realtime(ivm, context, mailbox);
1972  }
1973  if (!vmu && !ast_strlen_zero(aliasescontext)) {
1974  struct alias_mailbox_mapping *mapping;
1975  char *search_string = ast_alloca(MAX_VM_MAILBOX_LEN);
1976 
1977  snprintf(search_string, MAX_VM_MAILBOX_LEN, "%s%s%s",
1978  mailbox,
1979  ast_strlen_zero(context) ? "" : "@",
1980  S_OR(context, ""));
1981 
1982  mapping = ao2_find(alias_mailbox_mappings, search_string, OBJ_SEARCH_KEY);
1983  if (mapping) {
1984  char *search_mailbox = NULL;
1985  char *search_context = NULL;
1986 
1987  separate_mailbox(ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);
1988  ao2_ref(mapping, -1);
1989  vmu = find_user(ivm, search_mailbox, search_context);
1990  }
1991  }
1992 
1993  return vmu;
1994 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
list of users found in the config file
char context[MAX_VM_CONTEXT_LEN]
#define VM_SEARCH
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
static struct ast_vm_user * find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the realtime engine.
char * emailbody
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
static struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
char * emailsubject
#define VM_ALLOCED
static struct ast_flags globalflags
Definition: app_minivm.c:699
char mailbox[MAX_VM_MBOX_ID_LEN]
static struct ast_vm_user* find_user_realtime ( struct ast_vm_user ivm,
const char *  context,
const char *  mailbox 
)
static

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 1894 of file app_voicemail.c.

References apply_options_full(), ast_calloc, ast_copy_string(), ast_variables_destroy(), ast_vm_user::mailbox, populate_defaults(), VM_ALLOCED, and VM_SEARCH.

Referenced by find_user().

1895 {
1896  struct ast_variable *var;
1897  struct ast_vm_user *retval;
1898 
1899  if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
1900  if (ivm) {
1901  memset(retval, 0, sizeof(*retval));
1902  }
1903  populate_defaults(retval);
1904  if (!ivm) {
1905  ast_set_flag(retval, VM_ALLOCED);
1906  }
1907  if (mailbox) {
1908  ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
1909  }
1910  if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
1911  var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
1912  } else {
1913  var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
1914  }
1915  if (var) {
1916  apply_options_full(retval, var);
1917  ast_variables_destroy(var);
1918  } else {
1919  if (!ivm)
1920  ast_free(retval);
1921  retval = NULL;
1922  }
1923  }
1924  return retval;
1925 }
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
Loads the options specific to a voicemail user.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Structure for variables, used for configurations and for channel variables.
char context[MAX_VM_CONTEXT_LEN]
#define VM_SEARCH
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define VM_ALLOCED
static struct ast_flags globalflags
Definition: app_minivm.c:699
char mailbox[MAX_VM_MBOX_ID_LEN]
static void populate_defaults(struct ast_vm_user *vmu)
Sets default voicemail system options to a voicemail user.
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 mailbox, and then invoke leave_message() function to record and store the message.

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

  • retrieves 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 8680 of file app_voicemail.c.

References 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_MAX_EXTENSION, ast_play_and_wait(), ast_readstring(), ast_say_digit_str(), ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_test_suite_event_notify, ast_waitfordigit(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, copy_message(), find_user(), leave_voicemail(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, pbx_exec(), pbx_findapp(), run_externnotify(), S_COR, S_OR, VM_ATTACH, VM_DIRECTFORWARD, vm_forwardoptions(), and VM_FWDURGAUTO.

8681 {
8682 #ifdef IMAP_STORAGE
8683  int todircount = 0;
8684  struct vm_state *dstvms;
8685 #endif
8686  char username[70]="";
8687  char fn[PATH_MAX]; /* for playback of name greeting */
8688  char ecodes[16] = "#";
8689  int res = 0, cmd = 0;
8690  struct ast_vm_user *receiver = NULL, *vmtmp;
8692  char *stringp;
8693  const char *s;
8694  const char mailbox_context[256];
8695  int saved_messages = 0;
8696  int valid_extensions = 0;
8697  char *dir;
8698  int curmsg;
8699  char urgent_str[7] = "";
8700  int prompt_played = 0;
8701 #ifndef IMAP_STORAGE
8702  char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
8703 #endif
8704  SCOPE_ENTER(3, "%s: user: %s dir: %s msg: %d\n", ast_channel_name(chan),
8705  vms->username, vms->curdir, vms->curmsg);
8706 
8707  if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
8708  ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
8709  }
8710 
8711  if (vms == NULL) {
8712  SCOPE_EXIT_RTN_VALUE(-1, "vms is NULL\n");
8713  }
8714  dir = vms->curdir;
8715  curmsg = vms->curmsg;
8716 
8717  ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
8718  while (!res && !valid_extensions) {
8719  int use_directory = 0;
8720  if (ast_test_flag((&globalflags), VM_DIRECTFORWARD)) {
8721  int done = 0;
8722  int retries = 0;
8723  cmd = 0;
8724  while ((cmd >= 0) && !done ){
8725  if (cmd)
8726  retries = 0;
8727  switch (cmd) {
8728  case '1':
8729  use_directory = 0;
8730  done = 1;
8731  break;
8732  case '2':
8733  use_directory = 1;
8734  done = 1;
8735  break;
8736  case '*':
8737  cmd = 't';
8738  done = 1;
8739  break;
8740  default:
8741  /* Press 1 to enter an extension press 2 to use the directory */
8742  cmd = ast_play_and_wait(chan, "vm-forward");
8743  if (!cmd) {
8744  cmd = ast_waitfordigit(chan, 3000);
8745  }
8746  if (!cmd) {
8747  retries++;
8748  }
8749  if (retries > 3) {
8750  cmd = 't';
8751  done = 1;
8752  }
8753  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8754  isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
8755  }
8756  }
8757  if (cmd < 0 || cmd == 't')
8758  break;
8759  }
8760 
8761  if (use_directory) {
8762  /* use app_directory */
8763 
8764  struct ast_app* directory_app;
8765 
8766  directory_app = pbx_findapp("Directory");
8767  if (directory_app) {
8768  char vmcontext[256];
8769  char old_context[strlen(ast_channel_context(chan)) + 1];
8770  char old_exten[strlen(ast_channel_exten(chan)) + 1];
8771  int old_priority;
8772  /* make backup copies */
8773  strcpy(old_context, ast_channel_context(chan)); /* safe */
8774  strcpy(old_exten, ast_channel_exten(chan)); /* safe */
8775  old_priority = ast_channel_priority(chan);
8776 
8777  /* call the Directory, changes the channel */
8778  snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
8779  res = pbx_exec(chan, directory_app, vmcontext);
8780 
8781  ast_copy_string(username, ast_channel_exten(chan), sizeof(username));
8782 
8783  /* restore the old context, exten, and priority */
8784  ast_channel_context_set(chan, old_context);
8785  ast_channel_exten_set(chan, old_exten);
8786  ast_channel_priority_set(chan, old_priority);
8787  } else {
8788  ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
8789  ast_clear_flag((&globalflags), VM_DIRECTFORWARD);
8790  }
8791  } else {
8792  /* Ask for an extension */
8793  res = ast_streamfile(chan, "vm-extension", ast_channel_language(chan)); /* "extension" */
8794  prompt_played++;
8795  if (res || prompt_played > 4)
8796  break;
8797  if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#")) < 0)
8798  break;
8799  }
8800 
8801  /* start all over if no username */
8802  if (ast_strlen_zero(username))
8803  continue;
8804  stringp = username;
8805  s = strsep(&stringp, "*");
8806  /* start optimistic */
8807  valid_extensions = 1;
8808  while (s) {
8809  snprintf((char*)mailbox_context, sizeof(mailbox_context), "%s@%s", s, context ? context : "default");
8810  if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
8811  int oldmsgs;
8812  int newmsgs;
8813  int capacity;
8814 
8815  if (inboxcount(mailbox_context, &newmsgs, &oldmsgs)) {
8816  ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context);
8817  /* Shouldn't happen, but allow trying another extension if it does */
8818  res = ast_play_and_wait(chan, "pbx-invalid");
8819  valid_extensions = 0;
8820  break;
8821  }
8822 #ifdef IMAP_STORAGE
8823  if (!(dstvms = get_vm_state_by_mailbox(s, context, 0))) {
8824  if (!(dstvms = create_vm_state_from_user(receiver))) {
8825  ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
8826  /* Shouldn't happen, but allow trying another extension if it does */
8827  res = ast_play_and_wait(chan, "pbx-invalid");
8828  valid_extensions = 0;
8829  break;
8830  }
8831  }
8832  check_quota(dstvms, imapfolder);
8833  if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) {
8834  ast_log(LOG_NOTICE, "Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit);
8835  res = ast_play_and_wait(chan, "vm-mailboxfull");
8836  valid_extensions = 0;
8837  while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
8838  inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8839  free_user(vmtmp);
8840  }
8841  break;
8842  }
8843 #endif
8844  capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
8845  if ((newmsgs + oldmsgs) >= capacity) {
8846  ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity);
8847  res = ast_play_and_wait(chan, "vm-mailboxfull");
8848  valid_extensions = 0;
8849  while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
8850  inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8851  free_user(vmtmp);
8852  }
8853  inprocess_count(receiver->mailbox, receiver->context, -1);
8854  break;
8855  }
8856  AST_LIST_INSERT_HEAD(&extensions, receiver, list);
8857  } else {
8858  /* XXX Optimization for the future. When we encounter a single bad extension,
8859  * bailing out on all of the extensions may not be the way to go. We should
8860  * probably just bail on that single extension, then allow the user to enter
8861  * several more. XXX
8862  */
8863  while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
8864  free_user(receiver);
8865  }
8866  ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", mailbox_context);
8867  /* "I am sorry, that's not a valid extension. Please try again." */
8868  res = ast_play_and_wait(chan, "pbx-invalid");
8869  valid_extensions = 0;
8870  break;
8871  }
8872 
8873  /* play name if available, else play extension number */
8874  snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
8875  SCOPE_CALL(-1, RETRIEVE, fn, -1, s, receiver->context);
8876  if (ast_fileexists(fn, NULL, NULL) > 0) {
8877  res = ast_stream_and_wait(chan, fn, ecodes);
8878  if (res) {
8879  SCOPE_CALL(-1, DISPOSE, fn, -1);
8880  return res;
8881  }
8882  } else {
8883  res = ast_say_digit_str(chan, s, ecodes, ast_channel_language(chan));
8884  }
8885  SCOPE_CALL(-1, DISPOSE, fn, -1);
8886 
8887  s = strsep(&stringp, "*");
8888  }
8889  /* break from the loop of reading the extensions */
8890  if (valid_extensions)
8891  break;
8892  }
8893  /* check if we're clear to proceed */
8894  if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
8895  return res;
8896  if (is_new_message == 1) {
8897  struct leave_vm_options leave_options;
8898  char mailbox[AST_MAX_EXTENSION * 2 + 2];
8899  snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
8900 
8901  /* Send VoiceMail */
8902  memset(&leave_options, 0, sizeof(leave_options));
8903  leave_options.record_gain = record_gain;
8904  leave_options.beeptone = "beep";
8905  cmd = SCOPE_CALL_WITH_INT_RESULT(-1, leave_voicemail, chan, mailbox, &leave_options);
8906  } else {
8907  /* Forward VoiceMail */
8908  long duration = 0;
8909  struct vm_state vmstmp;
8910  int copy_msg_result = 0;
8911 #ifdef IMAP_STORAGE
8912  char filename[PATH_MAX];
8913  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8914  const char *msg_id = NULL;
8915  struct ast_config *msg_cfg;
8916 #endif
8917  memcpy(&vmstmp, vms, sizeof(vmstmp));
8918 
8919  SCOPE_CALL(-1, RETRIEVE, dir, curmsg, sender->mailbox, sender->context);
8920 #ifdef IMAP_STORAGE
8921  make_file(filename, sizeof(filename), dir, curmsg);
8922  strncat(filename, ".txt", sizeof(filename) - strlen(filename) - 1);
8923  msg_cfg = ast_config_load(filename, config_flags);
8924  if (msg_cfg && msg_cfg == CONFIG_STATUS_FILEINVALID) {
8925  msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
8926  ast_config_destroy(msg_cfg);
8927  }
8928 #endif
8929 
8930  cmd = SCOPE_CALL_WITH_INT_RESULT(-1, vm_forwardoptions, chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
8931  if (!cmd) {
8932  AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
8933 #ifdef IMAP_STORAGE
8934  int attach_user_voicemail;
8935  char *myserveremail = serveremail;
8936 
8937  /* get destination mailbox */
8938  dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
8939  if (!dstvms) {
8940  dstvms = create_vm_state_from_user(vmtmp);
8941  }
8942  if (dstvms) {
8943  init_mailstream(dstvms, 0);
8944  if (!dstvms->mailstream) {
8945  ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
8946  } else {
8947  copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
8948  run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
8949  }
8950  } else {
8951  ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
8952  }
8953  if (!ast_strlen_zero(vmtmp->serveremail))
8954  myserveremail = vmtmp->serveremail;
8955  attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
8956  /* NULL category for IMAP storage */
8957  sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
8958  dstvms->curbox,
8959  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
8960  S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
8961  vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
8962  NULL, urgent_str, msg_id);
8963 #else
8964  copy_msg_result = SCOPE_CALL_WITH_INT_RESULT(-1, copy_message, chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL);
8965 #endif
8966  saved_messages++;
8968  inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8969  free_user(vmtmp);
8970  if (res)
8971  break;
8972  }
8974  if (saved_messages > 0 && !copy_msg_result) {
8975  /* give confirmation that the message was saved */
8976  /* commented out since we can't forward batches yet
8977  if (saved_messages == 1)
8978  res = ast_play_and_wait(chan, "vm-message");
8979  else
8980  res = ast_play_and_wait(chan, "vm-messages");
8981  if (!res)
8982  res = ast_play_and_wait(chan, "vm-saved"); */
8983  res = ast_play_and_wait(chan, "vm-msgforwarded");
8984  }
8985 #ifndef IMAP_STORAGE
8986  else {
8987  /* with IMAP, mailbox full warning played by imap_check_limits */
8988  res = ast_play_and_wait(chan, "vm-mailboxfull");
8989  }
8990  /* Restore original message without prepended message if backup exists */
8991  make_file(msgfile, sizeof(msgfile), dir, curmsg);
8992  strcpy(textfile, msgfile);
8993  strcpy(backup, msgfile);
8994  strcpy(backup_textfile, msgfile);
8995  strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
8996  strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
8997  strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8998  if (ast_fileexists(backup, NULL, NULL) > 0) {
8999  ast_filerename(backup, msgfile, NULL);
9000  rename(backup_textfile, textfile);
9001  }
9002 #endif
9003  }
9004  SCOPE_CALL(-1, DISPOSE, dir, curmsg);
9005 #ifndef IMAP_STORAGE
9006  if (cmd) { /* assuming hangup, cleanup backup file */
9007  make_file(msgfile, sizeof(msgfile), dir, curmsg);
9008  strcpy(textfile, msgfile);
9009  strcpy(backup_textfile, msgfile);
9010  strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
9011  strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9012  rename(backup_textfile, textfile);
9013  }
9014 #endif
9015  }
9016 
9017  /* If anything failed above, we still have this list to free */
9018  while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
9019  inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
9020  free_user(vmtmp);
9021  }
9022  SCOPE_EXIT_RTN_VALUE(res ? res : cmd, "Done. res: %d cmd: %d\n", res, cmd);
9023 }
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.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
Definition: channel.c:8259
#define VM_ATTACH
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
Number structure.
Definition: app_followme.c:154
#define ast_config_load(filename, flags)
Load a config file.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_MAX_EXTENSION
Definition: channel.h:134
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define VM_DIRECTFORWARD
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:346
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.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
static struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1878
Structure used to handle boolean flags.
Definition: utils.h:199
Options for leaving voicemail with the voicemail() application.
Definition: app_minivm.c:654
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
ast_app: A registered application
Definition: pbx_app.c:45
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:1146
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.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define VM_FWDURGAUTO
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
Definition: channel.c:6558
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
static void run_externnotify(struct ast_channel *chan, struct minivm_account *vmu)
Run external notification for voicemail message.
Definition: app_minivm.c:1643
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
static struct ast_flags globalflags
Definition: app_minivm.c:699
char mailbox[MAX_VM_MBOX_ID_LEN]
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 6658 of file app_voicemail.c.

References ast_atomic_fetchadd_int().

Referenced by leave_voicemail().

6659 {
6660  /* msg id is time of msg_id generation plus an incrementing value
6661  * called each time a new msg_id is generated. This should achieve uniqueness,
6662  * but only in single system solutions.
6663  */
6664  unsigned int unique_counter = ast_atomic_fetchadd_int(&msg_id_incrementor, +1);
6665  snprintf(dst, MSG_ID_LEN, "%ld-%08x", (long) time(NULL), unique_counter);
6666 }
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
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 6075 of file app_voicemail.c.

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

Referenced by leave_voicemail().

6076 {
6077  struct ast_tm tm;
6078  struct timeval t = ast_tvnow();
6079 
6080  ast_localtime(&t, &tm, "UTC");
6081 
6082  return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
6083 }
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
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 8304 of file app_voicemail.c.

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

8305 {
8306  int res = 0;
8307  int loops = 0;
8308 
8309  res = ast_play_and_wait(chan, fn); /* Folder name */
8310  while (((res < '0') || (res > '9')) &&
8311  (res != '#') && (res >= 0) &&
8312  loops < 4) {
8313  /* res = get_folder(chan, 0); */
8314  if (!strcasecmp(ast_channel_language(chan), "ja")) { /* Japanese syntax */
8315  res = get_folder_ja(chan, 0);
8316  } else { /* Default syntax */
8317  res = get_folder(chan, 0);
8318  }
8319  loops++;
8320  }
8321  if (loops == 4) { /* give up */
8322  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
8323  return '#';
8324  }
8325  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8326  isprint(res) ? res : '?', isprint(res) ? res : '?');
8327  return res;
8328 }
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 ...
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
static int has_voicemail ( const char *  mailbox,
const char *  folder 
)
static

Determines if the given folder has messages.

Parameters
mailboxThe @ delimited string for user@context. 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 6491 of file app_voicemail.c.

References ast_copy_string().

Referenced by ast_app_has_voicemail().

6492 {
6493  char tmp[256], *tmp2 = tmp, *box, *context;
6494  ast_copy_string(tmp, mailbox, sizeof(tmp));
6495  if (ast_strlen_zero(folder)) {
6496  folder = "INBOX";
6497  }
6498  while ((box = strsep(&tmp2, ",&"))) {
6499  if ((context = strchr(box, '@')))
6500  *context++ = '\0';
6501  else
6502  context = "default";
6503  if (__has_voicemail(context, box, folder, 1))
6504  return 1;
6505  /* If we are checking INBOX, we should check Urgent as well */
6506  if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
6507  return 1;
6508  }
6509  }
6510  return 0;
6511 }
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
static int inboxcount2 ( const char *  mailbox,
int *  urgentmsgs,
int *  newmsgs,
int *  oldmsgs 
)
static

Check the given mailbox's message count.

Parameters
mailboxThe @ delimited string for user@context. If no context is found, uses 'default' for the context.
urgentmsgsurgent message count.
newmsgsnew message count.
oldmsgsold message count pointer
Returns
-1 if error occurred, 0 otherwise.

Definition at line 6521 of file app_voicemail.c.

References ast_copy_string().

Referenced by ast_app_inboxcount2().

6522 {
6523  char tmp[256];
6524  char *context;
6525 
6526  /* If no mailbox, return immediately */
6527  if (ast_strlen_zero(mailbox)) {
6528  return 0;
6529  }
6530 
6531  if (newmsgs) {
6532  *newmsgs = 0;
6533  }
6534  if (oldmsgs) {
6535  *oldmsgs = 0;
6536  }
6537  if (urgentmsgs) {
6538  *urgentmsgs = 0;
6539  }
6540 
6541  if (strchr(mailbox, ',')) {
6542  int tmpnew, tmpold, tmpurgent;
6543  char *mb, *cur;
6544 
6545  ast_copy_string(tmp, mailbox, sizeof(tmp));
6546  mb = tmp;
6547  while ((cur = strsep(&mb, ", "))) {
6548  if (!ast_strlen_zero(cur)) {
6549  if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) {
6550  return -1;
6551  } else {
6552  if (newmsgs) {
6553  *newmsgs += tmpnew;
6554  }
6555  if (oldmsgs) {
6556  *oldmsgs += tmpold;
6557  }
6558  if (urgentmsgs) {
6559  *urgentmsgs += tmpurgent;
6560  }
6561  }
6562  }
6563  }
6564  return 0;
6565  }
6566 
6567  ast_copy_string(tmp, mailbox, sizeof(tmp));
6568 
6569  if ((context = strchr(tmp, '@'))) {
6570  *context++ = '\0';
6571  } else {
6572  context = "default";
6573  }
6574 
6575  if (newmsgs) {
6576  *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
6577  }
6578  if (oldmsgs) {
6579  *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
6580  }
6581  if (urgentmsgs) {
6582  *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
6583  }
6584 
6585  return 0;
6586 }
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Check the given mailbox's message count.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
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 1869 of file app_voicemail.c.

References ast_strdupa.

1870 {
1871  int i;
1872  char *local_key = ast_strdupa(key);
1873 
1874  for (i = 0; i < strlen(key); ++i) {
1875  if (!strchr(VALID_DTMF, *local_key)) {
1876  ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1877  return 0;
1878  }
1879  local_key++;
1880  }
1881  return 1;
1882 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int last_message_index ( char *  dir)
static

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

Parameters
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 5056 of file app_voicemail.c.

References ast_debug.

5057 {
5058  int x;
5059  unsigned char map[MAXMSGLIMIT] = "";
5060  DIR *msgdir;
5061  struct dirent *msgdirent;
5062  int msgdirint;
5063  char extension[4];
5064  int stopcount = 0;
5065 
5066  /* Reading the entire directory into a file map scales better than
5067  * doing a stat repeatedly on a predicted sequence. I suspect this
5068  * is partially due to stat(2) internally doing a readdir(2) itself to
5069  * find each file. */
5070  if (!(msgdir = opendir(dir))) {
5071  return -1;
5072  }
5073 
5074  while ((msgdirent = readdir(msgdir))) {
5075  if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
5076  map[msgdirint] = 1;
5077  stopcount++;
5078  ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
5079  }
5080  }
5081  closedir(msgdir);
5082 
5083  for (x = 0; x < MAXMSGLIMIT && stopcount; x++) {
5084  stopcount -= map[x];
5085  }
5086 
5087  return x - 1;
5088 }
structure to hold extensions
#define ast_debug(level,...)
Log a DEBUG message.
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 6990 of file app_voicemail.c.

References ast_answer(), ast_canmatch_extension(), ast_check_realtime(), ast_copy_string(), ast_debug, ast_destroy_realtime(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_play_and_wait(), AST_STATE_UP, ast_stopstream(), ast_store_realtime(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_unlock_path(), ast_update_realtime(), ast_waitstream(), ast_vm_user::context, copy_message(), create_dirpath(), find_user(), generate_msg_id(), get_date(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, notify_new_message(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, S_OR, vm_lock_path(), and VM_OPERATOR.

Referenced by advanced_options(), and forward_message().

6991 {
6992 #ifdef IMAP_STORAGE
6993  int newmsgs, oldmsgs;
6994 #endif
6995  char txtfile[PATH_MAX];
6996  char tmptxtfile[PATH_MAX];
6997  struct vm_state *vms = NULL;
6998  char callerid[256];
6999  FILE *txt;
7000  char date[256];
7001  int txtdes;
7002  int res = 0;
7003  int msgnum;
7004  int duration = 0;
7005  int sound_duration = 0;
7006  int ouseexten = 0;
7007  int greeting_only = 0;
7008  char tmpdur[16];
7009  char priority[16];
7010  char origtime[16];
7011  char dir[PATH_MAX];
7012  char tmpdir[PATH_MAX];
7013  char fn[PATH_MAX];
7014  char prefile[PATH_MAX] = "";
7015  char tempfile[PATH_MAX] = "";
7016  char ext_context[256] = "";
7017  char fmt[80];
7018  char *context;
7019  char ecodes[17] = "#";
7020  struct ast_str *tmp = ast_str_create(16);
7021  char *tmpptr;
7022  struct ast_vm_user *vmu;
7023  struct ast_vm_user svm;
7024  const char *category = NULL;
7025  const char *code;
7026  const char *alldtmf = "0123456789ABCD*#";
7027  char flag[80];
7028  SCOPE_ENTER(3, "%s: %s\n", ast_channel_name(chan), ext);
7029 
7030  if (!tmp) {
7031  SCOPE_EXIT_RTN_VALUE(-1, "Failed to allocate memory for tmp\n");
7032  }
7033 
7034  ast_str_set(&tmp, 0, "%s", ext);
7035  ext = ast_str_buffer(tmp);
7036  if ((context = strchr(ext, '@'))) {
7037  *context++ = '\0';
7038  tmpptr = strchr(context, '&');
7039  } else {
7040  tmpptr = strchr(ext, '&');
7041  }
7042 
7043  if (tmpptr)
7044  *tmpptr++ = '\0';
7045 
7046  ast_channel_lock(chan);
7047  if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
7048  category = ast_strdupa(category);
7049  }
7050  ast_channel_unlock(chan);
7051 
7052  if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
7053  ast_copy_string(flag, "Urgent", sizeof(flag));
7054  } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
7055  ast_copy_string(flag, "PRIORITY", sizeof(flag));
7056  } else {
7057  flag[0] = '\0';
7058  }
7059 
7060  ast_debug(3, "Before find_user\n");
7061  memset(&svm, 0, sizeof(svm));
7062  if (!(vmu = find_user(&svm, context, ext))) {
7063  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7064  ast_free(tmp);
7065  SCOPE_EXIT_LOG_RTN_VALUE(res, LOG_WARNING,
7066  "%s: Exten: %s: No entry in voicemail config file for '%s'\n", ast_channel_name(chan), ext, ext);
7067  }
7068 
7069  /* If maxmsg is zero, act as a "greetings only" voicemail: Exit successfully without recording */
7070  if (vmu->maxmsg == 0) {
7071  greeting_only = 1;
7072  ast_set_flag(options, OPT_SILENT);
7073  }
7074 
7075  /* Setup pre-file if appropriate */
7076  if (strcmp(vmu->context, "default"))
7077  snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
7078  else
7079  ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
7080 
7081  /* Set the path to the prefile. Will be one of
7082  VM_SPOOL_DIRcontext/ext/busy
7083  VM_SPOOL_DIRcontext/ext/unavail
7084  Depending on the flag set in options.
7085  */
7086  if (ast_test_flag(options, OPT_BUSY_GREETING)) {
7087  snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
7088  } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
7089  snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
7090  }
7091  ast_trace(-1, "prefile: %s\n", prefile);
7092  /* Set the path to the tmpfile as
7093  VM_SPOOL_DIR/context/ext/temp
7094  and attempt to create the folder structure.
7095  */
7096  snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
7097  ast_trace(-1, "tempfile: %s\n", tempfile);
7098  if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
7099  free_user(vmu);
7100  ast_free(tmp);
7101  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING,
7102  "%s: Exten: %s: Failed to make directory (%s)\n", ast_channel_name(chan), ext, tempfile);
7103  }
7104  SCOPE_CALL(-1, RETRIEVE, tempfile, -1, vmu->mailbox, vmu->context);
7105  if (ast_fileexists(tempfile, NULL, NULL) > 0) {
7106  ast_copy_string(prefile, tempfile, sizeof(prefile));
7107  ast_trace(-1, "new prefile: %s\n", prefile);
7108  }
7109 
7110  SCOPE_CALL(-1, DISPOSE, tempfile, -1);
7111 
7112  /* It's easier just to try to make it than to check for its existence */
7113 #ifndef IMAP_STORAGE
7114  create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
7115 #else
7116  snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
7117  if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
7118  ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
7119  }
7120 #endif
7121 
7122  /* Check current context for special extensions */
7123  if (ast_test_flag(vmu, VM_OPERATOR)) {
7124  if (!ast_strlen_zero(vmu->exit)) {
7125  if (ast_exists_extension(chan, vmu->exit, "o", 1,
7126  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
7127  strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
7128  ouseexten = 1;
7129  }
7130  } else if (ast_exists_extension(chan, ast_channel_context(chan), "o", 1,
7131  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
7132  strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
7133  ouseexten = 1;
7134  }
7135  }
7136 
7137  if (!ast_strlen_zero(vmu->exit)) {
7138  if (ast_exists_extension(chan, vmu->exit, "a", 1,
7139  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
7140  strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
7141  }
7142  } else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
7143  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
7144  strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
7145  }
7146 
7147  if (ast_test_flag(options, OPT_DTMFEXIT)) {
7148  for (code = alldtmf; *code; code++) {
7149  char e[2] = "";
7150  e[0] = *code;
7151  if (strchr(ecodes, e[0]) == NULL
7152  && ast_canmatch_extension(chan,
7153  (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : ast_channel_context(chan)),
7154  e, 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
7155  strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
7156  }
7157  }
7158  }
7159 
7160  /* Play the beginning intro if desired */
7161  if (!ast_strlen_zero(prefile)) {
7162 #if defined(ODBC_STORAGE)
7163  int success = SCOPE_CALL_WITH_INT_RESULT(-1, RETRIEVE, prefile, -1, ext, context);
7164 #elif defined(IMAP_STORAGE)
7165  SCOPE_CALL(-1, RETRIEVE, prefile, -1, ext, context);
7166 #endif
7167 
7168  if (ast_fileexists(prefile, NULL, NULL) > 0) {
7169  if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1) {
7170  /* We know we have a greeting at this point, so squelch the instructions
7171  * if that is what is being asked of us */
7172  if (ast_test_flag(options, OPT_SILENT_IF_GREET)) {
7173  ast_set_flag(options, OPT_SILENT);
7174  }
7175  res = ast_waitstream(chan, ecodes);
7176  }
7177 #ifdef ODBC_STORAGE
7178  if (success == -1) {
7179  /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
7180  ast_trace(-1, "Greeting '%s' not retrieved from database, but found in file storage. Inserting into database\n", prefile);
7181  SCOPE_CALL(-1, odbc_store_message, prefile, vmu->mailbox, vmu->context, -1);
7182  }
7183 #endif
7184  } else {
7185  ast_trace(-1, "%s doesn't exist, doing what we can\n", prefile);
7186  res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
7187  }
7188  SCOPE_CALL(-1, DISPOSE, prefile, -1);
7189  if (res < 0) {
7190  free_user(vmu);
7191  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7192  ast_free(tmp);
7193  SCOPE_EXIT_RTN_VALUE(-1, "Hang up during prefile playback\n");
7194  }
7195  }
7196  if (res == '#') {
7197  /* On a '#' we skip the instructions */
7198  ast_set_flag(options, OPT_SILENT);
7199  res = 0;
7200  }
7201  if (!res && !ast_test_flag(options, OPT_SILENT)) {
7202  res = ast_stream_and_wait(chan, INTRO, ecodes);
7203  if (res == '#') {
7204  ast_set_flag(options, OPT_SILENT);
7205  res = 0;
7206  }
7207  }
7208  if (res > 0)
7209  ast_stopstream(chan);
7210  /* Check for a '*' here in case the caller wants to escape from voicemail to something
7211  other than the operator -- an automated attendant or mailbox login for example */
7212  if (res == '*') {
7213  ast_channel_exten_set(chan, "a");
7214  if (!ast_strlen_zero(vmu->exit)) {
7215  ast_channel_context_set(chan, vmu->exit);
7216  }
7217  ast_channel_priority_set(chan, 0);
7218  free_user(vmu);
7219  pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
7220  ast_free(tmp);
7221  SCOPE_EXIT_RTN_VALUE(0, "User escaped with '*'\n");
7222  }
7223 
7224  /* Check for a '0' here */
7225  if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
7226  transfer:
7227  if (ouseexten) {
7228  ast_channel_exten_set(chan, "o");
7229  if (!ast_strlen_zero(vmu->exit)) {
7230  ast_channel_context_set(chan, vmu->exit);
7231  }
7232  ast_play_and_wait(chan, "transfer");
7233  ast_channel_priority_set(chan, 0);
7234  pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
7235  }
7236  free_user(vmu);
7237  ast_free(tmp);
7238  SCOPE_EXIT_RTN_VALUE(OPERATOR_EXIT, "User escaped with '0'\n");
7239  }
7240 
7241  /* Allow all other digits to exit Voicemail and return to the dialplan */
7242  if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
7243  if (!ast_strlen_zero(options->exitcontext)) {
7244  ast_channel_context_set(chan, options->exitcontext);
7245  }
7246  free_user(vmu);
7247  ast_free(tmp);
7248  pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
7249  SCOPE_EXIT_RTN_VALUE(res, "User escaped back to dialplan '%c'\n", res);
7250  }
7251 
7252  if (greeting_only) {
7253  ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
7254  pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
7255  res = 0;
7256  goto leave_vm_out;
7257  }
7258 
7259  if (res < 0) {
7260  free_user(vmu);
7261  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7262  ast_free(tmp);
7263  SCOPE_EXIT_RTN_VALUE(-1, "Other error '%d'\n", res);
7264  }
7265  /* The meat of recording the message... All the announcements and beeps have been played*/
7266  if (ast_channel_state(chan) != AST_STATE_UP) {
7267  ast_answer(chan);
7268  }
7269  ast_copy_string(fmt, vmfmts, sizeof(fmt));
7270  if (!ast_strlen_zero(fmt)) {
7271  char msg_id[MSG_ID_LEN] = "";
7272  msgnum = 0;
7273 
7274 #ifdef IMAP_STORAGE
7275  /* Is ext a mailbox? */
7276  /* must open stream for this user to get info! */
7277  res = inboxcount(ext_context, &newmsgs, &oldmsgs);
7278  if (res < 0) {
7279  ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
7280  free_user(vmu);
7281  ast_free(tmp);
7282  return -1;
7283  }
7284  if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
7285  /* It is possible under certain circumstances that inboxcount did not
7286  * create a vm_state when it was needed. This is a catchall which will
7287  * rarely be used.
7288  */
7289  if (!(vms = create_vm_state_from_user(vmu))) {
7290  ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
7291  free_user(vmu);
7292  ast_free(tmp);
7293  return -1;
7294  }
7295  }
7296  vms->newmessages++;
7297 
7298  /* here is a big difference! We add one to it later */
7299  msgnum = newmsgs + oldmsgs;
7300  ast_debug(3, "Messagecount set to %d\n", msgnum);
7301  snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
7302  /* set variable for compatibility */
7303  pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
7304 
7305  if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
7306  goto leave_vm_out;
7307  }
7308 #else
7309  if (COUNT(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
7310  res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
7311  if (!res)
7312  res = ast_waitstream(chan, "");
7313  ast_log(AST_LOG_WARNING, "No more messages possible\n");
7314  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7315  inprocess_count(vmu->mailbox, vmu->context, -1);
7316  goto leave_vm_out;
7317  }
7318 
7319 #endif
7320  snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
7321  ast_trace(-1, "Tempfile: %s\n", tmptxtfile);
7322  txtdes = mkstemp(tmptxtfile);
7323  chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
7324  if (txtdes < 0) {
7325  res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
7326  if (!res)
7327  res = ast_waitstream(chan, "");
7328  ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
7329  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7330  inprocess_count(vmu->mailbox, vmu->context, -1);
7331  goto leave_vm_out;
7332  }
7333 
7334  /* Now play the beep once we have the message number for our next message. */
7335  if (res >= 0) {
7336  /* Unless we're *really* silent, try to send the beep */
7337  /* Play default or custom beep, unless no beep desired */
7338  if (!ast_strlen_zero(options->beeptone)) {
7339  res = ast_stream_and_wait(chan, options->beeptone, "");
7340  }
7341  }
7342 
7343  /* Store information in real-time storage */
7344  if (ast_check_realtime("voicemail_data")) {
7345  snprintf(priority, sizeof(priority), "%d", ast_channel_priority(chan));
7346  snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
7347  get_date(date, sizeof(date));
7348  ast_callerid_merge(callerid, sizeof(callerid),
7349  S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7350  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7351  "Unknown");
7352  ast_store_realtime("voicemail_data",
7353  "origmailbox", ext,
7354  "context", ast_channel_context(chan),
7355  "exten", ast_channel_exten(chan),
7356  "priority", priority,
7357  "callerchan", ast_channel_name(chan),
7358  "callerid", callerid,
7359  "origdate", date,
7360  "origtime", origtime,
7361  "category", S_OR(category, ""),
7362  "filename", tmptxtfile,
7363  SENTINEL);
7364  }
7365 
7366  /* Store information */
7367  txt = fdopen(txtdes, "w+");
7368  if (txt) {
7369  generate_msg_id(msg_id);
7370  get_date(date, sizeof(date));
7371  ast_callerid_merge(callerid, sizeof(callerid),
7372  S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7373  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7374  "Unknown");
7375  fprintf(txt,
7376  ";\n"
7377  "; Message Information file\n"
7378  ";\n"
7379  "[message]\n"
7380  "origmailbox=%s\n"
7381  "context=%s\n"
7382  "exten=%s\n"
7383  "rdnis=%s\n"
7384  "priority=%d\n"
7385  "callerchan=%s\n"
7386  "callerid=%s\n"
7387  "origdate=%s\n"
7388  "origtime=%ld\n"
7389  "category=%s\n"
7390  "msg_id=%s\n",
7391  ext,
7392  ast_channel_context(chan),
7393  ast_channel_exten(chan),
7394  S_COR(ast_channel_redirecting(chan)->from.number.valid,
7395  ast_channel_redirecting(chan)->from.number.str, "unknown"),
7396  ast_channel_priority(chan),
7397  ast_channel_name(chan),
7398  callerid,
7399  date, (long) time(NULL),
7400  category ? category : "",
7401  msg_id);
7402  ast_trace(-1, "Saving txt file mbox: %s msg_id: %s\n", ext, msg_id);
7403  } else {
7404  ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
7405  inprocess_count(vmu->mailbox, vmu->context, -1);
7406  if (ast_check_realtime("voicemail_data")) {
7407  ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
7408  }
7409  res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
7410  goto leave_vm_out;
7411  }
7412 
7413  res = SCOPE_CALL_WITH_INT_RESULT(-1, play_record_review, chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag, msg_id, 0);
7414 
7415  /* At this point, either we were instructed to make the message Urgent
7416  by arguments to VoiceMail or during the review process by the person
7417  leaving the message. So we update the directory where we want this
7418  message to go. */
7419  if (!strcmp(flag, "Urgent")) {
7420  create_dirpath(dir, sizeof(dir), vmu->context, ext, "Urgent");
7421  }
7422 
7423  if (txt) {
7424  fprintf(txt, "flag=%s\n", flag);
7425  if (sound_duration < vmu->minsecs) {
7426  fclose(txt);
7427  ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
7428  ast_filedelete(tmptxtfile, NULL);
7429  unlink(tmptxtfile);
7430  if (ast_check_realtime("voicemail_data")) {
7431  ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
7432  }
7433  inprocess_count(vmu->mailbox, vmu->context, -1);
7434  } else {
7435  fprintf(txt, "duration=%d\n", duration);
7436  fclose(txt);
7437  if (vm_lock_path(dir)) {
7438  ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
7439  /* Delete files */
7440  ast_filedelete(tmptxtfile, NULL);
7441  unlink(tmptxtfile);
7442  inprocess_count(vmu->mailbox, vmu->context, -1);
7443  } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
7444  ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
7445  unlink(tmptxtfile);
7446  ast_unlock_path(dir);
7447  inprocess_count(vmu->mailbox, vmu->context, -1);
7448  if (ast_check_realtime("voicemail_data")) {
7449  ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
7450  }
7451  } else {
7452 #ifndef IMAP_STORAGE
7453  msgnum = LAST_MSG_INDEX(dir) + 1;
7454 #endif
7455  make_file(fn, sizeof(fn), dir, msgnum);
7456 
7457  /* assign a variable with the name of the voicemail file */
7458 #ifndef IMAP_STORAGE
7459  pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
7460 #else
7461  pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
7462 #endif
7463 
7464  snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
7465 
7466  ast_trace(-1, "Renaming recordings '%s' -> fn '%s'\n", tmptxtfile, fn);
7467  /* ast_filerename renames the recordings but not the txt file */
7468  ast_filerename(tmptxtfile, fn, NULL);
7469 
7470  ast_trace(-1, "Renaming txt file '%s' -> fn '%s'\n", tmptxtfile, txtfile);
7471  rename(tmptxtfile, txtfile);
7472  inprocess_count(vmu->mailbox, vmu->context, -1);
7473 
7474  /* Properly set permissions on voicemail text descriptor file.
7475  Unfortunately mkstemp() makes this file 0600 on most unix systems. */
7476  if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
7477  ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
7478 
7479  ast_unlock_path(dir);
7480  if (ast_check_realtime("voicemail_data")) {
7481  snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
7482  ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
7483  }
7484  /* We must store the file first, before copying the message, because
7485  * ODBC storage does the entire copy with SQL.
7486  */
7487  if (ast_fileexists(fn, NULL, NULL) > 0) {
7488  SCOPE_CALL(-1, STORE, dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
7489  }
7490 
7491  /* Are there to be more recipients of this message? */
7492  while (tmpptr) {
7493  struct ast_vm_user recipu, *recip;
7494  char *exten, *cntx;
7495 
7496  exten = strsep(&tmpptr, "&");
7497  cntx = strchr(exten, '@');
7498  if (cntx) {
7499  *cntx = '\0';
7500  cntx++;
7501  }
7502  memset(&recipu, 0, sizeof(recipu));
7503  if ((recip = find_user(&recipu, cntx, exten))) {
7504  copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
7505  free_user(recip);
7506  }
7507  }
7508 
7509  /* Notification needs to happen after the copy, though. */
7510  if (ast_fileexists(fn, NULL, NULL)) {
7511 #ifdef IMAP_STORAGE
7512  notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
7513  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7514  S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7515  flag);
7516 #else
7517  notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
7518  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7519  S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7520  flag);
7521 #endif
7522  }
7523 
7524  /* Disposal needs to happen after the optional move and copy */
7525  if (ast_fileexists(fn, NULL, NULL)) {
7526  SCOPE_CALL(-1, DISPOSE, dir, msgnum);
7527  }
7528  }
7529  }
7530  } else {
7531  inprocess_count(vmu->mailbox, vmu->context, -1);
7532  }
7533  if (res == '0') {
7534  goto transfer;
7535  } else if (res > 0 && res != 't')
7536  res = 0;
7537 
7538  if (sound_duration < vmu->minsecs)
7539  /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
7540  pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7541  else
7542  pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
7543  } else
7544  ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
7545 leave_vm_out:
7546  free_user(vmu);
7547 
7548 #ifdef IMAP_STORAGE
7549  /* expunge message - use UID Expunge if supported on IMAP server*/
7550  ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
7551  if (expungeonhangup == 1 && vms->mailstream != NULL) {
7552  ast_mutex_lock(&vms->lock);
7553 #ifdef HAVE_IMAP_TK2006
7554  if (LEVELUIDPLUS (vms->mailstream)) {
7555  mail_expunge_full(vms->mailstream, NIL, EX_UID);
7556  } else
7557 #endif
7558  mail_expunge(vms->mailstream);
7559  ast_mutex_unlock(&vms->lock);
7560  }
7561 #endif
7562 
7563  ast_free(tmp);
7564  SCOPE_EXIT_RTN_VALUE(res, "Done: '%d'\n", res);
7565 }
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.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
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 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.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1141
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3659
char context[MAX_VM_CONTEXT_LEN]
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4190
static int get_date(char *s, int len)
Gets the current date and time, as formatted string.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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 appropria...
Number structure.
Definition: app_followme.c:154
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
Definition: main/config.c:3740
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static void generate_msg_id(char *dst)
Sets the destination string to a uniquely identifying msg_id string.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
#define VM_OPERATOR
Support for dynamic strings.
Definition: strings.h:623
static struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1878
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Destroy realtime configuration.
Definition: main/config.c:3776
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
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...
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:1146
char mailbox[MAX_VM_MBOX_ID_LEN]
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
static int load_config_force ( int  reload,
int  force 
)
static

Reload voicemail.conf.

Parameters
reloadWhether this is a reload as opposed to module load
forceForcefully reload the config, even it has not changed
Return values
0on success, nonzero on failure

Definition at line 14683 of file app_voicemail.c.

References ast_config_destroy(), ast_config_load, ast_unload_realtime(), and CONFIG_FLAG_FILEUNCHANGED.

14684 {
14685  struct ast_config *cfg, *ucfg;
14686  struct ast_flags config_flags = { reload && !force ? CONFIG_FLAG_FILEUNCHANGED : 0 };
14687  int res;
14688 
14689  ast_unload_realtime("voicemail");
14690  ast_unload_realtime("voicemail_data");
14691 
14692  if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14693  if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14694  return 0;
14695  } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
14696  ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
14697  ucfg = NULL;
14698  }
14699  ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
14700  if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
14701  ast_config_destroy(ucfg);
14702  ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14703  return 0;
14704  }
14705  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
14706  ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14707  return 0;
14708  } else {
14709  ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
14710  if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
14711  ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
14712  ucfg = NULL;
14713  }
14714  }
14715 
14716  res = actual_load_config(reload, cfg, ucfg);
14717 
14718  ast_config_destroy(cfg);
14719  ast_config_destroy(ucfg);
14720 
14721  return res;
14722 }
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3576
#define ast_config_load(filename, flags)
Load a config file.
Structure used to handle boolean flags.
Definition: utils.h:199
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS.

If a dependency, allocation or environment variable fails tests, return AST_MODULE_LOAD_FAILURE.

If the module can't load the configuration file, can't register as a provider or has another issue not fatal to Asterisk itself, return AST_MODULE_LOAD_DECLINE.

On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 16300 of file app_voicemail.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_register(), ao2_container_unregister(), ast_cli_register_multiple, ast_custom_function_register, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_realtime_require_field(), ast_register_application_xml, ast_taskprocessor_get(), ast_vm_greeter_register, ast_vm_register, and manager_list_voicemail_users().

16301 {
16302  int res;
16303  my_umask = umask(0);
16304  umask(my_umask);
16305 
16306  inprocess_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 573,
16307  inprocess_hash_fn, NULL, inprocess_cmp_fn);
16308  if (!inprocess_container) {
16309  return AST_MODULE_LOAD_DECLINE;
16310  }
16311 
16312  alias_mailbox_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
16313  alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
16314  if (!alias_mailbox_mappings) {
16315  ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");
16316  ao2_cleanup(inprocess_container);
16317  return AST_MODULE_LOAD_DECLINE;
16318  }
16319  res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
16320  if (res) {
16321  ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");
16322  ao2_cleanup(inprocess_container);
16323  ao2_cleanup(alias_mailbox_mappings);
16324  return AST_MODULE_LOAD_DECLINE;
16325  }
16326 
16327  mailbox_alias_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
16328  mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
16329  if (!mailbox_alias_mappings) {
16330  ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");
16331  ao2_cleanup(inprocess_container);
16332  ao2_container_unregister("voicemail_alias_mailbox_mappings");
16333  ao2_cleanup(alias_mailbox_mappings);
16334  return AST_MODULE_LOAD_DECLINE;
16335  }
16336  res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
16337  if (res) {
16338  ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");
16339  ao2_cleanup(inprocess_container);
16340  ao2_container_unregister("voicemail_alias_mailbox_mappings");
16341  ao2_cleanup(alias_mailbox_mappings);
16342  ao2_cleanup(mailbox_alias_mappings);
16343  return AST_MODULE_LOAD_DECLINE;
16344  }
16345 
16346  /* compute the location of the voicemail spool directory */
16347  snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
16348 
16349  if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
16350  ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
16351  }
16352 
16353  if ((res = load_config(0))) {
16354  unload_module();
16355  return AST_MODULE_LOAD_DECLINE;
16356  }
16357 
16358  res = ast_register_application_xml(voicemail_app, vm_exec);
16359  res |= ast_register_application_xml(voicemailmain_app, vm_execmain);
16360  res |= ast_register_application_xml(vmauthenticate_app, vmauthenticate);
16361  res |= ast_register_application_xml(playmsg_app, vm_playmsgexec);
16362  res |= ast_register_application_xml(sayname_app, vmsayname_exec);
16363  res |= ast_custom_function_register(&vm_info_acf);
16364  res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
16365  res |= ast_manager_register_xml("VoicemailUserStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_status_voicemail_user);
16366  res |= ast_manager_register_xml("VoicemailRefresh", EVENT_FLAG_USER, manager_voicemail_refresh);
16367  res |= ast_manager_register_xml("VoicemailBoxSummary", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_get_mailbox_summary);
16368  res |= ast_manager_register_xml("VoicemailMove", EVENT_FLAG_USER, manager_voicemail_move);
16369  res |= ast_manager_register_xml("VoicemailRemove", EVENT_FLAG_USER, manager_voicemail_remove);
16370  res |= ast_manager_register_xml("VoicemailForward", EVENT_FLAG_USER, manager_voicemail_forward);
16371 #ifdef TEST_FRAMEWORK
16372  res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
16373  res |= AST_TEST_REGISTER(test_voicemail_msgcount);
16374  res |= AST_TEST_REGISTER(test_voicemail_vmuser);
16375  res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
16376  res |= AST_TEST_REGISTER(test_voicemail_load_config);
16377  res |= AST_TEST_REGISTER(test_voicemail_vm_info);
16378 #endif
16379 
16380  if (res) {
16381  ast_log(LOG_ERROR, "Failure registering applications, functions or tests\n");
16382  unload_module();
16383  return AST_MODULE_LOAD_DECLINE;
16384  }
16385 
16386  /* ast_vm_register may return DECLINE if another module registered for vm */
16387  res = ast_vm_register(&vm_table);
16388  if (res) {
16389  ast_log(LOG_ERROR, "Failure registering as a voicemail provider\n");
16390  unload_module();
16391  return AST_MODULE_LOAD_DECLINE;
16392  }
16393 
16394  /* ast_vm_greeter_register may return DECLINE if another module registered as a greeter */
16395  res = ast_vm_greeter_register(&vm_greeter_table);
16396  if (res) {
16397  ast_log(LOG_ERROR, "Failure registering as a greeter provider\n");
16398  unload_module();
16399  return AST_MODULE_LOAD_DECLINE;
16400  }
16401 
16402  ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
16403 
16404 #ifdef TEST_FRAMEWORK
16405  ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16406 #endif
16407 
16408  ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
16409  ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
16410 
16411  return AST_MODULE_LOAD_SUCCESS;
16412 }
static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
Manager list voicemail users command.
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3549
#define ast_vm_register(vm_table)
See __ast_vm_register()
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define ast_vm_greeter_register(vm_table)
See __ast_vm_greeter_register()
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
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
folderThe path is constructed as VM_SPOOL_DIRcontext/ext/folder
Returns
zero on success, -1 on error.

Definition at line 2189 of file app_voicemail.c.

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

2190 {
2191  return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
2192 }
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.
flag,msg_idThe email body, and base 64 encoded attachment (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 5434 of file app_voicemail.c.

References ast_channel_unref, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_dummy_channel_alloc, ast_localtime(), ast_str_buffer(), ast_str_create, ast_str_encode_mime(), ast_str_quote(), ast_str_set(), ast_str_substitute_variables(), ast_strdupa, ast_strftime(), check_mime(), CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::fromstring, ast_vm_user::fullname, ast_vm_user::locale, ast_vm_user::mailbox, make_dir(), make_file(), S_OR, strip_control_and_high(), valid_config(), VM_PBXSKIP, and vmu_tm().

5453 {
5454  char date[256];
5455  char host[MAXHOSTNAMELEN] = "";
5456  char who[256];
5457  char bound[256];
5458  char dur[256];
5459  struct ast_tm tm;
5460  char enc_cidnum[256] = "", enc_cidname[256] = "";
5461  struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
5462  char *greeting_attachment;
5463  char filename[256];
5464  int first_line;
5465  char *emailsbuf;
5466  char *email;
5467 
5468  if (!str1 || !str2) {
5469  ast_free(str1);
5470  ast_free(str2);
5471  return;
5472  }
5473 
5474  if (cidnum) {
5475  strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
5476  }
5477  if (cidname) {
5478  strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
5479  }
5480  gethostname(host, sizeof(host) - 1);
5481 
5482  if (strchr(srcemail, '@')) {
5483  ast_copy_string(who, srcemail, sizeof(who));
5484  } else {
5485  snprintf(who, sizeof(who), "%s@%s", srcemail, host);
5486  }
5487 
5488  greeting_attachment = strrchr(ast_strdupa(attach), '/');
5489  if (greeting_attachment) {
5490  *greeting_attachment++ = '\0';
5491  }
5492 
5493  snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
5494  ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
5495  fprintf(p, "Date: %s" ENDL, date);
5496 
5497  /* Set date format for voicemail mail */
5498  ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
5499 
5500  if (!ast_strlen_zero(fromstring) || !ast_strlen_zero(vmu->fromstring)) {
5501  struct ast_channel *ast;
5502  char *e_fromstring = !ast_strlen_zero(vmu->fromstring) ? vmu->fromstring : fromstring;
5503  if ((ast = ast_dummy_channel_alloc())) {
5504  char *ptr;
5505  prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5506  ast_str_substitute_variables(&str1, 0, ast, e_fromstring);
5507 
5508  if (check_mime(ast_str_buffer(str1))) {
5509  first_line = 1;
5510  ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
5511  while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
5512  *ptr = '\0';
5513  fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
5514  first_line = 0;
5515  /* Substring is smaller, so this will never grow */
5516  ast_str_set(&str2, 0, "%s", ptr + 1);
5517  }
5518  fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
5519  } else {
5520  fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
5521  }
5522  ast = ast_channel_unref(ast);
5523  } else {
5524  ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
5525  }
5526  } else {
5527  fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
5528  }
5529 
5530  emailsbuf = ast_strdupa(vmu->email);
5531  fprintf(p, "To:");
5532  first_line = 1;
5533  while ((email = strsep(&emailsbuf, "|"))) {
5534  char *next = emailsbuf;
5535  if (check_mime(vmu->fullname)) {
5536  char *ptr;
5537  ast_str_encode_mime(&str2, 0, vmu->fullname, first_line ? strlen("To: ") : 0, strlen(email) + 3 + (next ? strlen(",") : 0));
5538  while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
5539  *ptr = '\0';
5540  fprintf(p, " %s" ENDL, ast_str_buffer(str2));
5541  /* Substring is smaller, so this will never grow */
5542  ast_str_set(&str2, 0, "%s", ptr + 1);
5543  }
5544  fprintf(p, " %s <%s>%s" ENDL, ast_str_buffer(str2), email, next ? "," : "");
5545  } else {
5546  fprintf(p, " %s <%s>%s" ENDL, ast_str_quote(&str2, 0, vmu->fullname), email, next ? "," : "");
5547  }
5548  first_line = 0;
5549  }
5550 
5551  if (msgnum <= -1) {
5552  fprintf(p, "Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date);
5553  } else if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
5554  char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
5555  struct ast_channel *ast;
5556  if ((ast = ast_dummy_channel_alloc())) {
5557  prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5558  ast_str_substitute_variables(&str1, 0, ast, e_subj);
5559  if (check_mime(ast_str_buffer(str1))) {
5560  char *ptr;
5561  first_line = 1;
5562  ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
5563  while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
5564  *ptr = '\0';
5565  fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
5566  first_line = 0;
5567  /* Substring is smaller, so this will never grow */
5568  ast_str_set(&str2, 0, "%s", ptr + 1);
5569  }
5570  fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
5571  } else {
5572  fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
5573  }
5574  ast = ast_channel_unref(ast);
5575  } else {
5576  ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
5577  }
5578  } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
5579  if (ast_strlen_zero(flag)) {
5580  fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5581  } else {
5582  fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5583  }
5584  } else {
5585  if (ast_strlen_zero(flag)) {
5586  fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5587  } else {
5588  fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5589  }
5590  }
5591 
5592  fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
5593  (unsigned int) ast_random(), mailbox, (int) getpid(), host);
5594  if (imap) {
5595  /* additional information needed for IMAP searching */
5596  fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
5597  /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
5598  fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
5599  fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
5600 #ifdef IMAP_STORAGE
5601  fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
5602 #else
5603  fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
5604 #endif
5605  /* flag added for Urgent */
5606  fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, S_OR(flag, ""));
5607  fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan ? ast_channel_priority(chan) : 0);
5608  fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
5609  fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
5610  fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
5611  if (!ast_strlen_zero(category)) {
5612  fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
5613  } else {
5614  fprintf(p, "X-Asterisk-VM-Category: " ENDL);
5615  }
5616  fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
5617  fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
5618  fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
5619  fprintf(p, "X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
5620  }
5621  if (!ast_strlen_zero(cidnum)) {
5622  fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
5623  }
5624  if (!ast_strlen_zero(cidname)) {
5625  fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
5626  }
5627  fprintf(p, "MIME-Version: 1.0" ENDL);
5628  if (attach_user_voicemail) {
5629  /* Something unique. */
5630  snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
5631  (int) getpid(), (unsigned int) ast_random());
5632 
5633  fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
5634  fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
5635  fprintf(p, "--%s" ENDL, bound);
5636  }
5637  fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
5638  if (msgnum <= -1) {
5639  fprintf(p, "This message is to let you know that your greeting '%s' was changed on %s." ENDL
5640  "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL,
5641  greeting_attachment, date);
5642  } else if (emailbody || vmu->emailbody) {
5643  char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
5644  struct ast_channel *ast;
5645  if ((ast = ast_dummy_channel_alloc())) {
5646  prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5647  ast_str_substitute_variables(&str1, 0, ast, e_body);
5648 #ifdef IMAP_STORAGE
5649  {
5650  /* Convert body to native line terminators for IMAP backend */
5651  char *line = ast_str_buffer(str1), *next;
5652  do {
5653  /* Terminate line before outputting it to the file */
5654  if ((next = strchr(line, '\n'))) {
5655  *next++ = '\0';
5656  }
5657  fprintf(p, "%s" ENDL, line);
5658  line = next;
5659  } while (!ast_strlen_zero(line));
5660  }
5661 #else
5662  fprintf(p, "%s" ENDL, ast_str_buffer(str1));
5663 #endif
5664  ast = ast_channel_unref(ast);
5665  } else {
5666  ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
5667  }
5668  } else {
5669  if (strcmp(vmu->mailbox, mailbox)) {
5670  /* Forwarded type */
5671  struct ast_config *msg_cfg;
5672  const char *v;
5673  int inttime;
5674  char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
5675  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
5676  /* Retrieve info from VM attribute file */
5677  make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
5678  make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
5679  if (strlen(fromfile) < sizeof(fromfile) - 5) {
5680  strcat(fromfile, ".txt");
5681  }
5682  if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
5683  if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
5684  ast_copy_string(origcallerid, v, sizeof(origcallerid));
5685  }
5686 
5687  /* You might be tempted to do origdate, except that a) it's in the wrong
5688  * format, and b) it's missing for IMAP recordings. */
5689  if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
5690  struct timeval tv = { inttime, };
5691  struct ast_tm tm;
5692  ast_localtime(&tv, &tm, NULL);
5693  ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
5694  }
5695  fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
5696  " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
5697  "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
5698  " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
5699  msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
5700  date, origcallerid, origdate);
5701  ast_config_destroy(msg_cfg);
5702  } else {
5703  goto plain_message;
5704  }
5705  } else {
5706 plain_message:
5707  fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
5708  "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
5709  "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
5710  ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
5711  (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
5712  }
5713  }
5714 
5715  if (imap || attach_user_voicemail) {
5716  if (!ast_strlen_zero(attach2)) {
5717  snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
5718  ast_debug(5, "creating second attachment filename %s\n", filename);
5719  add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
5720  snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
5721  ast_debug(5, "creating attachment filename %s\n", filename);
5722  add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5723  } else {
5724  snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
5725  ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
5726  add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5727  }
5728  }
5729  ast_free(str1);
5730  ast_free(str2);
5731 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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 appropria...
char context[AST_MAX_CONTEXT]
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
static int check_mime(const char *str)
Check if the string would need encoding within the MIME standard, to avoid confusing certain mail sof...
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
char locale[20]
#define ast_config_load(filename, flags)
Load a config file.
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.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
#define ast_debug(level,...)
Log a DEBUG message.
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...
#define VM_PBXSKIP
char fromstring[100]
char * emailbody
Support for dynamic strings.
Definition: strings.h:623
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
Structure used to handle boolean flags.
Definition: utils.h:199
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
char * emailsubject
char fullname[80]
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
static const struct ast_tm * vmu_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 struct ast_flags globalflags
Definition: app_minivm.c:699
char mailbox[MAX_VM_MBOX_ID_LEN]
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 ...
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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
numThe path is constructed as VM_SPOOL_DIRcontext/ext/folder
Returns
zero on success, -1 on error.

Definition at line 2206 of file app_voicemail.c.

Referenced by advanced_options(), copy_message(), forward_message(), leave_voicemail(), make_email_file(), message_range_and_existence_check(), notify_new_message(), save_to_folder(), vm_forwardoptions(), and vm_msg_snapshot_create().

2207 {
2208  return snprintf(dest, len, "%s/msg%04d", dir, num);
2209 }
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
[out]msg_numsThe message indexes corresponding to the given
vmumessage IDs
Precondition
vms must have open_mailbox() called on it prior to this function.
Return values
-1Failure
0Success

Definition at line 17278 of file app_voicemail.c.

References ast_config_destroy(), ast_config_load, CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::mailbox, and make_file().

17279 {
17280  int i;
17281  int res = 0;
17282  for (i = 0; i < num_msgs; ++i) {
17283  const char *msg_id = msg_ids[i];
17284  int found = 0;
17285  for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17286  const char *other_msg_id;
17287  char filename[PATH_MAX];
17288  struct ast_config *msg_cfg;
17289  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17290 
17291  make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
17292  snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
17293  RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
17294  msg_cfg = ast_config_load(filename, config_flags);
17295  if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17296  DISPOSE(vms->curdir, vms->curmsg);
17297  res = -1;
17298  goto done;
17299  }
17300 
17301  other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
17302 
17303  if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17304  /* Message found. We can get out of this inner loop
17305  * and move on to the next message to find
17306  */
17307  found = 1;
17308  msg_nums[i] = vms->curmsg;
17309  ast_config_destroy(msg_cfg);
17310  DISPOSE(vms->curdir, vms->curmsg);
17311  break;
17312  }
17313  ast_config_destroy(msg_cfg);
17314  DISPOSE(vms->curdir, vms->curmsg);
17315  }
17316  if (!found) {
17317  /* If we can't find one of the message IDs requested, then OH NO! */
17318  res = -1;
17319  goto done;
17320  }
17321  }
17322 
17323 done:
17324  return res;
17325 }
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
#define ast_config_load(filename, flags)
Load a config file.
Structure used to handle boolean flags.
Definition: utils.h:199
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
char mailbox[MAX_VM_MBOX_ID_LEN]
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 8566 of file app_voicemail.c.

References ast_app_has_voicemail(), ast_app_inboxcount2(), ast_config_destroy(), ast_config_load, ast_strdupa, ast_vm_user::attachfmt, CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::email, ast_vm_user::mailbox, make_dir(), make_file(), ast_vm_user::pager, pbx_builtin_getvar_helper(), run_externnotify(), ast_vm_user::serveremail, VM_ATTACH, VM_DELETE, and vm_delete().

Referenced by copy_message(), and leave_voicemail().

8567 {
8568  char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
8569  int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8570  const char *category;
8571  char *myserveremail = serveremail;
8572 
8573  ast_channel_lock(chan);
8574  if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
8575  category = ast_strdupa(category);
8576  }
8577  ast_channel_unlock(chan);
8578 
8579 #ifndef IMAP_STORAGE
8580  make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
8581 #else
8582  snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
8583 #endif
8584  make_file(fn, sizeof(fn), todir, msgnum);
8585  snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
8586 
8587  if (!ast_strlen_zero(vmu->attachfmt)) {
8588  if (strstr(fmt, vmu->attachfmt))
8589  fmt = vmu->attachfmt;
8590  else
8591  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);
8592  }
8593 
8594  /* Attach only the first format */
8595  fmt = ast_strdupa(fmt);
8596  stringp = fmt;
8597  strsep(&stringp, "|");
8598 
8599  if (!ast_strlen_zero(vmu->serveremail))
8600  myserveremail = vmu->serveremail;
8601 
8602  if (!ast_strlen_zero(vmu->email)) {
8603  int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
8604  char *msg_id = NULL;
8605 #ifdef IMAP_STORAGE
8606  struct ast_config *msg_cfg;
8607  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8608  char filename[PATH_MAX];
8609 
8610  snprintf(filename, sizeof(filename), "%s.txt", fn);
8611  msg_cfg = ast_config_load(filename, config_flags);
8612  if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8613  msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
8614  ast_config_destroy(msg_cfg);
8615  }
8616 #endif
8617 
8618  if (attach_user_voicemail)
8619  RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
8620 
8621  /* XXX possible imap issue, should category be NULL XXX */
8622  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);
8623 
8624  if (attach_user_voicemail)
8625  DISPOSE(todir, msgnum);
8626  }
8627 
8628  if (!ast_strlen_zero(vmu->pager)) {
8629  sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
8630  }
8631 
8632  if (ast_test_flag(vmu, VM_DELETE))
8633  DELETE(todir, msgnum, fn, vmu);
8634 
8635  /* Leave voicemail for someone */
8636  if (ast_app_has_voicemail(ext_context, NULL))
8637  ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
8638 
8639  queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
8640  run_externnotify(vmu->context, vmu->mailbox, flag);
8641 
8642 #ifdef IMAP_STORAGE
8643  vm_delete(fn); /* Delete the file, but not the IMAP message */
8644  if (ast_test_flag(vmu, VM_DELETE)) { /* Delete the IMAP message if delete = yes */
8645  vm_imap_delete(NULL, vms->curmsg, vmu);
8646  vms->newmessages--; /* Fix new message count */
8647  }
8648 #endif
8649 
8650  return 0;
8651 }
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 appropria...
#define VM_ATTACH
char pager[80]
char context[MAX_VM_CONTEXT_LEN]
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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 appropria...
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Definition: main/app.c:619
#define ast_config_load(filename, flags)
Load a config file.
#define VM_DELETE
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int vm_delete(char *file)
Removes the voicemail sound and information file.
Structure used to handle boolean flags.
Definition: utils.h:199
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
Definition: main/app.c:582
char serveremail[80]
char attachfmt[20]
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
static void run_externnotify(struct ast_channel *chan, struct minivm_account *vmu)
Run external notification for voicemail message.
Definition: app_minivm.c:1643
char mailbox[MAX_VM_MBOX_ID_LEN]
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 11875 of file app_voicemail.c.

References ast_copy_string(), and find_user().

11876 {
11877  struct vm_state vms;
11878  struct ast_vm_user *vmu = NULL, vmus;
11879  int res = 0;
11880  int open = 0;
11881  int played = 0;
11882  int i;
11883 
11884  memset(&vmus, 0, sizeof(vmus));
11885  memset(&vms, 0, sizeof(vms));
11886 
11887  if (!(vmu = find_user(&vmus, context, mailbox))) {
11888  goto play_msg_cleanup;
11889  }
11890 
11891  /* Iterate through every folder, find the msg, and play it */
11892  for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
11893  ast_copy_string(vms.username, mailbox, sizeof(vms.username));
11894  vms.lastmsg = -1;
11895 
11896  /* open the mailbox state */
11897  if ((res = open_mailbox(&vms, vmu, i)) < 0) {
11898  ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
11899  res = -1;
11900  goto play_msg_cleanup;
11901  }
11902  open = 1;
11903 
11904  /* play msg if it exists in this mailbox */
11905  if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
11906  played = 1;
11907  }
11908 
11909  /* close mailbox */
11910  if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
11911  res = -1;
11912  goto play_msg_cleanup;
11913  }
11914  open = 0;
11915  }
11916 
11917 play_msg_cleanup:
11918  if (!played) {
11919  res = -1;
11920  }
11921 
11922  if (vmu && open) {
11923  close_mailbox(&vms, vmu);
11924  }
11925 
11926 #ifdef IMAP_STORAGE
11927  if (vmu) {
11928  vmstate_delete(&vms);
11929  }
11930 #endif
11931 
11932  free_user(vmu);
11933 
11934  return res;
11935 }
char context[MAX_VM_CONTEXT_LEN]
static struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char mailbox[MAX_VM_MBOX_ID_LEN]
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 1478 of file app_voicemail.c.

References ast_copy_string(), ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::locale, ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, ast_vm_user::passwordlocation, ast_vm_user::volgain, and ast_vm_user::zonetag.

Referenced by create_vmaccount(), and find_user_realtime().

1479 {
1480  ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
1482  if (saydurationminfo) {
1483  vmu->saydurationm = saydurationminfo;
1484  }
1485  ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
1486  ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
1487  ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
1488  ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
1489  ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
1490  if (vmminsecs) {
1491  vmu->minsecs = vmminsecs;
1492  }
1493  if (vmmaxsecs) {
1494  vmu->maxsecs = vmmaxsecs;
1495  }
1496  if (maxmsg) {
1497  vmu->maxmsg = maxmsg;
1498  }
1499  if (maxdeletedmsg) {
1501  }
1502  vmu->volgain = volgain;
1503  ast_free(vmu->email);
1504  vmu->email = NULL;
1505  ast_free(vmu->emailsubject);
1506  vmu->emailsubject = NULL;
1507  ast_free(vmu->emailbody);
1508  vmu->emailbody = NULL;
1509 #ifdef IMAP_STORAGE
1510  ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
1511  ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
1512  ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
1513  ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
1514 #endif
1515 }
double volgain
char locale[20]
char zonetag[80]
int passwordlocation
char * emailbody
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * emailsubject
static struct ast_flags globalflags
Definition: app_minivm.c:699
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 5033 of file app_voicemail.c.

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

5034 {
5035  char stxt[PATH_MAX];
5036  char dtxt[PATH_MAX];
5037  ast_filerename(sfn, dfn, NULL);
5038  snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
5039  snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
5040  if (ast_check_realtime("voicemail_data")) {
5041  ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
5042  }
5043  rename(stxt, dtxt);
5044 }
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3659
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:1146
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 2006 of file app_voicemail.c.

References ast_copy_string(), ast_json_pack(), ast_json_unref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_manager_publish_event(), ast_vm_user::context, ast_vm_user::mailbox, ast_vm_user::password, and S_OR.

Referenced by vm_change_password().

2007 {
2008  /* This function could be made to generate one from a database, too */
2009  struct ast_vm_user *cur;
2010  int res = -1;
2011  AST_LIST_LOCK(&users);
2012  AST_LIST_TRAVERSE(&users, cur, list) {
2013  if ((!context || !strcasecmp(context, cur->context)) &&
2014  (!strcasecmp(mailbox, cur->mailbox)))
2015  break;
2016  }
2017  if (cur) {
2018  ast_copy_string(cur->password, newpass, sizeof(cur->password));
2019  res = 0;
2020  }
2022  if (!res) {
2023  struct ast_json *json_object;
2024 
2025  json_object = ast_json_pack("{s: s, s: s, s: s}",
2026  "Context", S_OR(context, "default"),
2027  "Mailbox", mailbox,
2028  "NewPassword", newpass);
2029  ast_manager_publish_event("VoicemailPasswordChange", EVENT_FLAG_SYSTEM | EVENT_FLAG_USER, json_object);
2030  ast_json_unref(json_object);
2031  }
2032  return res;
2033 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
char password[80]
list of users found in the config file
char context[MAX_VM_CONTEXT_LEN]
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
Abstract JSON element (object, array, string, int, ...).
char mailbox[MAX_VM_MBOX_ID_LEN]
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition: manager.c:2063
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
otherFailure

Definition at line 7605 of file app_voicemail.c.

References ast_debug, ast_unlock_path(), ast_vm_user::context, create_dirpath(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, and vm_lock_path().

7606 {
7607 #ifdef IMAP_STORAGE
7608  /* we must use mbox(x) folder names, and copy the message there */
7609  /* simple. huh? */
7610  char sequence[10];
7611  char mailbox[256];
7612  int res;
7613  int curr_mbox;
7614 
7615  /* get the real IMAP message number for this message */
7616  snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
7617 
7618  ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
7619  ast_mutex_lock(&vms->lock);
7620  /* if save to Old folder, put in INBOX as read */
7621  if (box == OLD_FOLDER) {
7622  mail_setflag(vms->mailstream, sequence, "\\Seen");
7623  } else if (box == NEW_FOLDER) {
7624  mail_clearflag(vms->mailstream, sequence, "\\Seen");
7625  }
7626  if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
7627  ast_mutex_unlock(&vms->lock);
7628  return 0;
7629  }
7630 
7631  /* get the current mailbox so that we can point the mailstream back to it later */
7632  curr_mbox = get_folder_by_name(vms->curbox);
7633 
7634  /* Create the folder if it doesn't exist */
7635  imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */
7636  if (vms->mailstream && !mail_status(vms->mailstream, mailbox, SA_UIDNEXT)) {
7637  if (mail_create(vms->mailstream, mailbox) != NIL) {
7638  ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
7639  }
7640  }
7641 
7642  /* restore previous mbox stream */
7643  if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7644  ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
7645  res = -1;
7646  } else {
7647  if (move) {
7648  res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box));
7649  } else {
7650  res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
7651  }
7652  }
7653  ast_mutex_unlock(&vms->lock);
7654  return res;
7655 #else
7656  char *dir = vms->curdir;
7657  char *username = vms->username;
7658  char *context = vmu->context;
7659  char sfn[PATH_MAX];
7660  char dfn[PATH_MAX];
7661  char ddir[PATH_MAX];
7662  const char *dbox = mbox(vmu, box);
7663  int x, i;
7664  SCOPE_ENTER(3, "dir: %s msg: %d box: %d dbox: %s move? %d \n", dir, msg, box, dbox, move);
7665 
7666  create_dirpath(ddir, sizeof(ddir), context, username, dbox);
7667  ast_trace(-1, "ddir: %s\n", ddir);
7668 
7669  if (vm_lock_path(ddir)) {
7670  SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH, "Failed to lock path %s\n", ddir);
7671  }
7672 
7673  x = LAST_MSG_INDEX(ddir) + 1;
7674 
7675  if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/
7676  ast_trace(-1, "Deleting message %d\n", msg);
7677  x--;
7678  for (i = 1; i <= x; i++) {
7679  /* Push files down a "slot". The oldest file (msg0000) will be deleted. */
7680  make_file(sfn, sizeof(sfn), ddir, i);
7681  make_file(dfn, sizeof(dfn), ddir, i - 1);
7682  if (EXISTS(ddir, i, sfn, NULL)) {
7683  SCOPE_CALL(-1, RENAME, ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
7684  } else
7685  break;
7686  }
7687  } else {
7688  if (x >= vmu->maxmsg) {
7689  ast_unlock_path(ddir);
7690  SCOPE_EXIT_RTN_VALUE(ERROR_MAX_MSGS, "Max messages reached\n");
7691  }
7692  }
7693  make_file(sfn, sizeof(sfn), dir, msg);
7694  make_file(dfn, sizeof(dfn), ddir, x);
7695  if (strcmp(sfn, dfn)) {
7696  ast_trace(-1, "Copying message '%s' to '%s'\n", sfn, dfn);
7697  SCOPE_CALL(-1, COPY, dir, msg, ddir, x, username, context, sfn, dfn);
7698  }
7699  ast_unlock_path(ddir);
7700 
7701  if (newmsg) {
7702  *newmsg = x;
7703  }
7704  SCOPE_EXIT_RTN_VALUE(0, "Done\n");
7705 #endif
7706 }
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
basically mkdir -p $dest/$context/$ext/$folder
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
#define ast_debug(level,...)
Log a DEBUG message.
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...
char mailbox[MAX_VM_MBOX_ID_LEN]
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 1318 of file app_voicemail.c.

Referenced by make_email_file().

1319 {
1320  char *bufptr = buf;
1321  for (; *input; input++) {
1322  if (*input < 32) {
1323  continue;
1324  }
1325  *bufptr++ = *input;
1326  if (bufptr == buf + buflen - 1) {
1327  break;
1328  }
1329  }
1330  *bufptr = '\0';
1331  return buf;
1332 }
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 11674 of file app_voicemail.c.

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

11675 {
11676  if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH */
11677  return vm_browse_messages_es(chan, vms, vmu);
11678  } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK */
11679  return vm_browse_messages_gr(chan, vms, vmu);
11680  } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW */
11681  return vm_browse_messages_he(chan, vms, vmu);
11682  } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN */
11683  return vm_browse_messages_it(chan, vms, vmu);
11684  } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE */
11685  return vm_browse_messages_ja(chan, vms, vmu);
11686  } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE */
11687  return vm_browse_messages_pt(chan, vms, vmu);
11688  } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE */
11689  return vm_browse_messages_vi(chan, vms, vmu);
11690  } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) */
11691  return vm_browse_messages_zh(chan, vms, vmu);
11692  } else { /* Default to English syntax */
11693  return vm_browse_messages_en(chan, vms, vmu);
11694  }
11695 }
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_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_ja(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Japanese 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_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_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_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Chinese (Taiwan)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_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 11486 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11487 {
11488  int cmd = 0;
11489 
11490  if (vms->lastmsg > -1) {
11491  cmd = play_message(chan, vmu, vms);
11492  } else {
11493  cmd = ast_play_and_wait(chan, "vm-youhave");
11494  if (!cmd)
11495  cmd = ast_play_and_wait(chan, "vm-no");
11496  if (!cmd) {
11497  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11498  cmd = ast_play_and_wait(chan, vms->fn);
11499  }
11500  if (!cmd)
11501  cmd = ast_play_and_wait(chan, "vm-messages");
11502  }
11503  return cmd;
11504 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11567 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11568 {
11569  int cmd;
11570 
11571  if (vms->lastmsg > -1) {
11572  cmd = play_message(chan, vmu, vms);
11573  } else {
11574  cmd = ast_play_and_wait(chan, "vm-youhaveno");
11575  if (!cmd)
11576  cmd = ast_play_and_wait(chan, "vm-messages");
11577  if (!cmd) {
11578  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11579  cmd = ast_play_and_wait(chan, vms->fn);
11580  }
11581  }
11582  return cmd;
11583 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11434 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11435 {
11436  int cmd = 0;
11437 
11438  if (vms->lastmsg > -1) {
11439  cmd = play_message(chan, vmu, vms);
11440  } else {
11441  cmd = ast_play_and_wait(chan, "vm-youhaveno");
11442  if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
11443  if (!cmd) {
11444  snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
11445  cmd = ast_play_and_wait(chan, vms->fn);
11446  }
11447  if (!cmd)
11448  cmd = ast_play_and_wait(chan, "vm-messages");
11449  } else {
11450  if (!cmd)
11451  cmd = ast_play_and_wait(chan, "vm-messages");
11452  if (!cmd) {
11453  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11454  cmd = ast_play_and_wait(chan, vms->fn);
11455  }
11456  }
11457  }
11458  return cmd;
11459 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11514 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11515 {
11516  int cmd;
11517 
11518  if (vms->lastmsg > -1) {
11519  cmd = play_message(chan, vmu, vms);
11520  } else {
11521  cmd = ast_play_and_wait(chan, "vm-no");
11522  if (!cmd)
11523  cmd = ast_play_and_wait(chan, "vm-message");
11524  if (!cmd) {
11525  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11526  cmd = ast_play_and_wait(chan, vms->fn);
11527  }
11528  }
11529  return cmd;
11530 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
static int vm_browse_messages_ja ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
)
static

Japanese syntax for 'You have N messages' greeting.

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

Definition at line 11540 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11541 {
11542  int cmd = 0;
11543 
11544  if (vms->lastmsg > -1) {
11545  cmd = play_message(chan, vmu, vms);
11546  } else {
11547  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11548  cmd = ast_play_and_wait(chan, vms->fn);
11549  if (!cmd)
11550  cmd = ast_play_and_wait(chan, "vm-messages");
11551  if (!cmd)
11552  cmd = ast_play_and_wait(chan, "jp-wa");
11553  if (!cmd)
11554  cmd = ast_play_and_wait(chan, "jp-arimasen");
11555  }
11556  return cmd;
11557 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11593 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11594 {
11595  int cmd;
11596 
11597  if (vms->lastmsg > -1) {
11598  cmd = play_message(chan, vmu, vms);
11599  } else {
11600  cmd = ast_play_and_wait(chan, "vm-no");
11601  if (!cmd) {
11602  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11603  cmd = ast_play_and_wait(chan, vms->fn);
11604  }
11605  if (!cmd)
11606  cmd = ast_play_and_wait(chan, "vm-messages");
11607  }
11608  return cmd;
11609 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11647 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11648 {
11649  int cmd = 0;
11650 
11651  if (vms->lastmsg > -1) {
11652  cmd = play_message(chan, vmu, vms);
11653  } else {
11654  cmd = ast_play_and_wait(chan, "vm-no");
11655  if (!cmd) {
11656  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11657  cmd = ast_play_and_wait(chan, vms->fn);
11658  }
11659  }
11660  return cmd;
11661 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 11619 of file app_voicemail.c.

References ast_play_and_wait().

Referenced by vm_browse_messages().

11620 {
11621  int cmd;
11622 
11623  if (vms->lastmsg > -1) {
11624  cmd = play_message(chan, vmu, vms);
11625  } else {
11626  cmd = ast_play_and_wait(chan, "vm-you");
11627  if (!cmd)
11628  cmd = ast_play_and_wait(chan, "vm-haveno");
11629  if (!cmd)
11630  cmd = ast_play_and_wait(chan, "vm-messages");
11631  if (!cmd) {
11632  snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11633  cmd = ast_play_and_wait(chan, vms->fn);
11634  }
11635  }
11636  return cmd;
11637 }
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
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 2050 of file app_voicemail.c.

References ast_category_browse(), ast_category_get(), ast_config_destroy(), ast_config_load, ast_config_text_file_save(), ast_copy_string(), ast_debug, ast_malloc, ast_test_suite_event_notify, ast_variable_update(), change_password_realtime(), CONFIG_FLAG_WITHCOMMENTS, ast_vm_user::context, ast_vm_user::mailbox, ast_vm_user::password, ast_vm_user::passwordlocation, reset_user_pw(), and valid_config().

2051 {
2052  struct ast_config *cfg = NULL;
2053  struct ast_variable *var = NULL;
2054  struct ast_category *cat = NULL;
2055  char *category = NULL;
2056  const char *tmp = NULL;
2057  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
2058  char secretfn[PATH_MAX] = "";
2059  int found = 0;
2060 
2061  if (!change_password_realtime(vmu, newpassword))
2062  return;
2063 
2064  /* check if we should store the secret in the spool directory next to the messages */
2065  switch (vmu->passwordlocation) {
2066  case OPT_PWLOC_SPOOLDIR:
2067  snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
2068  if (write_password_to_file(secretfn, newpassword) == 0) {
2069  ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
2070  ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
2071  reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2072  ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2073  break;
2074  } else {
2075  ast_log(LOG_WARNING, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2076  }
2077  /* Fall-through */
2078  case OPT_PWLOC_VOICEMAILCONF:
2079  if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
2080  while ((category = ast_category_browse(cfg, category))) {
2081  if (!strcasecmp(category, vmu->context)) {
2082  char *value = NULL;
2083  char *new = NULL;
2084  if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
2085  ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
2086  break;
2087  }
2088  value = strstr(tmp, ",");
2089  if (!value) {
2090  new = ast_malloc(strlen(newpassword) + 1);
2091  sprintf(new, "%s", newpassword);
2092  } else {
2093  new = ast_malloc((strlen(value) + strlen(newpassword) + 1));
2094  sprintf(new, "%s%s", newpassword, value);
2095  }
2096  if (!(cat = ast_category_get(cfg, category, NULL))) {
2097  ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
2098  ast_free(new);
2099  break;
2100  }
2101  ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
2102  found = 1;
2103  ast_free(new);
2104  }
2105  }
2106  /* save the results */
2107  if (found) {
2108  ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2109  reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2110  ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2111  ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "app_voicemail");
2112  ast_config_destroy(cfg);
2113  break;
2114  }
2115 
2116  ast_config_destroy(cfg);
2117  }
2118  /* Fall-through */
2119  case OPT_PWLOC_USERSCONF:
2120  /* check users.conf and update the password stored for the mailbox */
2121  /* if no vmsecret entry exists create one. */
2122  if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
2123  ast_debug(4, "we are looking for %s\n", vmu->mailbox);
2124  for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
2125  ast_debug(4, "users.conf: %s\n", category);
2126  if (!strcasecmp(category, vmu->mailbox)) {
2127  char new[strlen(newpassword) + 1];
2128  if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
2129  ast_debug(3, "looks like we need to make vmsecret!\n");
2130  var = ast_variable_new("vmsecret", newpassword, "");
2131  } else {
2132  var = NULL;
2133  }
2134 
2135  sprintf(new, "%s", newpassword);
2136  if (!(cat = ast_category_get(cfg, category, NULL))) {
2137  ast_debug(4, "failed to get category!\n");
2138  ast_free(var);
2139  break;
2140  }
2141  if (!var) {
2142  ast_variable_update(cat, "vmsecret", new, NULL, 0);
2143  } else {
2144  ast_variable_append(cat, var);
2145  }
2146  found = 1;
2147  break;
2148  }
2149  }
2150  /* save the results and clean things up */
2151  if (found) {
2152  ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
2153  reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2154  ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2155  ast_config_text_file_save("users.conf", cfg, "app_voicemail");
2156  }
2157 
2158  ast_config_destroy(cfg);
2159  }
2160  }
2161 }
int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator)
Save a config text file preserving the pre 13.2 behavior.
Definition: main/config.c:2701
Structure for variables, used for configurations and for channel variables.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
char password[80]
char context[MAX_VM_CONTEXT_LEN]
#define ast_config_load(filename, flags)
Load a config 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.
int passwordlocation
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
Definition: main/config.c:1533
Structure used to handle boolean flags.
Definition: utils.h:199
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1111
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
char mailbox[MAX_VM_MBOX_ID_LEN]
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
Resets a user password to a specified password.
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 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 5221 of file app_voicemail.c.

References ast_alloca, ast_check_realtime(), ast_destroy_realtime(), and ast_filedelete().

Referenced by copy_message(), and notify_new_message().

5222 {
5223  char *txt;
5224  int txtsize = 0;
5225  int res = 0;
5226  SCOPE_ENTER(3, "file: %s\n", file);
5227 
5228  txtsize = (strlen(file) + 5)*sizeof(char);
5229  txt = ast_alloca(txtsize);
5230  /* Sprintf here would safe because we alloca'd exactly the right length,
5231  * but trying to eliminate all sprintf's anyhow
5232  */
5233  if (ast_check_realtime("voicemail_data")) {
5234  ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
5235  }
5236  snprintf(txt, txtsize, "%s.txt", file);
5237  ast_trace(-1, "unlinking '%s'\n", txt);
5238  unlink(txt);
5239  ast_trace(-1, "deleting sound files '%s'\n", file);
5240  res = ast_filedelete(file, NULL);
5241  SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d\n", res);
5242 }
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1141
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Destroy realtime configuration.
Definition: main/config.c:3776
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
flagPresents 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 8348 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_update(), ast_waitfordigit(), CONFIG_FLAG_NOCACHE, copy(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxsecs, and valid_config().

Referenced by forward_message().

8351 {
8352  int cmd = 0;
8353  int retries = 0, prepend_duration = 0, already_recorded = 0;
8354  char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
8355  char textfile[PATH_MAX];
8356  struct ast_config *msg_cfg;
8357  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8358 #ifndef IMAP_STORAGE
8359  signed char zero_gain = 0;
8360 #else
8361  const char *msg_id = NULL;
8362 #endif
8363  const char *duration_str;
8364  SCOPE_ENTER(3, "mbox: %s msgnum: %d curdir: %s", vmu->mailbox, curmsg, curdir);
8365 
8366  /* Must always populate duration correctly */
8367  make_file(msgfile, sizeof(msgfile), curdir, curmsg);
8368  ast_trace(-1, "msgfile: %s\n", msgfile);
8369  strcpy(textfile, msgfile);
8370  strcpy(backup, msgfile);
8371  strcpy(backup_textfile, msgfile);
8372  strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
8373  strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
8374  strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8375 
8376  if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
8377  *duration = atoi(duration_str);
8378  } else {
8379  *duration = 0;
8380  }
8381 
8382  while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
8383  if (cmd)
8384  retries = 0;
8385  switch (cmd) {
8386  case '1':
8387 
8388 #ifdef IMAP_STORAGE
8389  /* Record new intro file */
8390  if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8391  msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
8392  }
8393  make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
8394  strncat(vms->introfn, "intro", sizeof(vms->introfn));
8395  ast_play_and_wait(chan, "vm-record-prepend");
8396  ast_play_and_wait(chan, "beep");
8397  cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag, msg_id, 1);
8398  if (cmd == -1) {
8399  break;
8400  }
8401  cmd = 't';
8402 #else
8403 
8404  /* prepend a message to the current message, update the metadata and return */
8405  ast_trace(-1, "Prepending to message %d\n", curmsg);
8406 
8407  make_file(msgfile, sizeof(msgfile), curdir, curmsg);
8408  ast_trace(-1, "msgfile: %s\n", msgfile);
8409 
8410  strcpy(textfile, msgfile);
8411  strncat(textfile, ".txt", sizeof(textfile) - 1);
8412  *duration = 0;
8413 
8414  /* if we can't read the message metadata, stop now */
8415  if (!valid_config(msg_cfg)) {
8416  cmd = 0;
8417  break;
8418  }
8419 
8420  /* Back up the original file, so we can retry the prepend and restore it after forward. */
8421 #ifndef IMAP_STORAGE
8422  if (already_recorded) {
8423  ast_trace(-1, "Restoring '%s' to '%s'\n", backup, msgfile);
8424  ast_filecopy(backup, msgfile, NULL);
8425  copy(backup_textfile, textfile);
8426  }
8427  else {
8428  ast_trace(-1, "Backing up '%s' to '%s'\n", backup, msgfile);
8429  ast_filecopy(msgfile, backup, NULL);
8430  copy(textfile, backup_textfile);
8431  }
8432 #endif
8433  already_recorded = 1;
8434 
8435  if (record_gain)
8436  ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
8437 
8438  cmd = SCOPE_CALL_WITH_INT_RESULT(-1, ast_play_and_prepend, chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
8439 
8440  if (cmd == 'S') { /* If we timed out, tell the user it didn't work properly and clean up the files */
8441  ast_stream_and_wait(chan, vm_pls_try_again, ""); /* this might be removed if a proper vm_prepend_timeout is ever recorded */
8442  ast_stream_and_wait(chan, vm_prepend_timeout, "");
8443  ast_filerename(backup, msgfile, NULL);
8444  }
8445 
8446  if (record_gain)
8447  ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
8448 
8449 
8450  if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
8451  *duration = atoi(duration_str);
8452 
8453  if (prepend_duration) {
8454  struct ast_category *msg_cat;
8455  /* need enough space for a maximum-length message duration */
8456  char duration_buf[12];
8457 
8458  *duration += prepend_duration;
8459  ast_trace(-1, "Prepending duration: %d total duration: %ld\n", prepend_duration, *duration);
8460  msg_cat = ast_category_get(msg_cfg, "message", NULL);
8461  snprintf(duration_buf, sizeof(duration_buf), "%ld", *duration);
8462  if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
8463  ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
8464  }
8465  }
8466 
8467 #endif
8468  break;
8469  case '2':
8470  /* NULL out introfile so we know there is no intro! */
8471 #ifdef IMAP_STORAGE
8472  *vms->introfn = '\0';
8473 #endif
8474  cmd = 't';
8475  break;
8476  case '*':
8477  cmd = '*';
8478  break;
8479  default:
8480  /* If time_out and return to menu, reset already_recorded */
8481  already_recorded = 0;
8482 
8483  cmd = ast_play_and_wait(chan, "vm-forwardoptions");
8484  /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
8485  if (!cmd) {
8486  cmd = ast_play_and_wait(chan, "vm-starmain");
8487  /* "press star to return to the main menu" */
8488  }
8489  if (!cmd) {
8490  cmd = ast_waitfordigit(chan, 6000);
8491  }
8492  if (!cmd) {
8493  retries++;
8494  }
8495  if (retries > 3) {
8496  cmd = '*'; /* Let's cancel this beast */
8497  }
8498  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8499  isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
8500  }
8501  }
8502 
8503  if (valid_config(msg_cfg))
8504  ast_config_destroy(msg_cfg);
8505  if (prepend_duration)
8506  *duration = prepend_duration;
8507 
8508  if (already_recorded && cmd == -1) {
8509  /* restore original message if prepention cancelled */
8510  ast_trace(-1, "Restoring '%s' to '%s'\n", backup, msgfile);
8511  ast_filerename(backup, msgfile, NULL);
8512  rename(backup_textfile, textfile);
8513  }
8514 
8515  if (cmd == 't' || cmd == 'S') { /* XXX entering this block with a value of 'S' is probably no longer possible. */
8516  cmd = 0;
8517  }
8518  SCOPE_EXIT_RTN_VALUE(cmd, "Done. CMD: %d %c\n", cmd, cmd >= 32 && cmd < 127 ? cmd : '?');
8519 }
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
Definition: file.c:1151
int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator)
Save a config text file preserving the pre 13.2 behavior.
Definition: main/config.c:2701
static int copy(char *infile, char *outfile)
Utility function to copy a file.
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms)
Record a file based on input frm a channel. Recording is performed in 'prepend' mode which works a li...
Definition: main/app.c:2159
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7422
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 appropria...
#define ast_config_load(filename, flags)
Load a config file.
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
#define AST_OPTION_RXGAIN
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1878
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
Definition: main/config.c:1533
Structure used to handle boolean flags.
Definition: utils.h:199
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:1146
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1111
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
char mailbox[MAX_VM_MBOX_ID_LEN]
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
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 17012 of file app_voicemail.c.

References 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_string_field_set, CONFIG_FLAG_NOCACHE, ast_vm_user::context, ast_vm_user::mailbox, and make_file().

17019 {
17020  struct ast_vm_msg_snapshot *msg_snapshot;
17021  struct ast_vm_msg_snapshot *msg_snapshot_tmp;
17022  struct ast_config *msg_cfg;
17023  struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17024  char filename[PATH_MAX];
17025  const char *value;
17026 
17027  for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17028  int inserted = 0;
17029  /* Find the msg */
17030  make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
17031  snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
17032  RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
17033  msg_cfg = ast_config_load(filename, config_flags);
17034  if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17035  DISPOSE(vms->curdir, vms->curmsg);
17036  continue;
17037  }
17038 
17039  /* Create the snapshot object */
17040  if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
17041  ast_config_destroy(msg_cfg);
17042  return -1;
17043  }
17044 
17045  /* Fill in the snapshot object */
17046  if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
17047  ast_string_field_set(msg_snapshot, msg_id, value);
17048  } else {
17049  /* Message snapshots *really* should have a
17050  * message ID. Add one to the message config
17051  * if it does not already exist
17052  */
17053  char id[MSG_ID_LEN];
17054  if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
17055  filename, id, sizeof(id), vmu, mailbox_index))) {
17056  ast_string_field_set(msg_snapshot, msg_id, id);
17057  } else {
17058  ast_log(LOG_WARNING, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
17059  }
17060  }
17061  if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
17062  ast_string_field_set(msg_snapshot, callerid, value);
17063  }
17064  if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
17065  ast_string_field_set(msg_snapshot, callerchan, value);
17066  }
17067  if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
17068  ast_string_field_set(msg_snapshot, exten, value);
17069  }
17070  if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
17071  ast_string_field_set(msg_snapshot, origdate, value);
17072  }
17073  if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
17074  ast_string_field_set(msg_snapshot, origtime, value);
17075  }
17076  if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
17077  ast_string_field_set(msg_snapshot, duration, value);
17078  }
17079  if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
17080  ast_string_field_set(msg_snapshot, flag, value);
17081  }
17082  msg_snapshot->msg_number = vms->curmsg;
17083  ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);
17084 
17085  /* store msg snapshot in mailbox snapshot */
17086  switch (sort_val) {
17087  default:
17088  case AST_VM_SNAPSHOT_SORT_BY_ID:
17089  if (descending) {
17090  AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17091  } else {
17092  AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17093  }
17094  inserted = 1;
17095  break;
17096  case AST_VM_SNAPSHOT_SORT_BY_TIME:
17097  AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
17098  int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
17099  if (descending && val >= 0) {
17100  AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17101  inserted = 1;
17102  break;
17103  } else if (!descending && val <= 0) {
17104  AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17105  inserted = 1;
17106  break;
17107  }
17108  }
17110  break;
17111  }
17112 
17113  if (!inserted) {
17114  AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17115  }
17116 
17117  mailbox_snapshot->total_msg_num++;
17118 
17119  /* cleanup configs and msg */
17120  ast_config_destroy(msg_cfg);
17121  DISPOSE(vms->curdir, vms->curmsg);
17122  }
17123 
17124  return 0;
17125 }
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
char context[MAX_VM_CONTEXT_LEN]
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 appropria...
#define ast_config_load(filename, flags)
Load a config file.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
Structure used to handle boolean flags.
Definition: utils.h:199
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
char mailbox[MAX_VM_MBOX_ID_LEN]
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
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 11359 of file app_voicemail.c.

References ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_voice_mode(), ast_fileexists(), ast_play_and_wait(), ast_test_suite_event_notify, ast_waitfordigit(), ast_vm_user::context, and ast_vm_user::mailbox.

11360 {
11361  int cmd = 0;
11362  int retries = 0;
11363  int duration = 0;
11364  char prefile[PATH_MAX] = "";
11365  unsigned char buf[256];
11366  int bytes = 0;
11367 
11368  if (ast_adsi_available(chan)) {
11369  bytes += adsi_logo(buf + bytes);
11370  bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
11371  bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
11372  bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
11373  bytes += ast_adsi_voice_mode(buf + bytes, 0);
11374  ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
11375  }
11376 
11377  ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
11378  snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
11379  while ((cmd >= 0) && (cmd != 't')) {
11380  if (cmd)
11381  retries = 0;
11382  RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
11383  if (ast_fileexists(prefile, NULL, NULL) <= 0) {
11384  cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11385  if (cmd == -1) {
11386  break;
11387  }
11388  cmd = 't';
11389  } else {
11390  switch (cmd) {
11391  case '1':
11392  cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11393  break;
11394  case '2':
11395  DELETE(prefile, -1, prefile, vmu);
11396  ast_play_and_wait(chan, "vm-tempremoved");
11397  cmd = 't';
11398  break;
11399  case '*':
11400  cmd = 't';
11401  break;
11402  default:
11403  cmd = ast_play_and_wait(chan,
11404  ast_fileexists(prefile, NULL, NULL) > 0 ? /* XXX always true ? */
11405  "vm-tempgreeting2" : "vm-tempgreeting");
11406  if (!cmd) {
11407  cmd = ast_waitfordigit(chan, 6000);
11408  }
11409  if (!cmd) {
11410  retries++;
11411  }
11412  if (retries > 3) {
11413  cmd = 't';
11414  }
11415  ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
11416  isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
11417  }
11418  }
11419  DISPOSE(prefile, -1);
11420  }
11421  if (cmd == 't')
11422  cmd = 0;
11423  return cmd;
11424 }
int ast_adsi_voice_mode(unsigned char *buf, int when)
Puts CPE in voice mode.
Definition: adsi.c:252
char context[MAX_VM_CONTEXT_LEN]
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
Definition: adsi.c:285
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1616
int ast_adsi_display(unsigned char *buf, int page, int line, int just, int wrap, char *col1, char *col2)
Loads a line of info into the display.
Definition: adsi.c:274
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
Definition: adsi.c:263
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
char mailbox[MAX_VM_MBOX_ID_LEN]
static const struct ast_tm* vmu_tm ( const struct ast_vm_user vmu,
struct ast_tm tm 
)
static

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 5328 of file app_voicemail.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_tvnow(), and ast_vm_user::zonetag.

Referenced by make_email_file().

5329 {
5330  const struct vm_zone *z = NULL;
5331  struct timeval t = ast_tvnow();
5332 
5333  /* Does this user have a timezone specified? */
5334  if (!ast_strlen_zero(vmu->zonetag)) {
5335  /* Find the zone in the list */
5336  AST_LIST_LOCK(&zones);
5337  AST_LIST_TRAVERSE(&zones, z, list) {
5338  if (!strcmp(z->name, vmu->zonetag))
5339  break;
5340  }
5342  }
5343  ast_localtime(&t, tm, z ? z->timezone : NULL);
5344  return tm;
5345 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
char zonetag[80]
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491

Variable Documentation

struct ast_mwi_observer mwi_observer
Initial value:
= {
.on_subscribe = mwi_handle_subscribe,
.on_unsubscribe = mwi_handle_unsubscribe,
}

Definition at line 14118 of file app_voicemail.c.

unsigned int poll_freq = DEFAULT_POLL_FREQ
static

Polling frequency

Definition at line 1087 of file app_voicemail.c.

unsigned int poll_mailboxes
static

Poll mailboxes for changes since there is something external to app_voicemail that may change them.

Definition at line 1082 of file app_voicemail.c.

struct ast_custom_function vm_info_acf
static
Initial value:
= {
.name = "VM_INFO",
.read = acf_vm_info,
}

Definition at line 13676 of file app_voicemail.c.