Asterisk - The Open Source Telephony Project GIT-master-7988d11
Loading...
Searching...
No Matches
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"
Include dependency graph for app_voicemail.c:

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 }
 

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)
 
static int add_email_attachment (FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
 
static int add_message_id (struct ast_config *msg_cfg, char *dir, int msg, char *filename, char *id, size_t id_size, struct ast_vm_user *vmu, int folder)
 
static void adsi_begin (struct ast_channel *chan, int *useadsi)
 
static void adsi_delete (struct ast_channel *chan, struct vm_state *vms)
 
static void adsi_folders (struct ast_channel *chan, int start, char *label)
 
static void adsi_goodbye (struct ast_channel *chan)
 
static int adsi_load_vmail (struct ast_channel *chan, int *useadsi)
 
static void adsi_login (struct ast_channel *chan)
 
static int adsi_logo (unsigned char *buf)
 
static void adsi_message (struct ast_channel *chan, struct vm_state *vms)
 
static void adsi_password (struct ast_channel *chan)
 
static void adsi_status (struct ast_channel *chan, struct vm_state *vms)
 
static void adsi_status2 (struct ast_channel *chan, struct vm_state *vms)
 
static int advanced_options (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
 The advanced options within a message.
 
static 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.
 
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.
 
static void apply_option (struct ast_vm_user *vmu, const char *var, const char *value)
 Sets a specific property value.
 
static void apply_options (struct ast_vm_user *vmu, const char *options)
 Destructively Parse options and apply.
 
static void apply_options_full (struct ast_vm_user *retval, struct ast_variable *var)
 Loads the options specific to a voicemail user.
 
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.
 
static const char * ast_str_quote (struct ast_str **buf, ssize_t maxlen, const char *from)
 Wraps a character sequence in double quotes, escaping occurrences of quotes within the string.
 
static int change_password_realtime (struct ast_vm_user *vmu, const char *password)
 Performs a change of the voicemail password in the realtime engine.
 
static int check_mime (const char *str)
 Check if the string would need encoding within the MIME standard, to avoid confusing certain mail software that expects messages to be 7-bit clean.
 
static int check_password (struct ast_vm_user *vmu, char *password)
 Check that password meets minimum required length.
 
static int close_mailbox (struct vm_state *vms, struct ast_vm_user *vmu)
 
static char * complete_voicemail_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.
 
static int copy_message (struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag, const char *dest_folder)
 Copies a message from one mailbox to another.
 
static void copy_plain_file (char *frompath, char *topath)
 Copies a voicemail information (envelope) file.
 
static int count_messages (struct ast_vm_user *vmu, char *dir)
 Find all .txt files - even if they are not in sequence from 0000.
 
static int create_dirpath (char *dest, int len, const char *context, const char *ext, const char *folder)
 basically mkdir -p $dest/$context/$ext/$folder
 
static int dialout (struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
 
static struct ast_vm_userfind_or_create (const char *context, const char *box)
 
static struct ast_vm_userfind_user (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the users file or the realtime engine.
 
static struct ast_vm_userfind_user_realtime (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the realtime engine.
 
static int forward_message (struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
 Sends a voicemail message to a mailbox recipient.
 
static 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.
 
static int get_date (char *s, int len)
 Gets the current date and time, as formatted string.
 
static int get_folder (struct ast_channel *chan, int start)
 get_folder: Folder menu Plays "press 1 for INBOX messages" etc. Should possibly be internationalized
 
static int get_folder2 (struct ast_channel *chan, char *fn, int start)
 plays a prompt and waits for a keypress.
 
static int get_folder_by_name (const char *name)
 
static int 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.
 
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.
 
static int inprocess_cmp_fn (void *obj, void *arg, int flags)
 
static int inprocess_count (const char *context, const char *mailbox, int delta)
 
static int inprocess_hash_fn (const void *obj, const int flags)
 
static int invent_message (struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
 
static int is_valid_dtmf (const char *key)
 Determines if a DTMF key entered is valid.
 
static int last_message_index (char *dir)
 Determines the highest message number in use for a given user and mailbox folder.
 
static int leave_voicemail (struct ast_channel *chan, char *ext, struct leave_vm_options *options)
 Prompts the user and records a voicemail to a mailbox.
 
static 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.
 
static int load_module (void)
 Load the module.
 
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.
 
static void make_email_file (FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag, const char *msg_id)
 Creates the email file to be sent to indicate a new voicemail exists for a user.
 
static int make_file (char *dest, const int len, const char *dir, const int num)
 Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
 
static int manager_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.
 
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.
 
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.
 
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.
 
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.
 
static int resequence_mailbox (struct ast_vm_user *vmu, char *dir, int stopcount)
 
static int reset_user_pw (const char *context, const char *mailbox, const char *newpass)
 Resets a user password to a specified password.
 
static void run_externnotify (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.
 
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.
 
static int vm_browse_messages_en (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Default English syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_es (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Spanish syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_gr (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Greek syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_he (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 
static int vm_browse_messages_it (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Italian syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_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_pt (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Portuguese syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_vi (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Vietnamese syntax for 'You have N messages' greeting.
 
static int vm_browse_messages_zh (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Chinese (Taiwan)syntax for 'You have N messages' greeting.
 
static void vm_change_password (struct ast_vm_user *vmu, const char *newpassword)
 The handler for the change password option.
 
static void vm_change_password_shell (struct ast_vm_user *vmu, char *newpassword)
 
static char * vm_check_password_shell (char *command, char *buf, size_t len)
 
static int vm_delete (char *file)
 Removes the voicemail sound and information file.
 
static int vm_exec (struct ast_channel *chan, const char *data)
 
static int vm_execmain (struct ast_channel *chan, const char *data)
 
static int vm_forwardoptions (struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts, char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
 presents the option to prepend to an existing message when forwarding it.
 
static const char * vm_index_to_foldername (int id)
 
static int vm_instructions (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, 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.
 
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'.
 
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.
 
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 = tdesc , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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 = AST_MUTEX_INIT_VALUE
 
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 = AST_LIST_HEAD_INIT_VALUE
 
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 = AST_LIST_HEAD_INIT_VALUE
 
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

◆ ALIASES_OUTPUT_FORMAT

#define ALIASES_OUTPUT_FORMAT   "%-32s %-32s\n"

◆ ASTERISK_USERNAME

#define ASTERISK_USERNAME   "asterisk"

Definition at line 686 of file app_voicemail.c.

◆ CHUNKSIZE

#define CHUNKSIZE   65536

Definition at line 683 of file app_voicemail.c.

◆ COMMAND_TIMEOUT

#define COMMAND_TIMEOUT   5000

Definition at line 679 of file app_voicemail.c.

◆ COPY

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

Definition at line 1061 of file app_voicemail.c.

◆ COUNT

#define COUNT (   a,
  b 
)    count_messages(a,b)

Definition at line 1054 of file app_voicemail.c.

◆ DEFAULT_LISTEN_CONTROL_FORWARD_KEY

#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY   "#"

Definition at line 691 of file app_voicemail.c.

◆ DEFAULT_LISTEN_CONTROL_PAUSE_KEY

#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY   "0"

Definition at line 693 of file app_voicemail.c.

◆ DEFAULT_LISTEN_CONTROL_RESTART_KEY

#define DEFAULT_LISTEN_CONTROL_RESTART_KEY   "2"

Definition at line 694 of file app_voicemail.c.

◆ DEFAULT_LISTEN_CONTROL_REVERSE_KEY

#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY   "*"

Definition at line 692 of file app_voicemail.c.

◆ DEFAULT_LISTEN_CONTROL_STOP_KEY

#define DEFAULT_LISTEN_CONTROL_STOP_KEY   "13456789"

Definition at line 695 of file app_voicemail.c.

◆ DEFAULT_POLL_FREQ

#define DEFAULT_POLL_FREQ   30

By default, poll every 30 seconds

Definition at line 1130 of file app_voicemail.c.

◆ DELETE

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

Definition at line 1062 of file app_voicemail.c.

◆ DISPOSE

#define DISPOSE (   a,
  b 
)

Definition at line 1057 of file app_voicemail.c.

◆ ENDL

#define ENDL   "\n"

Definition at line 713 of file app_voicemail.c.

◆ ERROR_LOCK_PATH

#define ERROR_LOCK_PATH   -100

Definition at line 742 of file app_voicemail.c.

◆ ERROR_MAX_MSGS

#define ERROR_MAX_MSGS   -101

Definition at line 743 of file app_voicemail.c.

◆ EXISTS

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

Definition at line 1059 of file app_voicemail.c.

◆ force_reload_config

#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.

Definition at line 832 of file app_voicemail.c.

◆ HVSU_OUTPUT_FORMAT

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

◆ HVSZ_OUTPUT_FORMAT

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

◆ INTRO

#define INTRO   "vm-intro"

Definition at line 701 of file app_voicemail.c.

◆ LAST_MSG_INDEX

#define LAST_MSG_INDEX (   a)    last_message_index(a)

Definition at line 1055 of file app_voicemail.c.

◆ MAPPING_BUCKETS

#define MAPPING_BUCKETS   511

Definition at line 1153 of file app_voicemail.c.

◆ MAX_DATETIME_FORMAT

#define MAX_DATETIME_FORMAT   512

Definition at line 716 of file app_voicemail.c.

◆ MAX_MAIL_BODY_CONTENT_SIZE

#define MAX_MAIL_BODY_CONTENT_SIZE   134217728L

Definition at line 703 of file app_voicemail.c.

◆ MAX_NUM_CID_CONTEXTS

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 717 of file app_voicemail.c.

◆ MAX_VM_CONTEXT_LEN

#define MAX_VM_CONTEXT_LEN   (AST_MAX_CONTEXT)

Definition at line 933 of file app_voicemail.c.

◆ MAX_VM_MAILBOX_LEN

#define MAX_VM_MAILBOX_LEN   (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)

Definition at line 935 of file app_voicemail.c.

◆ MAX_VM_MBOX_ID_LEN

#define MAX_VM_MBOX_ID_LEN   (AST_MAX_EXTENSION)

Definition at line 932 of file app_voicemail.c.

◆ MAXMSG

#define MAXMSG   100

Definition at line 705 of file app_voicemail.c.

◆ MAXMSGLIMIT

#define MAXMSGLIMIT   9999

Definition at line 706 of file app_voicemail.c.

◆ MINPASSWORD

#define MINPASSWORD   0

Default minimum mailbox password length

Definition at line 708 of file app_voicemail.c.

◆ MSG_ID_LEN

#define MSG_ID_LEN   256

Definition at line 4018 of file app_voicemail.c.

◆ MSGFILE_LEN

#define MSGFILE_LEN   (7)

Length of the message file name: msgXXXX

Definition at line 746 of file app_voicemail.c.

◆ OPERATOR_EXIT

#define OPERATOR_EXIT   300

Definition at line 744 of file app_voicemail.c.

◆ PWDCHANGE_EXTERNAL

#define PWDCHANGE_EXTERNAL   (1 << 2)

Definition at line 1075 of file app_voicemail.c.

◆ PWDCHANGE_INTERNAL

#define PWDCHANGE_INTERNAL   (1 << 1)

Definition at line 1074 of file app_voicemail.c.

◆ RENAME

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

Definition at line 1060 of file app_voicemail.c.

◆ RETRIEVE

#define RETRIEVE (   a,
  b,
  c,
  d 
)

Definition at line 1056 of file app_voicemail.c.

◆ SENDMAIL

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

Definition at line 700 of file app_voicemail.c.

◆ SMDI_MWI_WAIT_TIMEOUT

#define SMDI_MWI_WAIT_TIMEOUT   1000 /* 1 second */

Definition at line 677 of file app_voicemail.c.

◆ STORE

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

Definition at line 1058 of file app_voicemail.c.

◆ tdesc

#define tdesc   "Comedian Mail (Voicemail System)"

Definition at line 1084 of file app_voicemail.c.

◆ UPDATE_MSG_ID

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

Definition at line 1063 of file app_voicemail.c.

◆ VALID_DTMF

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

Definition at line 696 of file app_voicemail.c.

◆ VM_ALLOCED

#define VM_ALLOCED   (1 << 13)

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

Definition at line 732 of file app_voicemail.c.

◆ VM_ATTACH

#define VM_ATTACH   (1 << 11)

Attach message to voicemail notifications?

Definition at line 730 of file app_voicemail.c.

◆ VM_DELETE

#define VM_DELETE   (1 << 12)

Delete message after sending notification

Definition at line 731 of file app_voicemail.c.

◆ VM_DIRECTFORWARD

#define VM_DIRECTFORWARD   (1 << 10)

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

Definition at line 729 of file app_voicemail.c.

◆ VM_EMAIL_EXT_RECS

#define VM_EMAIL_EXT_RECS   (1 << 19)

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

Definition at line 738 of file app_voicemail.c.

◆ VM_ENVELOPE

#define VM_ENVELOPE   (1 << 4)

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

Definition at line 723 of file app_voicemail.c.

◆ VM_FORCEGREET

#define VM_FORCEGREET   (1 << 8)

Have new users record their greetings

Definition at line 727 of file app_voicemail.c.

◆ VM_FORCENAME

#define VM_FORCENAME   (1 << 7)

Have new users record their name

Definition at line 726 of file app_voicemail.c.

◆ VM_FWDURGAUTO

#define VM_FWDURGAUTO   (1 << 18)

Autoset of Urgent flag on forwarded Urgent messages set globally

Definition at line 737 of file app_voicemail.c.

◆ VM_MARK_URGENT

#define VM_MARK_URGENT   (1 << 20)

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

Definition at line 739 of file app_voicemail.c.

◆ VM_MESSAGEWRAP

#define VM_MESSAGEWRAP   (1 << 17)

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

Definition at line 736 of file app_voicemail.c.

◆ VM_MOVEHEARD

#define VM_MOVEHEARD   (1 << 16)

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

Definition at line 735 of file app_voicemail.c.

◆ VM_ODBC_AUDIO_ON_DISK

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

◆ VM_OPERATOR

#define VM_OPERATOR   (1 << 1)

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

Definition at line 720 of file app_voicemail.c.

◆ VM_PBXSKIP

#define VM_PBXSKIP   (1 << 9)

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

Definition at line 728 of file app_voicemail.c.

◆ VM_REVIEW

#define VM_REVIEW   (1 << 0)

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

Definition at line 719 of file app_voicemail.c.

◆ VM_SAYCID

#define VM_SAYCID   (1 << 2)

Repeat the CallerID info during envelope playback

Definition at line 721 of file app_voicemail.c.

◆ VM_SAYDURATION

#define VM_SAYDURATION   (1 << 5)

Play the length of the message during envelope playback

Definition at line 724 of file app_voicemail.c.

◆ VM_SEARCH

#define VM_SEARCH   (1 << 14)

Search all contexts for a matching mailbox

Definition at line 733 of file app_voicemail.c.

◆ VM_SKIPAFTERCMD

#define VM_SKIPAFTERCMD   (1 << 6)

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

Definition at line 725 of file app_voicemail.c.

◆ VM_STRING_HEADER_FORMAT

#define VM_STRING_HEADER_FORMAT   "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"

◆ VM_SVMAIL

#define VM_SVMAIL   (1 << 3)

Allow the user to compose a new VM from within VoicemailMain

Definition at line 722 of file app_voicemail.c.

◆ VM_TEMPGREETWARN

#define VM_TEMPGREETWARN   (1 << 15)

Remind user tempgreeting is set

Definition at line 734 of file app_voicemail.c.

◆ VMBOX_STRING_DATA_FORMAT

#define VMBOX_STRING_DATA_FORMAT   "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"

◆ VMBOX_STRING_HEADER_FORMAT

#define VMBOX_STRING_HEADER_FORMAT   "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"

◆ VMSTATE_MAX_MSG_ARRAY

#define VMSTATE_MAX_MSG_ARRAY   256

Definition at line 987 of file app_voicemail.c.

◆ VOICEMAIL_CONFIG

#define VOICEMAIL_CONFIG   "voicemail.conf"

Definition at line 685 of file app_voicemail.c.

◆ VOICEMAIL_DIR_MODE

#define VOICEMAIL_DIR_MODE   0777

Definition at line 681 of file app_voicemail.c.

◆ VOICEMAIL_FILE_MODE

#define VOICEMAIL_FILE_MODE   0666

Definition at line 682 of file app_voicemail.c.

Enumeration Type Documentation

◆ vm_box

enum vm_box
Enumerator
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 

Definition at line 748 of file app_voicemail.c.

748 {
749 NEW_FOLDER = 0,
750 OLD_FOLDER = 1,
751 WORK_FOLDER = 2,
752 FAMILY_FOLDER = 3,
753 FRIENDS_FOLDER = 4,
755};
@ FRIENDS_FOLDER
@ NEW_FOLDER
@ GREETINGS_FOLDER
@ FAMILY_FOLDER
@ WORK_FOLDER
@ OLD_FOLDER

◆ vm_option_args

Enumerator
OPT_ARG_RECORDGAIN 
OPT_ARG_PLAYFOLDER 
OPT_ARG_DTMFEXIT 
OPT_ARG_BEEP_TONE 
OPT_ARG_ARRAY_SIZE 

Definition at line 773 of file app_voicemail.c.

773 {
778 /* This *must* be the last value in this enum! */
780};
@ OPT_ARG_RECORDGAIN
@ OPT_ARG_PLAYFOLDER
@ OPT_ARG_BEEP_TONE
@ OPT_ARG_ARRAY_SIZE
@ OPT_ARG_DTMFEXIT

◆ vm_option_flags

Enumerator
OPT_SILENT 
OPT_BUSY_GREETING 
OPT_UNAVAIL_GREETING 
OPT_RECORDGAIN 
OPT_PREPEND_MAILBOX 
OPT_AUTOPLAY 
OPT_DTMFEXIT 
OPT_MESSAGE_Urgent 
OPT_MESSAGE_PRIORITY 
OPT_EARLYM_GREETING 
OPT_BEEP 
OPT_SILENT_IF_GREET 
OPT_READONLY 

Definition at line 757 of file app_voicemail.c.

757 {
758 OPT_SILENT = (1 << 0),
759 OPT_BUSY_GREETING = (1 << 1),
760 OPT_UNAVAIL_GREETING = (1 << 2),
761 OPT_RECORDGAIN = (1 << 3),
762 OPT_PREPEND_MAILBOX = (1 << 4),
763 OPT_AUTOPLAY = (1 << 6),
764 OPT_DTMFEXIT = (1 << 7),
765 OPT_MESSAGE_Urgent = (1 << 8),
766 OPT_MESSAGE_PRIORITY = (1 << 9),
767 OPT_EARLYM_GREETING = (1 << 10),
768 OPT_BEEP = (1 << 11),
769 OPT_SILENT_IF_GREET = (1 << 12),
770 OPT_READONLY = (1 << 13),
771};
@ OPT_MESSAGE_PRIORITY
@ OPT_PREPEND_MAILBOX
@ OPT_BEEP
@ OPT_BUSY_GREETING
@ OPT_RECORDGAIN
@ OPT_EARLYM_GREETING
@ OPT_SILENT_IF_GREET
@ OPT_UNAVAIL_GREETING
@ OPT_READONLY
@ OPT_SILENT
@ OPT_DTMFEXIT
@ OPT_MESSAGE_Urgent
@ OPT_AUTOPLAY

◆ vm_passwordlocation

Enumerator
OPT_PWLOC_VOICEMAILCONF 
OPT_PWLOC_SPOOLDIR 

Definition at line 782 of file app_voicemail.c.

782 {
785};
@ OPT_PWLOC_SPOOLDIR
@ OPT_PWLOC_VOICEMAILCONF

Function Documentation

◆ __has_voicemail()

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

Definition at line 6435 of file app_voicemail.c.

6436{
6437 DIR *dir;
6438 struct dirent *de;
6439 char fn[256];
6440 int ret = 0;
6441 struct alias_mailbox_mapping *mapping;
6442 char *c;
6443 char *m;
6444
6445 /* If no mailbox, return immediately */
6447 return 0;
6448
6449 if (ast_strlen_zero(folder))
6450 folder = "INBOX";
6451 if (ast_strlen_zero(context))
6452 context = "default";
6453
6454 c = (char *)context;
6455 m = (char *)mailbox;
6456
6458 char tmp[MAX_VM_MAILBOX_LEN];
6459
6460 snprintf(tmp, MAX_VM_MAILBOX_LEN, "%s@%s", mailbox, context);
6462 if (mapping) {
6463 separate_mailbox(ast_strdupa(mapping->mailbox), &m, &c);
6464 ao2_ref(mapping, -1);
6465 }
6466 }
6467
6468 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, c, m, folder);
6469
6470 if (!(dir = opendir(fn)))
6471 return 0;
6472
6473 while ((de = readdir(dir))) {
6474 if (!strncasecmp(de->d_name, "msg", 3)) {
6475 if (shortcircuit) {
6476 ret = 1;
6477 break;
6478 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
6479 ret++;
6480 }
6481 }
6482 }
6483
6484 closedir(dir);
6485
6486 return ret;
6487}
static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
static char aliasescontext[MAX_VM_CONTEXT_LEN]
#define MAX_VM_MAILBOX_LEN
static char VM_SPOOL_DIR[PATH_MAX]
static struct ao2_container * alias_mailbox_mappings
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
static struct test_val c

References alias_mailbox_mappings, aliasescontext, ao2_find, ao2_ref, ast_strdupa, ast_strlen_zero(), c, alias_mailbox_mapping::mailbox, MAX_VM_MAILBOX_LEN, OBJ_SEARCH_KEY, separate_mailbox(), and VM_SPOOL_DIR.

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

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 17755 of file app_voicemail.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 17755 of file app_voicemail.c.

◆ acf_vm_info()

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

Definition at line 13614 of file app_voicemail.c.

13615{
13616 struct ast_vm_user svm;
13617 struct ast_vm_user *vmu = NULL;
13618 char *parse;
13619 char *mailbox;
13620 char *context;
13621 int res = 0;
13622
13624 AST_APP_ARG(mailbox_context);
13625 AST_APP_ARG(attribute);
13626 AST_APP_ARG(folder);
13627 );
13628
13629 buf[0] = '\0';
13630
13631 if (ast_strlen_zero(args)) {
13632 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13633 return -1;
13634 }
13635
13636 parse = ast_strdupa(args);
13637 AST_STANDARD_APP_ARGS(arg, parse);
13638
13639 if (ast_strlen_zero(arg.mailbox_context)
13640 || ast_strlen_zero(arg.attribute)
13641 || separate_mailbox(ast_strdupa(arg.mailbox_context), &mailbox, &context)) {
13642 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13643 return -1;
13644 }
13645
13646 memset(&svm, 0, sizeof(svm));
13647 vmu = find_user(&svm, context, mailbox);
13648
13649 if (!strncasecmp(arg.attribute, "exists", 5)) {
13650 ast_copy_string(buf, vmu ? "1" : "0", len);
13651 free_user(vmu);
13652 return 0;
13653 }
13654
13655 if (vmu) {
13656 if (!strncasecmp(arg.attribute, "password", 8)) {
13658 } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
13660 } else if (!strncasecmp(arg.attribute, "email", 5)) {
13661 ast_copy_string(buf, vmu->email, len);
13662 } else if (!strncasecmp(arg.attribute, "pager", 5)) {
13663 ast_copy_string(buf, vmu->pager, len);
13664 } else if (!strncasecmp(arg.attribute, "language", 8)) {
13666 } else if (!strncasecmp(arg.attribute, "locale", 6)) {
13667 ast_copy_string(buf, vmu->locale, len);
13668 } else if (!strncasecmp(arg.attribute, "tz", 2)) {
13670 } else if (!strncasecmp(arg.attribute, "count", 5)) {
13671 char *mailbox_id;
13672
13673 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
13674 sprintf(mailbox_id, "%s@%s", mailbox, context);/* Safe */
13675
13676 /* If mbxfolder is empty messagecount will default to INBOX */
13677 res = messagecount(mailbox_id, arg.folder);
13678 if (res < 0) {
13679 ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
13680 free_user(vmu);
13681 return -1;
13682 }
13683 snprintf(buf, len, "%d", res);
13684 } else {
13685 ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
13686 free_user(vmu);
13687 return -1;
13688 }
13689 free_user(vmu);
13690 }
13691
13692 return 0;
13693}
static void free_user(struct ast_vm_user *vmu)
static int messagecount(const char *mailbox_id, const char *folder)
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_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_log
Definition astobj2.c:42
const char * ast_channel_language(const struct ast_channel *chan)
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_ERROR
static struct @522 args
#define NULL
Definition resample.c:96
#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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char fullname[80]
char context[MAX_VM_CONTEXT_LEN]
char pager[80]
char mailbox[MAX_VM_MBOX_ID_LEN]
char zonetag[80]
char password[80]
char locale[20]
char language[MAX_LANGUAGE]

References args, ast_alloca, AST_APP_ARG, ast_channel_language(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), buf, ast_vm_user::context, ast_vm_user::email, find_user(), free_user(), ast_vm_user::fullname, ast_vm_user::language, len(), ast_vm_user::locale, LOG_ERROR, ast_vm_user::mailbox, messagecount(), NULL, ast_vm_user::pager, ast_vm_user::password, S_OR, separate_mailbox(), and ast_vm_user::zonetag.

◆ actual_load_config()

static int actual_load_config ( int  reload,
struct ast_config cfg 
)
static

Definition at line 14837 of file app_voicemail.c.

14838{
14839 const char *val;
14840 char *q, *stringp, *tmp;
14841 int x;
14842 unsigned int tmpadsi[4];
14843 long tps_queue_low;
14844 long tps_queue_high;
14845
14846#ifdef IMAP_STORAGE
14847 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
14848#endif
14849 /* set audio control prompts */
14856
14857#ifdef IMAP_STORAGE
14858 ast_mwi_state_callback_all(imap_close_subscribed_mailbox, NULL);
14859#endif
14860
14861 /* Free all the users structure */
14862 free_vm_users();
14863
14864 /* Free all the zones structure */
14865 free_vm_zones();
14866
14867 /* Remove all aliases */
14870
14872
14873 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
14874 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
14875
14876 if (cfg) {
14877 /* General settings */
14878 aliasescontext[0] = '\0';
14879 val = ast_variable_retrieve(cfg, "general", "aliasescontext");
14881
14882 /* Attach voice message to mail message ? */
14883 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
14884 val = "yes";
14886
14887 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
14888 val = "no";
14890
14891 volgain = 0.0;
14892 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
14893 sscanf(val, "%30lf", &volgain);
14894
14895#ifdef ODBC_STORAGE
14896 strcpy(odbc_database, "asterisk");
14897 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
14898 ast_copy_string(odbc_database, val, sizeof(odbc_database));
14899 }
14900
14901 strcpy(odbc_table, "voicemessages");
14902 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
14903 ast_copy_string(odbc_table, val, sizeof(odbc_table));
14904 }
14905 odbc_table_len = strlen(odbc_table);
14906
14908 if (!(val = ast_variable_retrieve(cfg, "general", "odbc_audio_on_disk")))
14909 val = "no";
14911
14912#endif
14913 /* Mail command */
14914 strcpy(mailcmd, SENDMAIL);
14915 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
14916 ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */
14917
14918 maxsilence = 0;
14919 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
14920 maxsilence = atoi(val);
14921 if (maxsilence > 0)
14922 maxsilence *= 1000;
14923 }
14924
14925 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
14926 maxmsg = MAXMSG;
14927 } else {
14928 maxmsg = atoi(val);
14929 if (maxmsg < 0) {
14930 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
14931 maxmsg = MAXMSG;
14932 } else if (maxmsg > MAXMSGLIMIT) {
14933 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14935 }
14936 }
14937
14938 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
14939 maxdeletedmsg = 0;
14940 } else {
14941 if (sscanf(val, "%30d", &x) == 1)
14942 maxdeletedmsg = x;
14943 else if (ast_true(val))
14945 else
14946 maxdeletedmsg = 0;
14947
14948 if (maxdeletedmsg < 0) {
14949 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
14951 } else if (maxdeletedmsg > MAXMSGLIMIT) {
14952 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14954 }
14955 }
14956
14957 /* Load date format config for voicemail mail */
14958 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
14960 }
14961
14962 /* Load date format config for voicemail pager mail */
14963 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
14965 }
14966
14967 /* External password changing command */
14968 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
14971 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
14974 }
14975
14976 /* External password validation command */
14977 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
14979 ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd);
14980 }
14981
14982#ifdef IMAP_STORAGE
14983 /* IMAP server address */
14984 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
14985 ast_copy_string(imapserver, val, sizeof(imapserver));
14986 } else {
14987 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
14988 }
14989 /* IMAP server port */
14990 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
14991 ast_copy_string(imapport, val, sizeof(imapport));
14992 } else {
14993 ast_copy_string(imapport, "143", sizeof(imapport));
14994 }
14995 /* IMAP server flags */
14996 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
14997 ast_copy_string(imapflags, val, sizeof(imapflags));
14998 }
14999 /* IMAP server master username */
15000 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
15001 ast_copy_string(authuser, val, sizeof(authuser));
15002 }
15003 /* IMAP server master password */
15004 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
15005 ast_copy_string(authpassword, val, sizeof(authpassword));
15006 }
15007 /* Expunge on exit */
15008 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
15009 if (ast_false(val))
15010 expungeonhangup = 0;
15011 else
15012 expungeonhangup = 1;
15013 } else {
15014 expungeonhangup = 1;
15015 }
15016 /* IMAP voicemail folder */
15017 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
15018 ast_copy_string(imapfolder, val, sizeof(imapfolder));
15019 } else {
15020 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
15021 }
15022 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
15023 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
15024 }
15025 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
15026 imapgreetings = ast_true(val);
15027 } else {
15028 imapgreetings = 0;
15029 }
15030 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
15031 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
15032 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
15033 /* Also support greetingsfolder as documented in voicemail.conf.sample */
15034 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
15035 } else {
15036 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
15037 }
15038 if ((val = ast_variable_retrieve(cfg, "general", "imap_poll_logout"))) {
15039 imap_poll_logout = ast_true(val);
15040 } else {
15041 imap_poll_logout = 0;
15042 }
15043
15044 /* There is some very unorthodox casting done here. This is due
15045 * to the way c-client handles the argument passed in. It expects a
15046 * void pointer and casts the pointer directly to a long without
15047 * first dereferencing it. */
15048 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
15049 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
15050 } else {
15051 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
15052 }
15053
15054 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
15055 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
15056 } else {
15057 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
15058 }
15059
15060 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
15061 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
15062 } else {
15063 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
15064 }
15065
15066 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
15067 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
15068 } else {
15069 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
15070 }
15071
15072 /* Increment configuration version */
15073 imapversion++;
15074#endif
15075 /* External voicemail notify application */
15076 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
15078 ast_debug(1, "found externnotify: %s\n", externnotify);
15079 } else {
15080 externnotify[0] = '\0';
15081 }
15082
15083 /* SMDI voicemail notification */
15084 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
15085 ast_debug(1, "Enabled SMDI voicemail notification\n");
15086 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
15088 } else {
15089 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
15090 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
15091 }
15092 if (!smdi_iface) {
15093 ast_log(AST_LOG_ERROR, "No valid SMDI interface specified, disabling SMDI voicemail notification\n");
15094 }
15095 }
15096
15097 /* Silence treshold */
15099 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
15100 silencethreshold = atoi(val);
15101
15102 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
15105
15106 vmmaxsecs = 0;
15107 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
15108 if (sscanf(val, "%30d", &x) == 1) {
15109 vmmaxsecs = x;
15110 } else {
15111 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
15112 }
15113 }
15114
15115 vmminsecs = 0;
15116 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
15117 if (sscanf(val, "%30d", &x) == 1) {
15118 vmminsecs = x;
15119 if (maxsilence / 1000 >= vmminsecs) {
15120 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
15121 }
15122 } else {
15123 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
15124 }
15125 }
15126
15127 val = ast_variable_retrieve(cfg, "general", "format");
15128 if (!val) {
15129 val = "wav";
15130 } else {
15131 tmp = ast_strdupa(val);
15133 if (!val) {
15134 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
15135 val = "wav";
15136 }
15137 }
15138 ast_copy_string(vmfmts, val, sizeof(vmfmts));
15139
15140 skipms = 3000;
15141 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
15142 if (sscanf(val, "%30d", &x) == 1) {
15143 maxgreet = x;
15144 } else {
15145 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
15146 }
15147 }
15148
15149 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
15150 if (sscanf(val, "%30d", &x) == 1) {
15151 skipms = x;
15152 } else {
15153 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
15154 }
15155 }
15156
15157 maxlogins = 3;
15158 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
15159 if (sscanf(val, "%30d", &x) == 1) {
15160 maxlogins = x;
15161 } else {
15162 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
15163 }
15164 }
15165
15167 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
15168 if (sscanf(val, "%30d", &x) == 1) {
15169 minpassword = x;
15170 } else {
15171 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
15172 }
15173 }
15174
15175 /* Force new user to record name ? */
15176 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
15177 val = "no";
15179
15180 /* Force new user to record greetings ? */
15181 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
15182 val = "no";
15184
15185 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
15186 ast_debug(1, "VM_CID Internal context string: %s\n", val);
15187 stringp = ast_strdupa(val);
15188 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
15189 if (!ast_strlen_zero(stringp)) {
15190 q = strsep(&stringp, ",");
15191 while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
15192 q++;
15194 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
15195 } else {
15196 cidinternalcontexts[x][0] = '\0';
15197 }
15198 }
15199 }
15200 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
15201 ast_debug(1, "VM Review Option disabled globally\n");
15202 val = "no";
15203 }
15205
15206 if (!(val = ast_variable_retrieve(cfg, "general", "leaveurgent"))){
15207 val = "yes";
15208 } else if (ast_false(val)) {
15209 ast_debug(1, "VM leave urgent messages disabled globally\n");
15210 val = "no";
15211 }
15213
15214 /* Temporary greeting reminder */
15215 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
15216 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
15217 val = "no";
15218 } else {
15219 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
15220 }
15222 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
15223 ast_debug(1, "VM next message wrap disabled globally\n");
15224 val = "no";
15225 }
15227
15228 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
15229 ast_debug(1, "VM Operator break disabled globally\n");
15230 val = "no";
15231 }
15233
15234 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
15235 ast_debug(1, "VM CID Info before msg disabled globally\n");
15236 val = "no";
15237 }
15239
15240 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
15241 ast_debug(1, "Send Voicemail msg disabled globally\n");
15242 val = "no";
15243 }
15245
15246 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
15247 ast_debug(1, "ENVELOPE before msg enabled globally\n");
15248 val = "yes";
15249 }
15251
15252 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
15253 ast_debug(1, "Move Heard enabled globally\n");
15254 val = "yes";
15255 }
15257
15258 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
15259 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
15260 val = "no";
15261 }
15263
15264 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
15265 ast_debug(1, "Duration info before msg enabled globally\n");
15266 val = "yes";
15267 }
15269
15270 saydurationminfo = 2;
15271 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
15272 if (sscanf(val, "%30d", &x) == 1) {
15273 saydurationminfo = x;
15274 } else {
15275 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
15276 }
15277 }
15278
15279 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
15280 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
15281 val = "no";
15282 }
15284
15285 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
15287 ast_debug(1, "found dialout context: %s\n", dialcontext);
15288 } else {
15289 dialcontext[0] = '\0';
15290 }
15291
15292 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
15294 ast_debug(1, "found callback context: %s\n", callcontext);
15295 } else {
15296 callcontext[0] = '\0';
15297 }
15298
15299 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
15301 ast_debug(1, "found operator context: %s\n", exitcontext);
15302 } else {
15303 exitcontext[0] = '\0';
15304 }
15305
15306 /* load password sounds configuration */
15307 if ((val = ast_variable_retrieve(cfg, "general", "vm-login")))
15309 if ((val = ast_variable_retrieve(cfg, "general", "vm-newuser")))
15311 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
15313 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
15315 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
15317 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
15319 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
15321 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
15323 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
15325 }
15326 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
15328 }
15329 /* load configurable audio prompts */
15330 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
15332 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
15334 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
15336 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
15338 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
15340
15341 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
15342 val = "no";
15344
15345 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
15346 val = "voicemail.conf";
15347 }
15348 if (!(strcmp(val, "spooldir"))) {
15350 } else {
15352 }
15353
15355 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
15356 if (sscanf(val, "%30u", &poll_freq) != 1) {
15358 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
15359 }
15360 }
15361
15362 poll_mailboxes = 0;
15363 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
15365
15366 memset(fromstring, 0, sizeof(fromstring));
15367 memset(pagerfromstring, 0, sizeof(pagerfromstring));
15368 strcpy(charset, "ISO-8859-1");
15369 if (emailbody) {
15371 emailbody = NULL;
15372 }
15373 if (emailsubject) {
15376 }
15377 if (pagerbody) {
15379 pagerbody = NULL;
15380 }
15381 if (pagersubject) {
15384 }
15385 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
15387 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
15389 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
15391 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
15393 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
15394 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15395 for (x = 0; x < 4; x++) {
15396 memcpy(&adsifdn[x], &tmpadsi[x], 1);
15397 }
15398 }
15399 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
15400 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15401 for (x = 0; x < 4; x++) {
15402 memcpy(&adsisec[x], &tmpadsi[x], 1);
15403 }
15404 }
15405 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
15406 if (atoi(val)) {
15407 adsiver = atoi(val);
15408 }
15409 }
15410 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
15412 }
15413 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
15414 ast_copy_string(locale, val, sizeof(locale));
15415 }
15416 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
15418 }
15419 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
15421 }
15422 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
15424 }
15425 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
15427 }
15428
15429 tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;
15430 if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_high"))) {
15431 if (sscanf(val, "%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {
15432 ast_log(AST_LOG_WARNING, "Invalid the taskprocessor high water alert trigger level '%s'\n", val);
15433 tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;
15434 }
15435 }
15436 tps_queue_low = -1;
15437 if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_low"))) {
15438 if (sscanf(val, "%30ld", &tps_queue_low) != 1 ||
15439 tps_queue_low < -1 || tps_queue_high < tps_queue_low) {
15440 ast_log(AST_LOG_WARNING, "Invalid the taskprocessor low water clear alert level '%s'\n", val);
15441 tps_queue_low = -1;
15442 }
15443 }
15444 if (ast_taskprocessor_alert_set_levels(mwi_subscription_tps, tps_queue_low, tps_queue_high)) {
15445 ast_log(AST_LOG_WARNING, "Failed to set alert levels for voicemail taskprocessor.\n");
15446 }
15447
15448 /* load mailboxes from voicemail.conf */
15449
15450 /*
15451 * Aliases must be loaded before users or the aliases won't be notified
15452 * if there's existing voicemail in the user mailbox.
15453 */
15454 load_aliases(cfg);
15455
15456 load_zonemessages(cfg);
15457
15458 load_users(cfg);
15459
15461
15466
15467 return 0;
15468 } else {
15470 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
15471 return 0;
15472 }
15473}
static char pagerfromstring[100]
static char vm_password[80]
static char vm_invalid_password[80]
#define VM_SEARCH
#define VM_ODBC_AUDIO_ON_DISK
static char listen_control_reverse_key[12]
static char serveremail[80]
#define VM_SAYCID
#define VM_FWDURGAUTO
#define VM_SAYDURATION
static int pwdchange
#define VM_TEMPGREETWARN
static int skipms
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY
static char mailcmd[160]
static int vmminsecs
static struct ast_taskprocessor * mwi_subscription_tps
#define VM_OPERATOR
static char vm_newpassword[80]
#define VM_MARK_URGENT
static struct ast_flags globalflags
static char listen_control_forward_key[12]
static char vm_login[80]
#define VM_DIRECTFORWARD
static char vm_newuser[80]
static unsigned char adsisec[4]
static const char * substitute_escapes(const char *value)
#define VM_SKIPAFTERCMD
static pthread_t poll_thread
static char zonetag[80]
static char * pagersubject
static int maxmsg
static char vmfmts[80]
static void load_zonemessages(struct ast_config *cfg)
static int passwordlocation
static char vm_mismatch[80]
#define ASTERISK_USERNAME
static char vm_pls_try_again[80]
#define VM_PBXSKIP
static char ext_pass_check_cmd[128]
static char * pagerbody
static char dialcontext[AST_MAX_CONTEXT]
#define DEFAULT_POLL_FREQ
#define VM_ENVELOPE
static void stop_poll_thread(void)
#define MAXMSG
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY
static char listen_control_stop_key[12]
static char fromstring[100]
#define PWDCHANGE_INTERNAL
#define VM_FORCEGREET
#define VM_MESSAGEWRAP
static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]
#define DEFAULT_LISTEN_CONTROL_STOP_KEY
static char emaildateformat[32]
static char vm_reenterpassword[80]
static int saydurationminfo
#define VM_ATTACH
static int maxgreet
#define SENDMAIL
#define VM_FORCENAME
static char ext_pass_cmd[128]
static int is_valid_dtmf(const char *key)
Determines if a DTMF key entered is valid.
static char pagerdateformat[32]
static double volgain
static int adsiver
static int maxlogins
static char * emailsubject
static struct ao2_container * mailbox_alias_mappings
#define VM_MOVEHEARD
static char externnotify[160]
static char listen_control_restart_key[12]
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY
#define MAX_NUM_CID_CONTEXTS
static char vm_prepend_timeout[80]
static char callcontext[AST_MAX_CONTEXT]
static int maxdeletedmsg
static char * emailbody
static char listen_control_pause_key[12]
static int silencethreshold
static void start_poll_thread(void)
static unsigned int poll_mailboxes
#define MINPASSWORD
static int minpassword
static unsigned int poll_freq
static void free_vm_zones(void)
Free the zones structure.
#define VM_SVMAIL
#define PWDCHANGE_EXTERNAL
static char locale[20]
static unsigned char adsifdn[4]
static int maxsilence
static void load_aliases(struct ast_config *cfg)
static int vmmaxsecs
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY
#define MAXMSGLIMIT
static char exitcontext[AST_MAX_CONTEXT]
#define VM_REVIEW
static char vm_passchanged[80]
static struct ast_smdi_interface * smdi_iface
static void free_vm_users(void)
Free the users structure.
char * strsep(char **str, const char *delims)
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
charset
@ THRESHOLD_SILENCE
Definition dsp.h:75
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition dsp.c:2196
char * ast_format_str_reduce(char *fmts)
Definition file.c:1928
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#define AST_PTHREADT_NULL
Definition lock.h:73
void ast_mwi_state_callback_all(on_mwi_state handler, void *data)
For each managed mailbox call the given handler.
Definition mwi.c:338
static int load_users(void)
struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
Definition res_smdi.c:569
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2250
list of users found in the config file
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.
#define ast_set2_flag(p, value, flag)
Definition utils.h:95

References adsifdn, adsisec, adsiver, alias_mailbox_mappings, aliasescontext, ao2_callback, ast_copy_string(), ast_debug, ast_dsp_get_threshold_from_settings(), ast_false(), ast_format_str_reduce(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log, AST_LOG_ERROR, AST_LOG_WARNING, ast_mwi_state_callback_all(), AST_PTHREADT_NULL, ast_set2_flag, ast_smdi_interface_find(), ast_strdup, ast_strdupa, ast_strlen_zero(), ast_taskprocessor_alert_set_levels(), AST_TASKPROCESSOR_HIGH_WATER_LEVEL, ast_true(), ast_variable_retrieve(), ASTERISK_USERNAME, callcontext, cidinternalcontexts, DEFAULT_LISTEN_CONTROL_FORWARD_KEY, DEFAULT_LISTEN_CONTROL_PAUSE_KEY, DEFAULT_LISTEN_CONTROL_RESTART_KEY, DEFAULT_LISTEN_CONTROL_REVERSE_KEY, DEFAULT_LISTEN_CONTROL_STOP_KEY, DEFAULT_POLL_FREQ, dialcontext, emailbody, emaildateformat, emailsubject, exitcontext, ext_pass_check_cmd, ext_pass_cmd, externnotify, free_vm_users(), free_vm_zones(), fromstring, globalflags, is_valid_dtmf(), listen_control_forward_key, listen_control_pause_key, listen_control_restart_key, listen_control_reverse_key, listen_control_stop_key, load_aliases(), load_users(), load_zonemessages(), locale, LOG_ERROR, mailbox_alias_mappings, mailcmd, MAX_NUM_CID_CONTEXTS, maxdeletedmsg, maxgreet, maxlogins, MAXMSG, maxmsg, MAXMSGLIMIT, maxsilence, MINPASSWORD, minpassword, mwi_subscription_tps, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_VOICEMAILCONF, pagerbody, pagerdateformat, pagerfromstring, pagersubject, passwordlocation, poll_freq, poll_mailboxes, poll_thread, pwdchange, PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, S_OR, saydurationminfo, SENDMAIL, serveremail, silencethreshold, skipms, smdi_iface, start_poll_thread(), stop_poll_thread(), strsep(), substitute_escapes(), THRESHOLD_SILENCE, VM_ATTACH, VM_DIRECTFORWARD, VM_ENVELOPE, VM_FORCEGREET, VM_FORCENAME, VM_FWDURGAUTO, vm_invalid_password, vm_login, VM_MARK_URGENT, VM_MESSAGEWRAP, vm_mismatch, VM_MOVEHEARD, vm_newpassword, vm_newuser, VM_ODBC_AUDIO_ON_DISK, VM_OPERATOR, vm_passchanged, vm_password, VM_PBXSKIP, vm_pls_try_again, vm_prepend_timeout, vm_reenterpassword, VM_REVIEW, VM_SAYCID, VM_SAYDURATION, VM_SEARCH, VM_SKIPAFTERCMD, VM_SVMAIL, VM_TEMPGREETWARN, vmfmts, vmmaxsecs, vmminsecs, volgain, and zonetag.

Referenced by load_config_force().

◆ add_email_attachment()

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

Definition at line 5734 of file app_voicemail.c.

5735{
5736 char fname[PATH_MAX] = "";
5737 char sox_gain_tmpdir[PATH_MAX];
5738 char *file_to_delete = NULL, *dir_to_delete = NULL;
5739 int res;
5740 char altfname[PATH_MAX] = "";
5741 int altused = 0;
5742 char altformat[80] = "";
5743 char *c = NULL;
5744
5745 /* Eww. We want formats to tell us their own MIME type */
5746 char *mime_type = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
5747
5748 /* Users of multiple file formats need special attention. */
5749 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
5750 if (!ast_file_is_readable(fname)) {
5751 ast_copy_string(altformat, vmfmts, sizeof(altformat));
5752 c = strchr(altformat, '|');
5753 if (c) {
5754 *c = '\0';
5755 }
5756 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s - trying first/alternate format %s\n", fname, strerror(errno), altformat);
5757 snprintf(altfname, sizeof(altfname), "%s.%s", attach, altformat);
5758 if (!ast_file_is_readable(altfname)) {
5759 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s - alternate format %s failure\n", altfname, strerror(errno), altformat);
5760 } else {
5761 altused = 1;
5762 }
5763 }
5764
5765 /* This 'while' loop will only execute once. We use it so that we can 'break' */
5766 while (vmu->volgain < -.001 || vmu->volgain > .001 || altused) {
5767 char tmpdir[PATH_MAX];
5768
5769 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
5770
5771 res = snprintf(sox_gain_tmpdir, sizeof(sox_gain_tmpdir), "%s/vm-gain-XXXXXX", tmpdir);
5772 if (res >= sizeof(sox_gain_tmpdir)) {
5773 ast_log(LOG_ERROR, "Failed to create temporary directory path %s: Out of buffer space\n", tmpdir);
5774 break;
5775 }
5776
5777 if (mkdtemp(sox_gain_tmpdir)) {
5778 int soxstatus = 0;
5779 char sox_gain_cmd[PATH_MAX];
5780
5781 ast_debug(3, "sox_gain_tmpdir: %s\n", sox_gain_tmpdir);
5782
5783 /* Save for later */
5784 dir_to_delete = sox_gain_tmpdir;
5785
5786 res = snprintf(fname, sizeof(fname), "%s/output.%s", sox_gain_tmpdir, format);
5787 if (res >= sizeof(fname)) {
5788 ast_log(LOG_ERROR, "Failed to create filename buffer for %s/output.%s: Too long\n", sox_gain_tmpdir, format);
5789 break;
5790 }
5791
5792 if (!altused) {
5793 res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox -v %.4f %s.%s %s",
5794 vmu->volgain, attach, format, fname);
5795 } else {
5796 if (!strcasecmp(format, "wav")) {
5797 if (vmu->volgain < -.001 || vmu->volgain > .001) {
5798 res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox -v %.4f %s.%s -e signed-integer -b 16 %s",
5799 vmu->volgain, attach, altformat, fname);
5800 } else {
5801 res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox %s.%s -e signed-integer -b 16 %s",
5802 attach, altformat, fname);
5803 }
5804 } else {
5805 if (vmu->volgain < -.001 || vmu->volgain > .001) {
5806 res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox -v %.4f %s.%s %s",
5807 vmu->volgain, attach, altformat, fname);
5808 } else {
5809 res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox %s.%s %s",
5810 attach, altformat, fname);
5811 }
5812 }
5813 }
5814
5815 if (res >= sizeof(sox_gain_cmd)) {
5816 ast_log(LOG_ERROR, "Failed to generate sox command, out of buffer space\n");
5817 break;
5818 }
5819
5820 soxstatus = ast_safe_system(sox_gain_cmd);
5821 if (!soxstatus) {
5822 /* Save for later */
5823 file_to_delete = fname;
5824 ast_debug(3, "VOLGAIN: Stored at: %s - Level: %.4f - Mailbox: %s\n", fname, vmu->volgain, mailbox);
5825 } else {
5826 ast_log(LOG_WARNING, "Sox failed to re-encode %s: %s (have you installed support for all sox file formats?)\n",
5827 fname,
5828 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
5829 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
5830 }
5831 }
5832
5833 break;
5834 }
5835
5836 if (!file_to_delete) {
5837 res = snprintf(fname, sizeof(fname), "%s.%s", attach, format);
5838 if (res >= sizeof(fname)) {
5839 ast_log(LOG_ERROR, "Failed to create filename buffer for %s.%s: Too long\n", attach, format);
5840 return -1;
5841 }
5842 }
5843
5844 fprintf(p, "--%s" ENDL, bound);
5845 if (msgnum > -1)
5846 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, mime_type, format, filename);
5847 else
5848 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, mime_type, format, greeting_attachment, format);
5849 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
5850 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
5851 if (msgnum > -1)
5852 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
5853 else
5854 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
5856 if (last)
5857 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
5858
5859 if (file_to_delete) {
5860 unlink(file_to_delete);
5861 }
5862
5863 if (dir_to_delete) {
5864 rmdir(dir_to_delete);
5865 }
5866
5867 return 0;
5868}
struct sla_ringing_trunk * last
Definition app_sla.c:338
#define ENDL
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
basically mkdir -p $dest/$context/$ext/$folder
char * mkdtemp(char *template_s)
#define PATH_MAX
Definition asterisk.h:40
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define LOG_WARNING
int errno
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition utils.c:3141
int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
Performs a base 64 encode algorithm on the contents of a File.
Definition utils.c:700

References ast_base64_encode_file_path(), ast_copy_string(), ast_debug, ast_file_is_readable(), ast_log, AST_LOG_WARNING, ast_safe_system(), c, ast_vm_user::context, create_dirpath(), ENDL, errno, last, LOG_ERROR, LOG_WARNING, ast_vm_user::mailbox, mkdtemp(), NULL, PATH_MAX, vmfmts, and ast_vm_user::volgain.

Referenced by make_email_file().

◆ add_message_id()

static int add_message_id ( struct ast_config msg_cfg,
char *  dir,
int  msg,
char *  filename,
char *  id,
size_t  id_size,
struct ast_vm_user vmu,
int  folder 
)
static

Definition at line 13286 of file app_voicemail.c.

13287{
13288 struct ast_variable *var;
13289 struct ast_category *cat;
13290 generate_msg_id(id);
13291
13292 var = ast_variable_new("msg_id", id, "");
13293 if (!var) {
13294 return -1;
13295 }
13296
13297 cat = ast_category_get(msg_cfg, "message", NULL);
13298 if (!cat) {
13299 ast_log(LOG_ERROR, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
13301 return -1;
13302 }
13303
13305
13306 if (ast_config_text_file_save(filename, msg_cfg, "app_voicemail")) {
13307 ast_log(LOG_WARNING, "Unable to update %s to have a message ID\n", filename);
13308 return -1;
13309 }
13310
13311 UPDATE_MSG_ID(dir, msg, id, vmu, msg_cfg, folder);
13312 return 0;
13313}
#define UPDATE_MSG_ID(a, b, c, d, e, f)
static void generate_msg_id(char *dst)
Sets the destination string to a uniquely identifying msg_id string.
#define var
Definition ast_expr2f.c:605
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.
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition extconf.c:1175
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Structure for variables, used for configurations and for channel variables.

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

Referenced by vm_msg_snapshot_create().

◆ adsi_begin()

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

Definition at line 7870 of file app_voicemail.c.

7871{
7872 int x;
7873 if (!ast_adsi_available(chan))
7874 return;
7875 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
7876 if (x < 0) {
7877 *useadsi = 0;
7879 return;
7880 }
7881 if (!x) {
7882 if (adsi_load_vmail(chan, useadsi)) {
7883 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
7884 return;
7885 }
7886 } else
7887 *useadsi = 1;
7888}
int ast_adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
Check if scripts for a given app are already loaded. Version may be -1, if any version is okay,...
Definition adsi.c:76
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
Definition adsi.c:263
static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
@ AST_ADSI_UNAVAILABLE
Definition channel.h:891
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)

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

Referenced by vm_authenticate(), and vm_execmain().

◆ adsi_delete()

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

Definition at line 8069 of file app_voicemail.c.

8070{
8071 int bytes = 0;
8072 unsigned char buf[256];
8073 unsigned char keys[8];
8074
8075 int x;
8076
8077 if (!ast_adsi_available(chan))
8078 return;
8079
8080 /* New meaning for keys */
8081 for (x = 0; x < 5; x++)
8082 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
8083
8084 keys[6] = 0x0;
8085 keys[7] = 0x0;
8086
8087 if (!vms->curmsg) {
8088 /* No prev key, provide "Folder" instead */
8089 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8090 }
8091 if (vms->curmsg >= vms->lastmsg) {
8092 /* If last message ... */
8093 if (vms->curmsg) {
8094 /* but not only message, provide "Folder" instead */
8095 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8096 } else {
8097 /* Otherwise if only message, leave blank */
8098 keys[3] = 1;
8099 }
8100 }
8101
8102 /* If deleted, show "undeleted" */
8103#ifdef IMAP_STORAGE
8104 ast_mutex_lock(&vms->lock);
8105#endif
8106 if (vms->deleted[vms->curmsg]) {
8107 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8108 }
8109#ifdef IMAP_STORAGE
8110 ast_mutex_unlock(&vms->lock);
8111#endif
8112
8113 /* Except "Exit" */
8114 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8115 bytes += ast_adsi_set_keys(buf + bytes, keys);
8116 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8117
8119}
#define ADSI_KEY_APPS
Definition adsi.h:109
#define ADSI_KEY_SKT
Definition adsi.h:117
#define ADSI_MSG_DISPLAY
Definition adsi.h:32
int ast_adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
Definition adsi.c:98
int ast_adsi_set_keys(unsigned char *buf, unsigned char *keys)
Set which soft keys should be displayed.
Definition adsi.c:307
int ast_adsi_voice_mode(unsigned char *buf, int when)
Puts CPE in voice mode.
Definition adsi.c:252
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
int * deleted

References ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_set_keys(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_mutex_lock, ast_mutex_unlock, buf, vm_state::curmsg, vm_state::deleted, and vm_state::lastmsg.

Referenced by vm_execmain().

◆ adsi_folders()

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

Definition at line 7938 of file app_voicemail.c.

7939{
7940 unsigned char buf[256];
7941 int bytes = 0;
7942 unsigned char keys[8];
7943 int x, y;
7944
7945 if (!ast_adsi_available(chan))
7946 return;
7947
7948 for (x = 0; x < 5; x++) {
7949 y = ADSI_KEY_APPS + 12 + start + x;
7950 if (y > ADSI_KEY_APPS + 12 + 4)
7951 y = 0;
7952 keys[x] = ADSI_KEY_SKT | y;
7953 }
7954 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
7955 keys[6] = 0;
7956 keys[7] = 0;
7957
7958 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
7959 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
7960 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7961 bytes += ast_adsi_set_keys(buf + bytes, keys);
7962 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7963
7965}
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 ADSI_JUST_CENT
Definition adsi.h:114
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
Definition adsi.c:285
#define ADSI_COMM_PAGE
Definition adsi.h:107

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

Referenced by vm_execmain().

◆ adsi_goodbye()

static void adsi_goodbye ( struct ast_channel chan)
static

Definition at line 8224 of file app_voicemail.c.

8225{
8226 unsigned char buf[256];
8227 int bytes = 0;
8228
8229 if (!ast_adsi_available(chan))
8230 return;
8231 bytes += adsi_logo(buf + bytes);
8232 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
8233 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
8234 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8235 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8236
8238}
#define ADSI_JUST_LEFT
Definition adsi.h:112
static int adsi_logo(unsigned char *buf)

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

Referenced by vm_execmain().

◆ adsi_load_vmail()

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

Definition at line 7741 of file app_voicemail.c.

7742{
7743 unsigned char buf[256];
7744 int bytes = 0;
7745 int x;
7746 char num[5];
7747
7748 *useadsi = 0;
7749 bytes += ast_adsi_data_mode(buf + bytes);
7751
7752 bytes = 0;
7753 bytes += adsi_logo(buf);
7754 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
7755#ifdef DISPLAY
7756 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
7757#endif
7758 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7759 bytes += ast_adsi_data_mode(buf + bytes);
7761
7763 bytes = 0;
7764 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
7765 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
7766 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7767 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7769 return 0;
7770 }
7771
7772#ifdef DISPLAY
7773 /* Add a dot */
7774 bytes = 0;
7775 bytes += ast_adsi_logo(buf);
7776 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
7777 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
7778 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7780#endif
7781 bytes = 0;
7782 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
7783 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
7784 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advanced", "3", 1);
7785 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
7786 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
7787 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
7789
7790#ifdef DISPLAY
7791 /* Add another dot */
7792 bytes = 0;
7793 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
7794 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7795
7796 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7798#endif
7799
7800 bytes = 0;
7801 /* These buttons we load but don't use yet */
7802 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
7803 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
7804 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
7805 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
7806 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
7807 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
7809
7810#ifdef DISPLAY
7811 /* Add another dot */
7812 bytes = 0;
7813 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
7814 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7816#endif
7817
7818 bytes = 0;
7819 for (x = 0; x < 5; x++) {
7820 snprintf(num, sizeof(num), "%d", x);
7821 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
7822 }
7823 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
7825
7826#ifdef DISPLAY
7827 /* Add another dot */
7828 bytes = 0;
7829 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
7830 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7832#endif
7833
7834 if (ast_adsi_end_download(chan)) {
7835 bytes = 0;
7836 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
7837 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
7838 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7839 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7841 return 0;
7842 }
7843 bytes = 0;
7844 bytes += ast_adsi_download_disconnect(buf + bytes);
7845 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7847
7848 ast_debug(1, "Done downloading scripts...\n");
7849
7850#ifdef DISPLAY
7851 /* Add last dot */
7852 bytes = 0;
7853 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
7854 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7855#endif
7856 ast_debug(1, "Restarting session...\n");
7857
7858 bytes = 0;
7859 /* Load the session now */
7860 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
7861 *useadsi = 1;
7862 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
7863 } else
7864 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
7865
7867 return 0;
7868}
int ast_adsi_load_soft_key(unsigned char *buf, int key, const char *llabel, const char *slabel, char *ret, int data)
Creates "load soft key" parameters.
Definition adsi.c:296
#define ADSI_MSG_DOWNLOAD
Definition adsi.h:33
int ast_adsi_data_mode(unsigned char *buf)
Puts CPE in data mode.
Definition adsi.c:219
int ast_adsi_begin_download(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version)
Definition adsi.c:32
int ast_adsi_end_download(struct ast_channel *chan)
Definition adsi.c:43
int ast_adsi_download_disconnect(unsigned char *buf)
Disconnects (and hopefully saves) a downloaded script.
Definition adsi.c:208
static char * addesc
static const char * mbox(struct ast_vm_user *vmu, int id)

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

Referenced by adsi_begin().

◆ adsi_login()

static void adsi_login ( struct ast_channel chan)
static

Definition at line 7890 of file app_voicemail.c.

7891{
7892 unsigned char buf[256];
7893 int bytes = 0;
7894 unsigned char keys[8];
7895 int x;
7896 if (!ast_adsi_available(chan))
7897 return;
7898
7899 for (x = 0; x < 8; x++)
7900 keys[x] = 0;
7901 /* Set one key for next */
7902 keys[3] = ADSI_KEY_APPS + 3;
7903
7904 bytes += adsi_logo(buf + bytes);
7905 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
7906 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
7907 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7908 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
7909 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
7910 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
7911 bytes += ast_adsi_set_keys(buf + bytes, keys);
7912 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7914}
int ast_adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
Set input information.
Definition adsi.c:318
int ast_adsi_input_format(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
Set input format.
Definition adsi.c:329
#define ADSI_DIR_FROM_LEFT
Definition adsi.h:120

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

Referenced by vm_authenticate().

◆ adsi_logo()

static int adsi_logo ( unsigned char *  buf)
static

Definition at line 7733 of file app_voicemail.c.

7734{
7735 int bytes = 0;
7736 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
7737 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
7738 return bytes;
7739}

References ADSI_COMM_PAGE, ADSI_JUST_CENT, ast_adsi_display(), and buf.

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

◆ adsi_message()

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

Definition at line 7967 of file app_voicemail.c.

7968{
7969 int bytes = 0;
7970 unsigned char buf[256];
7971 char buf1[256], buf2[256];
7972 char fn2[PATH_MAX];
7973
7974 char cid[256] = "";
7975 char *val;
7976 char *name, *num;
7977 char datetime[21] = "";
7978 FILE *f;
7979
7980 unsigned char keys[8];
7981
7982 int x;
7983
7984 if (!ast_adsi_available(chan))
7985 return;
7986
7987 /* Retrieve important info */
7988 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
7989 f = fopen(fn2, "r");
7990 if (f) {
7991 while (!feof(f)) {
7992 if (!fgets((char *) buf, sizeof(buf), f)) {
7993 continue;
7994 }
7995 if (!feof(f)) {
7996 char *stringp = NULL;
7997 stringp = (char *) buf;
7998 strsep(&stringp, "=");
7999 val = strsep(&stringp, "=");
8000 if (!ast_strlen_zero(val)) {
8001 if (!strcmp((char *) buf, "callerid"))
8002 ast_copy_string(cid, val, sizeof(cid));
8003 if (!strcmp((char *) buf, "origdate"))
8004 ast_copy_string(datetime, val, sizeof(datetime));
8005 }
8006 }
8007 }
8008 fclose(f);
8009 }
8010 /* New meaning for keys */
8011 for (x = 0; x < 5; x++)
8012 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
8013 keys[6] = 0x0;
8014 keys[7] = 0x0;
8015
8016 if (!vms->curmsg) {
8017 /* No prev key, provide "Folder" instead */
8018 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8019 }
8020 if (vms->curmsg >= vms->lastmsg) {
8021 /* If last message ... */
8022 if (vms->curmsg) {
8023 /* but not only message, provide "Folder" instead */
8024 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8025 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8026
8027 } else {
8028 /* Otherwise if only message, leave blank */
8029 keys[3] = 1;
8030 }
8031 }
8032
8033 if (!ast_strlen_zero(cid)) {
8034 ast_callerid_parse(cid, &name, &num);
8035 if (!name)
8036 name = num;
8037 } else {
8038 name = "Unknown Caller";
8039 }
8040
8041 /* If deleted, show "undeleted" */
8042#ifdef IMAP_STORAGE
8043 ast_mutex_lock(&vms->lock);
8044#endif
8045 if (vms->deleted[vms->curmsg]) {
8046 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8047 }
8048#ifdef IMAP_STORAGE
8049 ast_mutex_unlock(&vms->lock);
8050#endif
8051
8052 /* Except "Exit" */
8053 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8054 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
8055 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
8056 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
8057
8058 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8059 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8060 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
8061 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
8062 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8063 bytes += ast_adsi_set_keys(buf + bytes, keys);
8064 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8065
8067}
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition callerid.c:1162
static const char name[]
Definition format_mp3.c:68
char curbox[80]
char fn[PATH_MAX]

References ADSI_COMM_PAGE, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_keys(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_callerid_parse(), ast_copy_string(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), buf, vm_state::curbox, vm_state::curmsg, vm_state::deleted, vm_state::fn, vm_state::lastmsg, name, NULL, PATH_MAX, and strsep().

Referenced by play_message(), and vm_execmain().

◆ adsi_password()

static void adsi_password ( struct ast_channel chan)
static

Definition at line 7916 of file app_voicemail.c.

7917{
7918 unsigned char buf[256];
7919 int bytes = 0;
7920 unsigned char keys[8];
7921 int x;
7922 if (!ast_adsi_available(chan))
7923 return;
7924
7925 for (x = 0; x < 8; x++)
7926 keys[x] = 0;
7927 /* Set one key for next */
7928 keys[3] = ADSI_KEY_APPS + 3;
7929
7930 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7931 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
7932 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
7933 bytes += ast_adsi_set_keys(buf + bytes, keys);
7934 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7936}

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

Referenced by vm_authenticate().

◆ adsi_status()

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

Definition at line 8121 of file app_voicemail.c.

8122{
8123 unsigned char buf[256] = "";
8124 char buf1[256] = "", buf2[256] = "";
8125 int bytes = 0;
8126 unsigned char keys[8];
8127 int x;
8128
8129 char *newm = (vms->newmessages == 1) ? "message" : "messages";
8130 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
8131 if (!ast_adsi_available(chan))
8132 return;
8133 if (vms->newmessages) {
8134 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
8135 if (vms->oldmessages) {
8136 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
8137 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
8138 } else {
8139 snprintf(buf2, sizeof(buf2), "%s.", newm);
8140 }
8141 } else if (vms->oldmessages) {
8142 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
8143 snprintf(buf2, sizeof(buf2), "%s.", oldm);
8144 } else {
8145 strcpy(buf1, "You have no messages.");
8146 buf2[0] = ' ';
8147 buf2[1] = '\0';
8148 }
8149 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8150 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8151 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8152
8153 for (x = 0; x < 6; x++)
8154 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8155 keys[6] = 0;
8156 keys[7] = 0;
8157
8158 /* Don't let them listen if there are none */
8159 if (vms->lastmsg < 0)
8160 keys[0] = 1;
8161 bytes += ast_adsi_set_keys(buf + bytes, keys);
8162
8163 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8164
8166}

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

Referenced by vm_execmain().

◆ adsi_status2()

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

Definition at line 8168 of file app_voicemail.c.

8169{
8170 unsigned char buf[256] = "";
8171 char buf1[256] = "", buf2[256] = "";
8172 int bytes = 0;
8173 unsigned char keys[8];
8174 int x;
8175
8176 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
8177
8178 if (!ast_adsi_available(chan))
8179 return;
8180
8181 /* Original command keys */
8182 for (x = 0; x < 6; x++)
8183 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8184
8185 keys[6] = 0;
8186 keys[7] = 0;
8187
8188 if ((vms->lastmsg + 1) < 1)
8189 keys[0] = 0;
8190
8191 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
8192 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
8193
8194 if (vms->lastmsg + 1)
8195 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
8196 else
8197 strcpy(buf2, "no messages.");
8198 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8199 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8200 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
8201 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8202 bytes += ast_adsi_set_keys(buf + bytes, keys);
8203
8204 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8205
8207
8208}

References ADSI_COMM_PAGE, ADSI_JUST_LEFT, ADSI_KEY_APPS, ADSI_KEY_SKT, ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_keys(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), buf, vm_state::curbox, and vm_state::lastmsg.

Referenced by vm_execmain().

◆ advanced_options()

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

The advanced options within a message.

Parameters
chan
vmu
vms
msg
option
record_gain

Provides handling for the play message envelope, call the person back, or reply to message.

Returns
zero on success, -1 on error.

Definition at line 16434 of file app_voicemail.c.

16435{
16436 int res = 0;
16437 char filename[PATH_MAX];
16438 struct ast_config *msg_cfg = NULL;
16439 const char *origtime, *context;
16440 char *name, *num;
16441 int retries = 0;
16442 char *cid;
16443 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
16444
16445 vms->starting = 0;
16446
16447 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
16448
16449 /* Retrieve info from VM attribute file */
16450 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
16451 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
16452 msg_cfg = ast_config_load(filename, config_flags);
16453 DISPOSE(vms->curdir, vms->curmsg);
16454 if (!valid_config(msg_cfg)) {
16455 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
16456 return 0;
16457 }
16458
16459 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
16460 ast_config_destroy(msg_cfg);
16461 return 0;
16462 }
16463
16464 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
16465
16466 context = ast_variable_retrieve(msg_cfg, "message", "context");
16467 switch (option) {
16468 case 3: /* Play message envelope */
16469 if (!res) {
16470 res = play_message_datetime(chan, vmu, origtime, filename);
16471 }
16472 if (!res) {
16473 res = play_message_callerid(chan, vms, cid, context, 0, 1);
16474 }
16475
16476 res = 't';
16477 break;
16478
16479 case 2: /* Call back */
16480
16481 if (ast_strlen_zero(cid))
16482 break;
16483
16484 ast_callerid_parse(cid, &name, &num);
16485 while ((res > -1) && (res != 't')) {
16486 switch (res) {
16487 case '1':
16488 if (num) {
16489 /* Dial the CID number */
16490 res = dialout(chan, vmu, num, vmu->callback);
16491 if (res) {
16492 ast_config_destroy(msg_cfg);
16493 return 9;
16494 }
16495 } else {
16496 res = '2';
16497 }
16498 break;
16499
16500 case '2':
16501 /* Want to enter a different number, can only do this if there's a dialout context for this user */
16502 if (!ast_strlen_zero(vmu->dialout)) {
16503 res = dialout(chan, vmu, NULL, vmu->dialout);
16504 if (res) {
16505 ast_config_destroy(msg_cfg);
16506 return 9;
16507 }
16508 } else {
16509 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
16510 res = ast_play_and_wait(chan, "vm-sorry");
16511 }
16512 ast_config_destroy(msg_cfg);
16513 return res;
16514 case '*':
16515 res = 't';
16516 break;
16517 case '3':
16518 case '4':
16519 case '5':
16520 case '6':
16521 case '7':
16522 case '8':
16523 case '9':
16524 case '0':
16525
16526 res = ast_play_and_wait(chan, "vm-sorry");
16527 retries++;
16528 break;
16529 default:
16530 if (num) {
16531 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
16532 res = ast_play_and_wait(chan, "vm-num-i-have");
16533 if (!res)
16534 res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
16535 if (!res)
16536 res = ast_play_and_wait(chan, "vm-tocallnum");
16537 /* Only prompt for a caller-specified number if there is a dialout context specified */
16538 if (!ast_strlen_zero(vmu->dialout)) {
16539 if (!res)
16540 res = ast_play_and_wait(chan, "vm-calldiffnum");
16541 }
16542 } else {
16543 res = ast_play_and_wait(chan, "vm-nonumber");
16544 if (!ast_strlen_zero(vmu->dialout)) {
16545 if (!res)
16546 res = ast_play_and_wait(chan, "vm-toenternumber");
16547 }
16548 }
16549 if (!res) {
16550 res = ast_play_and_wait(chan, "vm-star-cancel");
16551 }
16552 if (!res) {
16553 res = ast_waitfordigit(chan, 6000);
16554 }
16555 if (!res) {
16556 retries++;
16557 if (retries > 3) {
16558 res = 't';
16559 }
16560 }
16561 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
16562 isprint(res) ? res : '?', isprint(res) ? res : '?');
16563 break;
16564
16565 }
16566 if (res == 't')
16567 res = 0;
16568 else if (res == '*')
16569 res = -1;
16570 }
16571 break;
16572
16573 case 1: /* Reply */
16574 /* Send reply directly to sender */
16575 if (ast_strlen_zero(cid))
16576 break;
16577
16578 ast_callerid_parse(cid, &name, &num);
16579 if (!num) {
16580 ast_verb(3, "No CID number available, no reply sent\n");
16581 if (!res)
16582 res = ast_play_and_wait(chan, "vm-nonumber");
16583 ast_config_destroy(msg_cfg);
16584 return res;
16585 } else {
16586 struct ast_vm_user vmu2, *vmu3;
16587 memset(&vmu2, 0, sizeof(vmu2));
16588 vmu3 = find_user(&vmu2, vmu->context, num);
16589 if (vmu3) {
16590 struct leave_vm_options leave_options;
16591 char mailbox[AST_MAX_EXTENSION * 2 + 2];
16592 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
16593
16594 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
16595
16596 memset(&leave_options, 0, sizeof(leave_options));
16597 leave_options.record_gain = record_gain;
16598 leave_options.beeptone = "beep";
16599 res = leave_voicemail(chan, mailbox, &leave_options);
16600 if (!res)
16601 res = 't';
16602 ast_config_destroy(msg_cfg);
16603 free_user(vmu3);
16604 return res;
16605 } else {
16606 /* Sender has no mailbox, can't reply */
16607 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
16608 ast_play_and_wait(chan, "vm-nobox");
16609 res = 't';
16610 ast_config_destroy(msg_cfg);
16611 return res;
16612 }
16613 }
16614 res = 0;
16615
16616 break;
16617 }
16618
16619 ast_config_destroy(msg_cfg);
16620
16621#ifndef IMAP_STORAGE
16622 if (!res) {
16623 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
16624 vms->heard[msg] = 1;
16625 res = wait_file(chan, vms, vms->fn);
16626 }
16627#endif
16628 return res;
16629}
static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
Prompts the user and records a voicemail to a mailbox.
static int 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...
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
#define DISPOSE(a, b)
static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
#define RETRIEVE(a, b, c, d)
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3213
#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:1617
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_NOCACHE
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
#define ast_verb(level,...)
Structure used to handle boolean flags.
Definition utils.h:220
char callback[80]
char dialout[80]
Options for leaving voicemail with the voicemail() application.
Definition app_minivm.c:681
signed char record_gain
Definition app_minivm.c:683
char curdir[PATH_MAX]
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189

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

Referenced by vm_execmain().

◆ alias_mailbox_mapping_create()

static struct alias_mailbox_mapping * alias_mailbox_mapping_create ( const char *  alias,
const char *  mailbox 
)
static

Definition at line 14745 of file app_voicemail.c.

14746{
14747 struct alias_mailbox_mapping *mapping;
14748 size_t from_len = strlen(alias) + 1;
14749 size_t to_len = strlen(mailbox) + 1;
14750
14751 mapping = ao2_alloc(sizeof(*mapping) + from_len + to_len, NULL);
14752 if (!mapping) {
14753 return NULL;
14754 }
14755 mapping->alias = mapping->buf;
14756 mapping->mailbox = mapping->buf + from_len;
14757 ast_copy_string(mapping->alias, alias, from_len); /* Safe */
14758 ast_copy_string(mapping->mailbox, mailbox, to_len); /* Safe */
14759
14760 return mapping;
14761}
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409

References alias_mailbox_mapping::alias, ao2_alloc, ast_copy_string(), alias_mailbox_mapping::buf, alias_mailbox_mapping::mailbox, and NULL.

Referenced by load_aliases().

◆ AO2_STRING_FIELD_CMP_FN() [1/2]

AO2_STRING_FIELD_CMP_FN ( alias_mailbox_mapping  ,
alias   
)

◆ AO2_STRING_FIELD_CMP_FN() [2/2]

AO2_STRING_FIELD_CMP_FN ( mailbox_alias_mapping  ,
mailbox   
)

◆ AO2_STRING_FIELD_HASH_FN() [1/2]

AO2_STRING_FIELD_HASH_FN ( alias_mailbox_mapping  ,
alias   
)

◆ AO2_STRING_FIELD_HASH_FN() [2/2]

AO2_STRING_FIELD_HASH_FN ( mailbox_alias_mapping  ,
mailbox   
)

◆ append_mailbox()

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

Definition at line 13355 of file app_voicemail.c.

13356{
13357 /* Assumes lock is already held */
13358 char *tmp;
13359 char *stringp;
13360 char *s;
13361 struct ast_vm_user *vmu;
13362 char mailbox_full[MAX_VM_MAILBOX_LEN];
13363 int new = 0, old = 0, urgent = 0;
13364 char secretfn[PATH_MAX] = "";
13365
13366 tmp = ast_strdupa(data);
13367
13368 if (!(vmu = find_or_create(context, box)))
13369 return -1;
13370
13371 populate_defaults(vmu);
13372
13373 stringp = tmp;
13374 if ((s = strsep(&stringp, ","))) {
13375 if (!ast_strlen_zero(s) && s[0] == '*') {
13376 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
13377 "\n\tmust be reset in voicemail.conf.\n", box);
13378 }
13379 /* assign password regardless of validity to prevent NULL password from being assigned */
13380 ast_copy_string(vmu->password, s, sizeof(vmu->password));
13381 }
13382 if (stringp && (s = strsep(&stringp, ","))) {
13383 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
13384 }
13385 if (stringp && (s = strsep(&stringp, ","))) {
13386 vmu->email = ast_strdup(s);
13387 }
13388 if (stringp && (s = strsep(&stringp, ","))) {
13389 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
13390 }
13391 if (stringp) {
13392 apply_options(vmu, stringp);
13393 }
13394
13395 switch (vmu->passwordlocation) {
13396 case OPT_PWLOC_SPOOLDIR:
13397 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
13398 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
13399 }
13400
13401 snprintf(mailbox_full, MAX_VM_MAILBOX_LEN, "%s%s%s",
13402 box,
13403 ast_strlen_zero(context) ? "" : "@",
13404 context);
13405
13406 inboxcount2(mailbox_full, &urgent, &new, &old);
13407#ifdef IMAP_STORAGE
13408 imap_logout(mailbox_full);
13409#endif
13410 queue_mwi_event(NULL, mailbox_full, urgent, new, old);
13411
13412 return 0;
13413}
static void read_password_from_file(const char *secretfn, char *password, int passwordlen)
static void populate_defaults(struct ast_vm_user *vmu)
Sets default voicemail system options to a voicemail user.
static void apply_options(struct ast_vm_user *vmu, const char *options)
Destructively Parse options and apply.
static struct ast_vm_user * find_or_create(const char *context, const char *box)
static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Check the given mailbox's message count.

References apply_options(), ast_copy_string(), ast_log, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_vm_user::context, ast_vm_user::email, find_or_create(), ast_vm_user::fullname, inboxcount2(), LOG_WARNING, ast_vm_user::mailbox, MAX_VM_MAILBOX_LEN, NULL, OPT_PWLOC_SPOOLDIR, ast_vm_user::pager, ast_vm_user::password, ast_vm_user::passwordlocation, PATH_MAX, populate_defaults(), queue_mwi_event(), read_password_from_file(), strsep(), and VM_SPOOL_DIR.

Referenced by load_users().

◆ append_vmbox_info_astman()

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

14302{
14303 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
14304 struct ast_vm_msg_snapshot *msg;
14305 int nummessages = 0;
14306 int i;
14307
14308 /* Take a snapshot of the mailbox */
14309 mailbox_snapshot = ast_vm_mailbox_snapshot_create(vmu->mailbox, vmu->context, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
14310 if (!mailbox_snapshot) {
14311 ast_log(LOG_ERROR, "Could not append voicemail box info for box %s@%s.",
14312 vmu->mailbox, vmu->context);
14313 return 0;
14314 }
14315
14316 astman_send_listack(s, m, "Voicemail box detail will follow", "start");
14317 /* walk through each folder's contents and append info for each message */
14318 for (i = 0; i < mailbox_snapshot->folders; i++) {
14319 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
14320 astman_append(s,
14321 "Event: %s\r\n"
14322 "%s"
14323 "Folder: %s\r\n"
14324 "CallerID: %s\r\n"
14325 "Date: %s\r\n"
14326 "Duration: %s\r\n"
14327 "Flag: %s\r\n"
14328 "ID: %s\r\n"
14329 "\r\n",
14330 event_name,
14331 actionid,
14332 msg->folder_name,
14333 msg->callerid,
14334 msg->origdate,
14335 msg->duration,
14336 msg->flag,
14337 msg->msg_id
14338 );
14339 nummessages++;
14340 }
14341 }
14342
14343 /* done, destroy. */
14344 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
14345 astman_send_list_complete_start(s, m, "VoicemailBoxDetailComplete", nummessages);
14347
14348 return 1;
14349}
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:2042
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:2078
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2086
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1921
@ AST_VM_SNAPSHOT_SORT_BY_ID
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.
struct ast_vm_msg_snapshot::@191 msg

References AST_LIST_TRAVERSE, ast_log, ast_vm_mailbox_snapshot_create(), ast_vm_mailbox_snapshot_destroy(), AST_VM_SNAPSHOT_SORT_BY_ID, astman_append(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_vm_user::context, ast_vm_mailbox_snapshot::folders, LOG_ERROR, ast_vm_user::mailbox, ast_vm_msg_snapshot::msg, and NULL.

Referenced by manager_get_mailbox_summary().

◆ append_vmu_info_astman()

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

14178{
14179 int new;
14180 int old;
14181 char *mailbox;
14182 int ret;
14183
14184 if((s == NULL) || (vmu == NULL) || (event_name == NULL) || (actionid == NULL)) {
14185 ast_log(LOG_ERROR, "Wrong input parameter.");
14186 return 0;
14187 }
14188
14189 /* create mailbox string */
14190 if (!ast_strlen_zero(vmu->context)) {
14191 ret = ast_asprintf(&mailbox, "%s@%s", vmu->mailbox, vmu->context);
14192 } else {
14193 ret = ast_asprintf(&mailbox, "%s", vmu->mailbox);
14194 }
14195 if (ret == -1) {
14196 ast_log(LOG_ERROR, "Could not create mailbox string. err[%s]\n", strerror(errno));
14197 return 0;
14198 }
14199
14200 /* get mailbox count */
14201 ret = inboxcount(mailbox, &new, &old);
14202 ast_free(mailbox);
14203 if (ret == -1) {
14204 ast_log(LOG_ERROR, "Could not get mailbox count. user[%s], context[%s]\n",
14205 vmu->mailbox ?: "", vmu->context ?: "");
14206 return 0;
14207 }
14208
14209 astman_append(s,
14210 "Event: %s\r\n"
14211 "%s"
14212 "VMContext: %s\r\n"
14213 "VoiceMailbox: %s\r\n"
14214 "Fullname: %s\r\n"
14215 "Email: %s\r\n"
14216 "Pager: %s\r\n"
14217 "ServerEmail: %s\r\n"
14218 "FromString: %s\r\n"
14219 "MailCommand: %s\r\n"
14220 "Language: %s\r\n"
14221 "TimeZone: %s\r\n"
14222 "Callback: %s\r\n"
14223 "Dialout: %s\r\n"
14224 "UniqueID: %s\r\n"
14225 "ExitContext: %s\r\n"
14226 "SayDurationMinimum: %d\r\n"
14227 "SayEnvelope: %s\r\n"
14228 "SayCID: %s\r\n"
14229 "AttachMessage: %s\r\n"
14230 "AttachmentFormat: %s\r\n"
14231 "DeleteMessage: %s\r\n"
14232 "VolumeGain: %.2f\r\n"
14233 "CanReview: %s\r\n"
14234 "CanMarkUrgent: %s\r\n"
14235 "CallOperator: %s\r\n"
14236 "MaxMessageCount: %d\r\n"
14237 "MaxMessageLength: %d\r\n"
14238 "NewMessageCount: %d\r\n"
14239 "OldMessageCount: %d\r\n"
14240#ifdef IMAP_STORAGE
14241 "IMAPUser: %s\r\n"
14242 "IMAPServer: %s\r\n"
14243 "IMAPPort: %s\r\n"
14244 "IMAPFlags: %s\r\n"
14245#endif
14246 "\r\n",
14247
14248 event_name,
14249 actionid,
14250 vmu->context,
14251 vmu->mailbox,
14252 vmu->fullname,
14253 vmu->email,
14254 vmu->pager,
14257 mailcmd,
14258 vmu->language,
14259 vmu->zonetag,
14260 vmu->callback,
14261 vmu->dialout,
14262 vmu->uniqueid,
14263 vmu->exit,
14264 vmu->saydurationm,
14265 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
14266 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
14267 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
14268 vmu->attachfmt,
14269 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
14270 vmu->volgain,
14271 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
14272 ast_test_flag(vmu, VM_MARK_URGENT) ? "Yes" : "No",
14273 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
14274 vmu->maxmsg,
14275 vmu->maxsecs,
14276 new,
14277 old
14278#ifdef IMAP_STORAGE
14279 ,
14280 vmu->imapuser,
14281 vmu->imapserver,
14282 vmu->imapport,
14283 vmu->imapflags
14284#endif
14285 );
14286
14287 return 1;
14288
14289}
static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
#define VM_DELETE
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
static char language[MAX_LANGUAGE]
Definition chan_iax2.c:361
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
char serveremail[80]
#define ast_test_flag(p, flag)
Definition utils.h:64

References ast_asprintf, ast_free, ast_log, ast_strlen_zero(), ast_test_flag, astman_append(), ast_vm_user::attachfmt, ast_vm_user::callback, ast_vm_user::context, ast_vm_user::dialout, ast_vm_user::email, errno, ast_vm_user::exit, ast_vm_user::fromstring, fromstring, ast_vm_user::fullname, inboxcount(), ast_vm_user::language, LOG_ERROR, ast_vm_user::mailbox, mailcmd, ast_vm_user::maxmsg, ast_vm_user::maxsecs, NULL, ast_vm_user::pager, ast_vm_user::saydurationm, ast_vm_user::serveremail, 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(), and manager_status_voicemail_user().

◆ apply_option()

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

1571{
1572 int x;
1573 if (!strcasecmp(var, "attach")) {
1575 } else if (!strcasecmp(var, "attachfmt")) {
1576 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
1577 } else if (!strcasecmp(var, "attachextrecs")) {
1579 } else if (!strcasecmp(var, "serveremail")) {
1580 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
1581 } else if (!strcasecmp(var, "fromstring")) {
1582 ast_copy_string(vmu->fromstring, value, sizeof(vmu->fromstring));
1583 } else if (!strcasecmp(var, "emailbody")) {
1584 ast_free(vmu->emailbody);
1586 } else if (!strcasecmp(var, "emailsubject")) {
1587 ast_free(vmu->emailsubject);
1589 } else if (!strcasecmp(var, "language")) {
1590 ast_copy_string(vmu->language, value, sizeof(vmu->language));
1591 } else if (!strcasecmp(var, "tz")) {
1592 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
1593 } else if (!strcasecmp(var, "locale")) {
1594 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
1595#ifdef IMAP_STORAGE
1596 } else if (!strcasecmp(var, "imapuser")) {
1597 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
1598 vmu->imapversion = imapversion;
1599 } else if (!strcasecmp(var, "imapserver")) {
1600 ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
1601 vmu->imapversion = imapversion;
1602 } else if (!strcasecmp(var, "imapport")) {
1603 ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
1604 vmu->imapversion = imapversion;
1605 } else if (!strcasecmp(var, "imapflags")) {
1606 ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
1607 vmu->imapversion = imapversion;
1608 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
1609 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
1610 vmu->imapversion = imapversion;
1611 } else if (!strcasecmp(var, "imapfolder")) {
1612 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
1613 vmu->imapversion = imapversion;
1614 } else if (!strcasecmp(var, "imapvmshareid")) {
1615 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
1616 vmu->imapversion = imapversion;
1617#endif
1618 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
1620 } else if (!strcasecmp(var, "saycid")){
1622 } else if (!strcasecmp(var, "sendvoicemail")){
1624 } else if (!strcasecmp(var, "review")){
1626 } else if (!strcasecmp(var, "leaveurgent")){
1628 } else if (!strcasecmp(var, "tempgreetwarn")){
1630 } else if (!strcasecmp(var, "messagewrap")){
1632 } else if (!strcasecmp(var, "operator")) {
1634 } else if (!strcasecmp(var, "envelope")){
1636 } else if (!strcasecmp(var, "moveheard")){
1638 } else if (!strcasecmp(var, "sayduration")){
1640 } else if (!strcasecmp(var, "saydurationm")){
1641 if (sscanf(value, "%30d", &x) == 1) {
1642 vmu->saydurationm = x;
1643 } else {
1644 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
1645 }
1646 } else if (!strcasecmp(var, "forcename")){
1648 } else if (!strcasecmp(var, "forcegreetings")){
1650 } else if (!strcasecmp(var, "callback")) {
1651 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
1652 } else if (!strcasecmp(var, "dialout")) {
1653 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
1654 } else if (!strcasecmp(var, "exitcontext")) {
1655 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
1656 } else if (!strcasecmp(var, "minsecs")) {
1657 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
1658 vmu->minsecs = x;
1659 } else {
1660 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1661 vmu->minsecs = vmminsecs;
1662 }
1663 } else if (!strcasecmp(var, "maxsecs")) {
1664 vmu->maxsecs = atoi(value);
1665 if (vmu->maxsecs <= 0) {
1666 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1667 vmu->maxsecs = vmmaxsecs;
1668 } else {
1669 vmu->maxsecs = atoi(value);
1670 }
1671 } else if (!strcasecmp(var, "maxmsg")) {
1672 vmu->maxmsg = atoi(value);
1673 /* Accept maxmsg=0 (Greetings only voicemail) */
1674 if (vmu->maxmsg < 0) {
1675 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
1676 vmu->maxmsg = MAXMSG;
1677 } else if (vmu->maxmsg > MAXMSGLIMIT) {
1678 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
1679 vmu->maxmsg = MAXMSGLIMIT;
1680 }
1681 } else if (!strcasecmp(var, "nextaftercmd")) {
1683 } else if (!strcasecmp(var, "backupdeleted")) {
1684 if (sscanf(value, "%30d", &x) == 1)
1685 vmu->maxdeletedmsg = x;
1686 else if (ast_true(value))
1687 vmu->maxdeletedmsg = MAXMSG;
1688 else
1689 vmu->maxdeletedmsg = 0;
1690
1691 if (vmu->maxdeletedmsg < 0) {
1692 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
1693 vmu->maxdeletedmsg = MAXMSG;
1694 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
1695 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
1697 }
1698 } else if (!strcasecmp(var, "volgain")) {
1699 sscanf(value, "%30lf", &vmu->volgain);
1700 } else if (!strcasecmp(var, "passwordlocation")) {
1701 if (!strcasecmp(value, "spooldir")) {
1703 } else {
1705 }
1706 } else if (!strcasecmp(var, "options")) {
1707 apply_options(vmu, value);
1708 }
1709}
#define VM_EMAIL_EXT_RECS
char fromstring[100]
char * emailsubject
char exit[80]
char attachfmt[20]
int value
Definition syslog.c:37

References apply_options(), ast_copy_string(), ast_free, ast_log, AST_LOG_WARNING, ast_set2_flag, ast_strdup, ast_true(), ast_vm_user::attachfmt, ast_vm_user::callback, ast_vm_user::dialout, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::exit, ast_vm_user::fromstring, ast_vm_user::language, ast_vm_user::locale, LOG_WARNING, ast_vm_user::maxdeletedmsg, MAXMSG, ast_vm_user::maxmsg, MAXMSGLIMIT, ast_vm_user::maxsecs, ast_vm_user::minsecs, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_VOICEMAILCONF, ast_vm_user::passwordlocation, ast_vm_user::saydurationm, ast_vm_user::serveremail, substitute_escapes(), value, var, 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, vmmaxsecs, vmminsecs, ast_vm_user::volgain, and ast_vm_user::zonetag.

Referenced by apply_options(), and apply_options_full().

◆ apply_options()

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

Destructively Parse options and apply.

Definition at line 1827 of file app_voicemail.c.

1828{
1829 char *stringp;
1830 char *s;
1831 char *var, *value;
1832 stringp = ast_strdupa(options);
1833 while ((s = strsep(&stringp, "|"))) {
1834 value = s;
1835 if ((var = strsep(&value, "=")) && value) {
1836 apply_option(vmu, var, value);
1837 }
1838 }
1839}
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
Sets a specific property value.
static struct test_options options

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

Referenced by append_mailbox(), and apply_option().

◆ apply_options_full()

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

1847{
1848 for (; var; var = var->next) {
1849 if (!strcasecmp(var->name, "vmsecret")) {
1850 ast_copy_string(retval->password, var->value, sizeof(retval->password));
1851 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
1852 if (ast_strlen_zero(retval->password)) {
1853 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
1854 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
1855 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
1856 } else {
1857 ast_copy_string(retval->password, var->value, sizeof(retval->password));
1858 }
1859 }
1860 } else if (!strcasecmp(var->name, "uniqueid")) {
1861 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
1862 } else if (!strcasecmp(var->name, "pager")) {
1863 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
1864 } else if (!strcasecmp(var->name, "email")) {
1865 ast_free(retval->email);
1866 retval->email = ast_strdup(var->value);
1867 } else if (!strcasecmp(var->name, "fullname")) {
1868 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
1869 } else if (!strcasecmp(var->name, "context")) {
1870 ast_copy_string(retval->context, var->value, sizeof(retval->context));
1871 } else if (!strcasecmp(var->name, "emailsubject")) {
1872 ast_free(retval->emailsubject);
1873 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
1874 } else if (!strcasecmp(var->name, "emailbody")) {
1875 ast_free(retval->emailbody);
1876 retval->emailbody = ast_strdup(substitute_escapes(var->value));
1877#ifdef IMAP_STORAGE
1878 } else if (!strcasecmp(var->name, "imapuser")) {
1879 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
1880 retval->imapversion = imapversion;
1881 } else if (!strcasecmp(var->name, "imapserver")) {
1882 ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
1883 retval->imapversion = imapversion;
1884 } else if (!strcasecmp(var->name, "imapport")) {
1885 ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
1886 retval->imapversion = imapversion;
1887 } else if (!strcasecmp(var->name, "imapflags")) {
1888 ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
1889 retval->imapversion = imapversion;
1890 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
1891 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
1892 retval->imapversion = imapversion;
1893 } else if (!strcasecmp(var->name, "imapfolder")) {
1894 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
1895 retval->imapversion = imapversion;
1896 } else if (!strcasecmp(var->name, "imapvmshareid")) {
1897 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
1898 retval->imapversion = imapversion;
1899#endif
1900 } else
1901 apply_option(retval, var->name, var->value);
1902 }
1903}
char uniqueid[80]

References apply_option(), ast_copy_string(), ast_free, ast_log, ast_strdup, ast_strlen_zero(), ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, ast_vm_user::fullname, LOG_WARNING, ast_vm_user::mailbox, ast_vm_user::pager, ast_vm_user::password, substitute_escapes(), ast_vm_user::uniqueid, and var.

Referenced by find_user_realtime().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 17755 of file app_voicemail.c.

◆ ast_str_encode_mime()

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

5380{
5381 struct ast_str *tmp = ast_str_alloca(80);
5382 int first_section = 1;
5383
5385 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5386 for (; *start; start++) {
5387 int need_encoding = 0;
5388 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
5389 need_encoding = 1;
5390 }
5391 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
5392 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
5393 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
5394 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
5395 /* Start new line */
5396 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
5397 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5398 first_section = 0;
5399 }
5400 if (need_encoding && *start == ' ') {
5401 ast_str_append(&tmp, -1, "_");
5402 } else if (need_encoding) {
5403 ast_str_append(&tmp, -1, "=%hhX", *start);
5404 } else {
5405 ast_str_append(&tmp, -1, "%c", *start);
5406 }
5407 }
5408 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
5409 return ast_str_buffer(*end);
5410}
char * end
Definition eagi_proxy.c:73
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
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
#define ast_str_alloca(init_len)
Definition strings.h:848
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
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 *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
Support for dynamic strings.
Definition strings.h:623

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

Referenced by make_email_file(), and sendpage().

◆ ast_str_quote()

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

5308{
5309 const char *ptr;
5310
5311 /* We're only ever passing 0 to maxlen, so short output isn't possible */
5312 ast_str_set(buf, maxlen, "\"");
5313 for (ptr = from; *ptr; ptr++) {
5314 if (*ptr == '"' || *ptr == '\\') {
5315 ast_str_append(buf, maxlen, "\\%c", *ptr);
5316 } else {
5317 ast_str_append(buf, maxlen, "%c", *ptr);
5318 }
5319 }
5320 ast_str_append(buf, maxlen, "\"");
5321
5322 return ast_str_buffer(*buf);
5323}

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

Referenced by make_email_file(), and sendpage().

◆ change_password_realtime()

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

Performs a change of the voicemail password 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 1805 of file app_voicemail.c.

1806{
1807 int res = -1;
1808 if (!strcmp(vmu->password, password)) {
1809 /* No change (but an update would return 0 rows updated, so we opt out here) */
1810 return 0;
1811 }
1812
1813 if (strlen(password) > 10) {
1814 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
1815 }
1816 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
1817 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
1818 ast_copy_string(vmu->password, password, sizeof(vmu->password));
1819 res = 0;
1820 }
1821 return res;
1822}
#define SENTINEL
Definition compiler.h:87
int ast_update2_realtime(const char *family,...) attribute_sentinel
Update realtime configuration.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.

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

Referenced by vm_change_password().

◆ check_mime()

static int check_mime ( const char *  str)
static

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

Definition at line 5352 of file app_voicemail.c.

5353{
5354 for (; *str; str++) {
5355 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
5356 return 1;
5357 }
5358 }
5359 return 0;
5360}
const char * str
Definition app_jack.c:150

References str.

Referenced by make_email_file(), and sendpage().

◆ check_password()

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

1765{
1766 /* check minimum length */
1767 if (strlen(password) < minpassword)
1768 return 1;
1769 /* check that password does not contain '*' character */
1770 if (!ast_strlen_zero(password) && password[0] == '*')
1771 return 1;
1773 char cmd[255], buf[255];
1774
1775 ast_debug(1, "Verify password policies for %s\n", password);
1776
1777 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
1778 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
1779 ast_debug(5, "Result: %s\n", buf);
1780 if (!strncasecmp(buf, "VALID", 5)) {
1781 ast_debug(3, "Passed password check: '%s'\n", buf);
1782 return 0;
1783 } else if (!strncasecmp(buf, "FAILURE", 7)) {
1784 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
1785 return 0;
1786 } else {
1787 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
1788 return 1;
1789 }
1790 }
1791 }
1792 return 0;
1793}
static char * vm_check_password_shell(char *command, char *buf, size_t len)
#define AST_LOG_NOTICE

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

◆ close_mailbox()

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

Definition at line 9592 of file app_voicemail.c.

9593{
9594 int x = 0;
9595 int last_msg_idx = 0;
9596
9597#ifndef IMAP_STORAGE
9598 int res = 0, nummsg;
9599 char fn2[PATH_MAX];
9600#endif
9601 SCOPE_ENTER(3, "user: %s dir: %s msg: %d\n",
9602 vms->username, vms->curdir, vms->curmsg);
9603
9604 if (vms->lastmsg <= -1) {
9605 ast_trace(-1, "No messages in mailbox\n");
9606 goto done;
9607 }
9608
9609 vms->curmsg = -1;
9610#ifndef IMAP_STORAGE
9611 /* Get the deleted messages fixed */
9612 if (vm_lock_path(vms->curdir)) {
9613 SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
9614 }
9615
9616 /* update count as message may have arrived while we've got mailbox open */
9617 last_msg_idx = LAST_MSG_INDEX(vms->curdir);
9618 if (last_msg_idx != vms->lastmsg) {
9619 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
9620 }
9621
9622 /* must check up to last detected message, just in case it is erroneously greater than maxmsg */
9623 for (x = 0; x < last_msg_idx + 1; x++) {
9624 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
9625 /* Save this message. It's not in INBOX or hasn't been heard */
9626 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9627 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
9628 break;
9629 }
9630 vms->curmsg++;
9631 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
9632 if (strcmp(vms->fn, fn2)) {
9633 SCOPE_CALL(-1, RENAME, vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
9634 }
9635 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
9636 /* Move to old folder before deleting */
9637 res = SCOPE_CALL_WITH_INT_RESULT(-1, save_to_folder, vmu, vms, x, 1, NULL, 0);
9638 if (res == ERROR_LOCK_PATH || res == ERROR_MAX_MSGS) {
9639 /* If save failed do not delete the message */
9640 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
9641 vms->deleted[x] = 0;
9642 vms->heard[x] = 0;
9643 --x;
9644 }
9645 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
9646 /* Move to deleted folder */
9647 res = SCOPE_CALL_WITH_INT_RESULT(-1, save_to_folder, vmu, vms, x, 10, NULL, 0);
9648 if (res == ERROR_LOCK_PATH) {
9649 ast_trace(-1, "Unable to lock path. Not moving message to deleted folder.\n");
9650 /* If save failed do not delete the message */
9651 vms->deleted[x] = 0;
9652 vms->heard[x] = 0;
9653 --x;
9654 }
9655 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
9656 /* If realtime storage enabled - we should explicitly delete this message,
9657 cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */
9658 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9659 res = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, vms->curdir, x, vms->fn, NULL);
9660 if (res) {
9661 SCOPE_CALL(-1, DELETE, vms->curdir, x, vms->fn, vmu);
9662 }
9663 }
9664 }
9665
9666 /* Delete ALL remaining messages */
9667 nummsg = x - 1;
9668 for (x = vms->curmsg + 1; x <= nummsg; x++) {
9669 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9670 res = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, vms->curdir, x, vms->fn, NULL);
9671 if (res) {
9672 SCOPE_CALL(-1, DELETE, vms->curdir, x, vms->fn, vmu);
9673 }
9674 }
9675 ast_unlock_path(vms->curdir);
9676#else /* defined(IMAP_STORAGE) */
9677 ast_mutex_lock(&vms->lock);
9678 if (vms->deleted) {
9679 /* Since we now expunge after each delete, deleting in reverse order
9680 * ensures that no reordering occurs between each step. */
9681 last_msg_idx = vms->dh_arraysize;
9682 for (x = last_msg_idx - 1; x >= 0; x--) {
9683 if (vms->deleted[x]) {
9684 ast_debug(3, "IMAP delete of %d\n", x);
9685 DELETE(vms->curdir, x, vms->fn, vmu);
9686 }
9687 }
9688 }
9689#endif
9690
9691done:
9692 if (vms->deleted) {
9693 ast_free(vms->deleted);
9694 vms->deleted = NULL;
9695 }
9696 if (vms->heard) {
9697 ast_free(vms->heard);
9698 vms->heard = NULL;
9699 }
9700 vms->dh_arraysize = 0;
9701#ifdef IMAP_STORAGE
9702 ast_mutex_unlock(&vms->lock);
9703#endif
9704
9705 SCOPE_EXIT_RTN_VALUE(0, "Done\n");
9706}
static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
#define EXISTS(a, b, c, d)
#define ERROR_LOCK_PATH
#define DELETE(a, b, c, d)
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...
#define RENAME(a, b, c, d, e, f, g, h)
#define LAST_MSG_INDEX(a)
#define ERROR_MAX_MSGS
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
#define SCOPE_CALL_WITH_INT_RESULT(level, __funcname,...)
#define SCOPE_CALL(level, __funcname,...)
#define ast_trace(level,...)
int ast_unlock_path(const char *path)
Unlock a path.
Definition main/app.c:2631
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
char username[80]
int done

References ast_check_realtime(), ast_debug, ast_free, ast_log, AST_LOG_NOTICE, AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_test_flag, ast_trace, ast_unlock_path(), ast_vm_user::context, vm_state::curbox, vm_state::curdir, vm_state::curmsg, DELETE, vm_state::deleted, vm_state::dh_arraysize, done, ERROR_LOCK_PATH, ERROR_MAX_MSGS, EXISTS, vm_state::fn, vm_state::heard, LAST_MSG_INDEX, vm_state::lastmsg, ast_vm_user::mailbox, make_file(), ast_vm_user::maxdeletedmsg, NULL, PATH_MAX, RENAME, save_to_folder(), SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, vm_state::username, vm_lock_path(), and VM_MOVEHEARD.

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

◆ complete_voicemail_move_message()

static char * complete_voicemail_move_message ( struct ast_cli_args a,
int  maxpos 
)
static

Definition at line 12204 of file app_voicemail.c.

12205{
12206 const char *word = a->word;
12207 int pos = a->pos;
12208 int state = a->n;
12209 int which = 0;
12210 int wordlen;
12211 struct ast_vm_user *vmu;
12212 const char *context = "", *mailbox = "", *folder = "", *id = "";
12213 char *ret = NULL;
12214
12215 if (pos > maxpos) {
12216 /* If the passed in pos is above the max, return NULL to avoid 'over-filling' the cli */
12217 return NULL;
12218 }
12219
12220 /* if we are in pos 2 or pos 6 in 'forward' mode */
12221 if (pos == 2 || (pos == 6 && maxpos == 8)) {
12222 /* find users */
12223 wordlen = strlen(word);
12225 AST_LIST_TRAVERSE(&users, vmu, list) {
12226 if (!strncasecmp(word, vmu->mailbox , wordlen)) {
12227 if (mailbox && strcmp(mailbox, vmu->mailbox) && ++which > state) {
12228 ret = ast_strdup(vmu->mailbox);
12230 return ret;
12231 }
12232 mailbox = vmu->mailbox;
12233 }
12234 }
12236 } else if (pos == 3 || pos == 7) {
12237 /* find contexts that match the user */
12238 mailbox = (pos == 3) ? a->argv[2] : a->argv[6];
12239 wordlen = strlen(word);
12241 AST_LIST_TRAVERSE(&users, vmu, list) {
12242 if (!strncasecmp(word, vmu->context, wordlen) && !strcasecmp(mailbox, vmu->mailbox)) {
12243 if (context && strcmp(context, vmu->context) && ++which > state) {
12244 ret = ast_strdup(vmu->context);
12246 return ret;
12247 }
12248 context = vmu->context;
12249 }
12250 }
12252 } else if (pos == 4 || pos == 8 || (pos == 6 && maxpos == 6) ) {
12253 int i;
12254 /* Walk through the standard folders */
12255 wordlen = strlen(word);
12256 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12257 if (folder && !strncasecmp(word, mailbox_folders[i], wordlen) && ++which > state) {
12258 return ast_strdup(mailbox_folders[i]);
12259 }
12260 folder = mailbox_folders[i];
12261 }
12262 } else if (pos == 5) {
12263 /* find messages in the folder */
12264 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
12265 struct ast_vm_msg_snapshot *msg;
12266 mailbox = a->argv[2];
12267 context = a->argv[3];
12268 folder = a->argv[4];
12269 wordlen = strlen(word);
12270
12271 /* Take a snapshot of the mailbox and snag the individual info */
12272 if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create(mailbox, context, folder, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
12273 int i;
12274 /* we are only requesting the one folder, but we still need to know it's index */
12275 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12276 if (!strcasecmp(mailbox_folders[i], folder)) {
12277 break;
12278 }
12279 }
12280 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
12281 if (id && !strncasecmp(word, msg->msg_id, wordlen) && ++which > state) {
12282 ret = ast_strdup(msg->msg_id);
12283 break;
12284 }
12285 id = msg->msg_id;
12286 }
12287 /* done, destroy. */
12288 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
12289 }
12290 }
12291
12292 return ret;
12293}
static const char *const mailbox_folders[]
short word
struct ast_vm_user::@86 list
static struct test_val a
#define ARRAY_LEN(a)
Definition utils.h:706

References a, ARRAY_LEN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_vm_mailbox_snapshot_create(), ast_vm_mailbox_snapshot_destroy(), AST_VM_SNAPSHOT_SORT_BY_ID, ast_vm_user::context, ast_vm_user::list, ast_vm_user::mailbox, mailbox_folders, ast_vm_msg_snapshot::msg, and NULL.

Referenced by handle_voicemail_forward_message(), handle_voicemail_move_message(), and handle_voicemail_remove_message().

◆ complete_voicemail_show_mailbox()

static char * complete_voicemail_show_mailbox ( struct ast_cli_args a)
static

Definition at line 12114 of file app_voicemail.c.

12115{
12116 const char *word = a->word;
12117 int pos = a->pos;
12118 int state = a->n;
12119 int which = 0;
12120 int wordlen;
12121 struct ast_vm_user *vmu;
12122 const char *context = "", *mailbox = "";
12123 char *ret = NULL;
12124
12125 /* 0 - voicemail; 1 - show; 2 - mailbox; 3 - <mailbox>; 4 - <context> */
12126 if (pos == 3) {
12127 wordlen = strlen(word);
12129 AST_LIST_TRAVERSE(&users, vmu, list) {
12130 if (!strncasecmp(word, vmu->mailbox , wordlen)) {
12131 if (mailbox && strcmp(mailbox, vmu->mailbox) && ++which > state) {
12132 ret = ast_strdup(vmu->mailbox);
12134 return ret;
12135 }
12136 mailbox = vmu->mailbox;
12137 }
12138 }
12140 } else if (pos == 4) {
12141 /* Only display contexts that match the user in pos 3 */
12142 const char *box = a->argv[3];
12143 wordlen = strlen(word);
12145 AST_LIST_TRAVERSE(&users, vmu, list) {
12146 if (!strncasecmp(word, vmu->context, wordlen) && !strcasecmp(box, vmu->mailbox)) {
12147 if (context && strcmp(context, vmu->context) && ++which > state) {
12148 ret = ast_strdup(vmu->context);
12150 return ret;
12151 }
12152 context = vmu->context;
12153 }
12154 }
12156 }
12157
12158 return ret;
12159}

References a, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_vm_user::context, ast_vm_user::list, ast_vm_user::mailbox, and NULL.

Referenced by handle_voicemail_show_mailbox().

◆ complete_voicemail_show_users()

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

Definition at line 13780 of file app_voicemail.c.

13781{
13782 int which = 0;
13783 int wordlen;
13784 struct ast_vm_user *vmu;
13785 const char *context = "";
13786 char *ret;
13787
13788 /* 0 - voicemail; 1 - show; 2 - users; 3 - for; 4 - <context> */
13789 if (pos > 4)
13790 return NULL;
13791 wordlen = strlen(word);
13793 AST_LIST_TRAVERSE(&users, vmu, list) {
13794 if (!strncasecmp(word, vmu->context, wordlen)) {
13795 if (context && strcmp(context, vmu->context) && ++which > state) {
13796 ret = ast_strdup(vmu->context);
13798 return ret;
13799 }
13800 /* ignore repeated contexts ? */
13801 context = vmu->context;
13802 }
13803 }
13805 return NULL;
13806}

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_vm_user::context, ast_vm_user::list, and NULL.

Referenced by handle_voicemail_show_users().

◆ copy()

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

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

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

Referenced by ast_ari_asterisk_update_object(), ast_bucket_file_copy(), ast_func_read(), ast_func_read2(), ast_func_write(), ast_sip_for_each_aor(), ast_sip_sanitize_xml(), ast_sip_session_add_supplements(), ast_sorcery_copy(), ast_sorcery_object_set_copy_handler(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), authenticate_api_key(), check_nonce(), config_hook_exec(), copy_plain_file(), handle_cli_transcoder_show(), handle_updates(), iax2_register(), module_load_error(), parse_hint_device(), parse_hint_presence(), process_dahdi(), reload_followme(), and vm_forwardoptions().

◆ copy_message()

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_folder

This is only used by file storage based mailboxes.

Returns
zero on success, -1 on error.

Definition at line 6344 of file app_voicemail.c.

6347{
6348 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
6349 const char *frombox = mbox(vmu, imbox);
6350 const char *userfolder;
6351 int recipmsgnum;
6352 int res = 0;
6353 SCOPE_ENTER(3, "mb: %s imb: %d msgnum: %d recip: %s dir: %s dest_folder: %s",
6354 vmu->mailbox, imbox, msgnum, recip->mailbox, dir, dest_folder);
6355
6356 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
6357
6358 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
6359 userfolder = "Urgent";
6360 } else if (!ast_strlen_zero(dest_folder)) {
6361 userfolder = dest_folder;
6362 } else {
6363 userfolder = "INBOX";
6364 }
6365
6366 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
6367 ast_trace(-1, "todir: %s\n", todir);
6368
6369 if (!dir)
6370 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
6371 else
6372 ast_copy_string(fromdir, dir, sizeof(fromdir));
6373
6374 ast_trace(-1, "fromdir: %s\n", fromdir);
6375
6376 make_file(frompath, sizeof(frompath), fromdir, msgnum);
6377 ast_trace(-1, "frompath: %s\n", frompath);
6378
6379 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
6380 ast_trace(-1, "todir: %s\n", todir);
6381
6382 if (vm_lock_path(todir)) {
6384 }
6385
6386 recipmsgnum = LAST_MSG_INDEX(todir) + 1;
6387 ast_trace(-1, "recip msgnum: %d\n", recipmsgnum);
6388
6389 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
6390 int exists = 0;
6391
6392 make_file(topath, sizeof(topath), todir, recipmsgnum);
6393 ast_trace(-1, "topath: %s\n", topath);
6394
6395 exists = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, fromdir, msgnum, frompath, chan ? ast_channel_language(chan) : "");
6396 if (exists) {
6397 SCOPE_CALL(-1, COPY, fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
6398 } else {
6399 SCOPE_CALL(-1, copy_plain_file,frompath, topath);
6400 SCOPE_CALL(-1, STORE, todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
6401 SCOPE_CALL(-1, vm_delete, topath);
6402
6403 }
6404 } else {
6405 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
6406 res = -1;
6407 }
6408 ast_unlock_path(todir);
6409 if (chan) {
6410 struct ast_party_caller *caller = ast_channel_caller(chan);
6411 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
6412 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
6413 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
6414 flag);
6415 }
6416
6417 SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d\n", res);
6418}
static int vm_delete(char *file)
Removes the voicemail sound and information file.
#define COPY(a, b, c, d, e, f, g, h)
static int inprocess_count(const char *context, const char *mailbox, int delta)
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...
static void copy_plain_file(char *frompath, char *topath)
Copies a voicemail information (envelope) file.
#define STORE(a, b, c, d, e, f, g, h, i, j, k)
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.
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
long int flag
Definition f2c.h:83
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition func_logic.c:185
#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
Caller Party information.
Definition channel.h:420
struct ast_party_id id
Caller party ID.
Definition channel.h:422
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293

References ast_channel_caller(), ast_channel_language(), ast_copy_string(), ast_log, AST_LOG_ERROR, AST_LOG_NOTICE, ast_strlen_zero(), ast_trace, ast_unlock_path(), ast_vm_user::context, COPY, copy_plain_file(), create_dirpath(), ERROR_LOCK_PATH, EXISTS, exists(), ast_party_caller::id, inprocess_count(), LAST_MSG_INDEX, ast_vm_user::mailbox, make_dir(), make_file(), maxmsg, mbox(), ast_party_id::name, notify_new_message(), NULL, ast_party_id::number, PATH_MAX, S_COR, SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, STORE, ast_party_name::str, ast_party_number::str, ast_party_name::valid, ast_party_number::valid, vm_delete(), and vm_lock_path().

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

◆ copy_plain_file()

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

Copies a voicemail information (envelope) file.

Parameters
frompath
topath

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

Definition at line 5169 of file app_voicemail.c.

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

References ast_check_realtime(), ast_filecopy(), ast_load_realtime(), ast_store_realtime(), ast_variables_destroy(), copy(), ast_variable::name, ast_variable::next, NULL, PATH_MAX, priority, SENTINEL, ast_variable::value, and var.

Referenced by copy_message().

◆ count_messages()

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

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

Parameters
vmu
dir

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

Returns
the count of messages, zero or more.

Definition at line 5004 of file app_voicemail.c.

5005{
5006
5007 int vmcount = 0;
5008 DIR *vmdir = NULL;
5009 struct dirent *vment = NULL;
5010
5011 if (vm_lock_path(dir))
5012 return ERROR_LOCK_PATH;
5013
5014 if ((vmdir = opendir(dir))) {
5015 while ((vment = readdir(vmdir))) {
5016 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
5017 vmcount++;
5018 }
5019 }
5020 closedir(vmdir);
5021 }
5022 ast_unlock_path(dir);
5023
5024 return vmcount;
5025}

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

◆ create_dirpath()

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

2221{
2222 mode_t mode = VOICEMAIL_DIR_MODE;
2223 int res;
2224
2225 make_dir(dest, len, context, ext, folder);
2226 if ((res = ast_mkdir(dest, mode))) {
2227 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
2228 return -1;
2229 }
2230 return 0;
2231}
#define VOICEMAIL_DIR_MODE
const char * ext
Definition http.c:151
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513

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

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

◆ dialout()

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

Definition at line 16362 of file app_voicemail.c.

16363{
16364 int cmd = 0;
16365 char destination[80] = "";
16366 int retries = 0;
16367
16368 if (!num) {
16369 ast_verb(3, "Destination number will be entered manually\n");
16370 while (retries < 3 && cmd != 't') {
16371 destination[1] = '\0';
16372 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
16373 if (!cmd)
16374 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
16375 if (!cmd)
16376 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
16377 if (!cmd) {
16378 cmd = ast_waitfordigit(chan, 6000);
16379 if (cmd)
16380 destination[0] = cmd;
16381 }
16382 if (!cmd) {
16383 retries++;
16384 } else {
16385
16386 if (cmd < 0)
16387 return 0;
16388 if (cmd == '*') {
16389 ast_verb(3, "User hit '*' to cancel outgoing call\n");
16390 return 0;
16391 }
16392 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
16393 retries++;
16394 else
16395 cmd = 't';
16396 }
16397 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
16398 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
16399 }
16400 if (retries >= 3) {
16401 return 0;
16402 }
16403
16404 } else {
16405 ast_verb(3, "Destination number is CID number '%s'\n", num);
16406 ast_copy_string(destination, num, sizeof(destination));
16407 }
16408
16409 if (!ast_strlen_zero(destination)) {
16410 if (destination[strlen(destination) -1 ] == '*')
16411 return 0;
16412 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan));
16413 ast_channel_exten_set(chan, destination);
16414 ast_channel_context_set(chan, outgoing_context);
16415 ast_channel_priority_set(chan, 0);
16416 return 9;
16417 }
16418 return 0;
16419}
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
Definition channel.c:6615

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

Referenced by advanced_options(), and vm_execmain().

◆ find_or_create()

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

Definition at line 13315 of file app_voicemail.c.

13316{
13317 struct ast_vm_user *vmu;
13318
13319 if (!ast_strlen_zero(box) && box[0] == '*') {
13320 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
13321 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
13322 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
13323 "\n\tand will be ignored.\n", box, context);
13324 return NULL;
13325 }
13326
13327 AST_LIST_TRAVERSE(&users, vmu, list) {
13328 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
13329 if (strcasecmp(vmu->context, context)) {
13330 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
13331 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
13332 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
13333 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
13334 }
13335 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
13336 return NULL;
13337 }
13338 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
13339 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
13340 return NULL;
13341 }
13342 }
13343
13344 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
13345 return NULL;
13346
13347 ast_copy_string(vmu->context, context, sizeof(vmu->context));
13348 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
13349
13351
13352 return vmu;
13353}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.

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

Referenced by append_mailbox().

◆ find_user()

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

1979{
1980 /* This function could be made to generate one from a database, too */
1981 struct ast_vm_user *vmu = NULL, *cur;
1983
1985 context = "default";
1986
1987 AST_LIST_TRAVERSE(&users, cur, list) {
1988#ifdef IMAP_STORAGE
1989 if (cur->imapversion != imapversion) {
1990 continue;
1991 }
1992#endif
1993 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
1994 break;
1995 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1996 break;
1997 }
1998 if (cur) {
1999 /* Make a copy, so that on a reload, we have no race */
2000 if ((vmu = (ivm ? ivm : ast_calloc(1, sizeof(*vmu))))) {
2001 ast_free(vmu->email);
2002 ast_free(vmu->emailbody);
2003 ast_free(vmu->emailsubject);
2004 *vmu = *cur;
2005 vmu->email = ast_strdup(cur->email);
2006 vmu->emailbody = ast_strdup(cur->emailbody);
2007 vmu->emailsubject = ast_strdup(cur->emailsubject);
2008 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
2009 AST_LIST_NEXT(vmu, list) = NULL;
2010 }
2011 }
2013 if (!vmu) {
2014 vmu = find_user_realtime(ivm, context, mailbox);
2015 }
2016 if (!vmu && !ast_strlen_zero(aliasescontext)) {
2017 struct alias_mailbox_mapping *mapping;
2018 char *search_string = ast_alloca(MAX_VM_MAILBOX_LEN);
2019
2020 snprintf(search_string, MAX_VM_MAILBOX_LEN, "%s%s%s",
2021 mailbox,
2022 ast_strlen_zero(context) ? "" : "@",
2023 S_OR(context, ""));
2024
2025 mapping = ao2_find(alias_mailbox_mappings, search_string, OBJ_SEARCH_KEY);
2026 if (mapping) {
2027 char *search_mailbox = NULL;
2028 char *search_context = NULL;
2029
2030 separate_mailbox(ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);
2031 ao2_ref(mapping, -1);
2032 vmu = find_user(ivm, search_mailbox, search_context);
2033 }
2034 }
2035
2036 return vmu;
2037}
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.
#define VM_ALLOCED
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.

References alias_mailbox_mappings, aliasescontext, ao2_find, ao2_ref, ast_alloca, ast_calloc, ast_free, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_set2_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_vm_user::context, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, find_user(), find_user_realtime(), globalflags, ast_vm_user::list, ast_vm_user::mailbox, alias_mailbox_mapping::mailbox, MAX_VM_MAILBOX_LEN, NULL, OBJ_SEARCH_KEY, S_OR, separate_mailbox(), VM_ALLOCED, and VM_SEARCH.

Referenced by acf_vm_info(), advanced_options(), find_user(), forward_message(), leave_voicemail(), manager_get_mailbox_summary(), manager_status_voicemail_user(), msg_create_from_file(), play_message_by_id(), show_mailbox_details(), vm_authenticate(), vm_execmain(), vm_mailbox_snapshot_create(), vm_msg_forward(), vm_msg_move(), vm_msg_play(), and vm_msg_remove().

◆ find_user_realtime()

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
mailbox

This is called as a fall through case when the normal find_user() was not able to find a user. That is, the default it so look in the usual voicemail users file first.

Returns
The ast_vm_user structure for the user that was found.

Definition at line 1937 of file app_voicemail.c.

1938{
1939 struct ast_variable *var;
1940 struct ast_vm_user *retval;
1941
1942 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
1943 if (ivm) {
1944 memset(retval, 0, sizeof(*retval));
1945 }
1946 populate_defaults(retval);
1947 if (!ivm) {
1948 ast_set_flag(retval, VM_ALLOCED);
1949 }
1950 if (mailbox) {
1951 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
1952 }
1954 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
1955 } else {
1956 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
1957 }
1958 if (var) {
1959 apply_options_full(retval, var);
1961 } else {
1962 if (!ivm)
1963 ast_free(retval);
1964 retval = NULL;
1965 }
1966 }
1967 return retval;
1968}
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
Loads the options specific to a voicemail user.
#define ast_set_flag(p, flag)
Definition utils.h:71

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

Referenced by find_user().

◆ forward_message()

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
urgent

Reads the destination mailbox(es) from keypad input for CID, or if use_directory feature is enabled, the Directory.

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

  • allow the leaving of a message for ourselves. (Will not allow us to forward a message to ourselves, when is_new_message == 0).
  • attempt to determine the context and 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 8705 of file app_voicemail.c.

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

References ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_language(), ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_fileexists(), ast_filerename(), AST_LIST_EMPTY, AST_LIST_HEAD_NOLOCK_STATIC, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, AST_LOG_ERROR, AST_LOG_WARNING, AST_MAX_EXTENSION, ast_play_and_wait(), ast_readstring(), ast_say_digit_str(), ast_strdupa, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, ast_variable_retrieve(), ast_waitfordigit(), leave_vm_options::beeptone, CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, copy_message(), vm_state::curbox, vm_state::curdir, vm_state::curmsg, DISPOSE, done, find_user(), vm_state::fn, free_user(), globalflags, inboxcount(), inprocess_count(), leave_voicemail(), ast_app::list, LOG_ERROR, LOG_NOTICE, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, name, NULL, PATH_MAX, pbx_exec(), pbx_findapp(), leave_vm_options::record_gain, RETRIEVE, run_externnotify(), S_COR, S_OR, SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, sendmail(), serveremail, STORE, strsep(), vm_state::username, VM_ATTACH, VM_DIRECTFORWARD, vm_forwardoptions(), VM_FWDURGAUTO, VM_SPOOL_DIR, and vmfmts.

Referenced by vm_execmain().

◆ forward_message_from_mailbox()

static int forward_message_from_mailbox ( struct ast_cli_args a)
static

Definition at line 12059 of file app_voicemail.c.

12060{
12061 const char *from_mailbox = a->argv[2];
12062 const char *from_context = a->argv[3];
12063 const char *from_folder = a->argv[4];
12064 const char *id[] = { a->argv[5] };
12065 const char *to_mailbox = a->argv[6];
12066 const char *to_context = a->argv[7];
12067 const char *to_folder = a->argv[8];
12068 int ret = vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1, id, 0);
12069 if (ret) {
12070 ast_cli(a->fd, "Error forwarding message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12071 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12072 } else {
12073 ast_cli(a->fd, "Forwarded message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12074 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12075 }
12076 return ret;
12077}
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)
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
from_mailbox(key, val, section, pjsip, nmapped)

References a, ast_cli(), and vm_msg_forward().

Referenced by handle_voicemail_forward_message().

◆ free_user()

static void free_user ( struct ast_vm_user vmu)
static

◆ free_user_final()

static void free_user_final ( struct ast_vm_user vmu)
static

Definition at line 2280 of file app_voicemail.c.

2281{
2282 if (!vmu) {
2283 return;
2284 }
2285
2286 if (!ast_strlen_zero(vmu->mailbox)) {
2288 }
2289
2290 free_user(vmu);
2291}
int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid)
Delete MWI state cached by stasis with all parameters.
Definition mwi.c:404

References ast_delete_mwi_state_full(), ast_strlen_zero(), ast_vm_user::context, free_user(), ast_vm_user::mailbox, and NULL.

Referenced by free_vm_users().

◆ free_vm_users()

static void free_vm_users ( void  )
static

Free the users structure.

Definition at line 14634 of file app_voicemail.c.

14635{
14636 struct ast_vm_user *current;
14638 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
14641 }
14643}
static void free_user_final(struct ast_vm_user *vmu)
size_t current

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_set_flag, current, free_user_final(), ast_vm_user::list, and VM_ALLOCED.

Referenced by actual_load_config(), and unload_module().

◆ free_vm_zones()

static void free_vm_zones ( void  )
static

Free the zones structure.

Definition at line 14646 of file app_voicemail.c.

14647{
14648 struct vm_zone *zcur;
14650 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
14651 free_zone(zcur);
14653}
static void free_zone(struct vm_zone *z)
struct vm_zone::@87 list

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, free_zone(), and vm_zone::list.

Referenced by actual_load_config(), and unload_module().

◆ free_zone()

static void free_zone ( struct vm_zone z)
static

Definition at line 6123 of file app_voicemail.c.

6124{
6125 ast_free(z);
6126}

References ast_free.

Referenced by free_vm_zones().

◆ generate_msg_id()

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

6666{
6667 /* msg id is time of msg_id generation plus an incrementing value
6668 * called each time a new msg_id is generated. This should achieve uniqueness,
6669 * but only in single system solutions.
6670 */
6671 unsigned int unique_counter = ast_atomic_fetchadd_int(&msg_id_incrementor, +1);
6672 snprintf(dst, MSG_ID_LEN, "%ld-%08x", (long) time(NULL), unique_counter);
6673}
static int msg_id_incrementor
#define MSG_ID_LEN
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:764

References ast_atomic_fetchadd_int(), msg_id_incrementor, MSG_ID_LEN, and NULL.

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

◆ get_date()

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

6080{
6081 struct ast_tm tm;
6082 struct timeval t = ast_tvnow();
6083
6084 ast_localtime(&t, &tm, "UTC");
6085
6086 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
6087}
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
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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

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

Referenced by leave_voicemail(), and msg_create_from_file().

◆ get_folder()

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

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

Definition at line 8244 of file app_voicemail.c.

8245{
8246 int x;
8247 int d;
8248 char fn[PATH_MAX];
8249 d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
8250 if (d)
8251 return d;
8252 for (x = start; x < 5; x++) { /* For all folders */
8253 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
8254 return d;
8255 d = ast_play_and_wait(chan, "vm-for"); /* "for" */
8256 if (d)
8257 return d;
8258 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
8259
8260 /* The inbox folder can have its name changed under certain conditions
8261 * so this checks if the sound file exists for the inbox folder name and
8262 * if it doesn't, plays the default name instead. */
8263 if (x == 0) {
8264 if (ast_fileexists(fn, NULL, NULL)) {
8265 d = vm_play_folder_name(chan, fn);
8266 } else {
8267 ast_verb(4, "Failed to find file %s; falling back to INBOX\n", fn);
8268 d = vm_play_folder_name(chan, "vm-INBOX");
8269 }
8270 } else {
8271 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
8272 d = vm_play_folder_name(chan, fn);
8273 }
8274
8275 if (d)
8276 return d;
8277 d = ast_waitfordigit(chan, 500);
8278 if (d)
8279 return d;
8280 }
8281
8282 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
8283 if (d)
8284 return d;
8285 d = ast_waitfordigit(chan, 4000);
8286 return d;
8287}
static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
#define AST_DIGIT_ANY
Definition file.h:48
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition channel.c:8341
static struct test_val d

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

Referenced by get_folder2().

◆ get_folder2()

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

8330{
8331 int res = 0;
8332 int loops = 0;
8333
8334 res = ast_play_and_wait(chan, fn); /* Folder name */
8335 while (((res < '0') || (res > '9')) &&
8336 (res != '#') && (res >= 0) &&
8337 loops < 4) {
8338 /* res = get_folder(chan, 0); */
8339 if (!strcasecmp(ast_channel_language(chan), "ja")) { /* Japanese syntax */
8340 res = get_folder_ja(chan, 0);
8341 } else { /* Default syntax */
8342 res = get_folder(chan, 0);
8343 }
8344 loops++;
8345 }
8346 if (loops == 4) { /* give up */
8347 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
8348 return '#';
8349 }
8350 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8351 isprint(res) ? res : '?', isprint(res) ? res : '?');
8352 return res;
8353}
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_folder_ja(struct ast_channel *chan, int start)

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

Referenced by vm_execmain().

◆ get_folder_by_name()

static int get_folder_by_name ( const char *  name)
static

Definition at line 2249 of file app_voicemail.c.

2250{
2251 size_t i;
2252
2253 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
2254 if (strcasecmp(name, mailbox_folders[i]) == 0) {
2255 return i;
2256 }
2257 }
2258
2259 return -1;
2260}

References ARRAY_LEN, mailbox_folders, and name.

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

◆ get_folder_ja()

static int get_folder_ja ( struct ast_channel chan,
int  start 
)
static

Definition at line 8290 of file app_voicemail.c.

8291{
8292 int x;
8293 int d;
8294 char fn[256];
8295 for (x = start; x < 5; x++) { /* For all folders */
8296 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL))) {
8297 return d;
8298 }
8299 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
8300 d = vm_play_folder_name(chan, fn);
8301 if (d) {
8302 return d;
8303 }
8304 d = ast_waitfordigit(chan, 500);
8305 if (d) {
8306 return d;
8307 }
8308 }
8309 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
8310 if (d) {
8311 return d;
8312 }
8313 d = ast_waitfordigit(chan, 4000);
8314 return d;
8315}

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), ast_waitfordigit(), d, mbox(), NULL, and vm_play_folder_name().

Referenced by get_folder2().

◆ handle_voicemail_forward_message()

static char * handle_voicemail_forward_message ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 12295 of file app_voicemail.c.

12296{
12297 switch (cmd) {
12298 case CLI_INIT:
12299 e->command = "voicemail forward";
12300 e->usage =
12301 "Usage: voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>\n"
12302 " Forward message <messageid> in mailbox <mailbox>@<context> <from_folder>\n"
12303 " to mailbox <mailbox>@<context> <to_folder>\n";
12304 return NULL;
12305 case CLI_GENERATE:
12307 case CLI_HANDLER:
12308 break;
12309 }
12310
12311 if (a->argc != 9) {
12312 return CLI_SHOWUSAGE;
12313 }
12314
12316 return CLI_FAILURE;
12317 }
12318
12319 return CLI_SUCCESS;
12320}
static int forward_message_from_mailbox(struct ast_cli_args *a)
static char * complete_voicemail_move_message(struct ast_cli_args *a, int maxpos)
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
@ CLI_HANDLER
Definition cli.h:154
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177

References a, CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_move_message(), forward_message_from_mailbox(), NULL, and ast_cli_entry::usage.

◆ handle_voicemail_move_message()

static char * handle_voicemail_move_message ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 12322 of file app_voicemail.c.

12323{
12324 switch (cmd) {
12325 case CLI_INIT:
12326 e->command = "voicemail move";
12327 e->usage =
12328 "Usage: voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>\n"
12329 " Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>\n";
12330 return NULL;
12331 case CLI_GENERATE:
12333 case CLI_HANDLER:
12334 break;
12335 }
12336
12337 if (a->argc != 7) {
12338 return CLI_SHOWUSAGE;
12339 }
12340
12342 return CLI_FAILURE;
12343 }
12344
12345 return CLI_SUCCESS;
12346}
static int move_message_from_mailbox(struct ast_cli_args *a)

References a, CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_move_message(), move_message_from_mailbox(), NULL, and ast_cli_entry::usage.

◆ handle_voicemail_reload()

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

Reload voicemail configuration from the CLI.

Definition at line 13961 of file app_voicemail.c.

13962{
13963 switch (cmd) {
13964 case CLI_INIT:
13965 e->command = "voicemail reload";
13966 e->usage =
13967 "Usage: voicemail reload\n"
13968 " Reload voicemail configuration\n";
13969 return NULL;
13970 case CLI_GENERATE:
13971 return NULL;
13972 }
13973
13974 if (a->argc != 2)
13975 return CLI_SHOWUSAGE;
13976
13977 ast_cli(a->fd, "Reloading voicemail configuration...\n");
13978 load_config(1);
13979
13980 return CLI_SUCCESS;
13981}
static int load_config(void)

References a, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, load_config(), NULL, and ast_cli_entry::usage.

◆ handle_voicemail_remove_message()

static char * handle_voicemail_remove_message ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 12348 of file app_voicemail.c.

12349{
12350 switch (cmd) {
12351 case CLI_INIT:
12352 e->command = "voicemail remove";
12353 e->usage =
12354 "Usage: voicemail remove <mailbox> <context> <from_folder> <messageid>\n"
12355 " Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>\n";
12356 return NULL;
12357 case CLI_GENERATE:
12359 case CLI_HANDLER:
12360 break;
12361 }
12362
12363 if (a->argc != 6) {
12364 return CLI_SHOWUSAGE;
12365 }
12366
12368 return CLI_FAILURE;
12369 }
12370
12371 return CLI_SUCCESS;
12372}
static int remove_message_from_mailbox(struct ast_cli_args *a)

References a, CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_move_message(), NULL, remove_message_from_mailbox(), and ast_cli_entry::usage.

◆ handle_voicemail_show_aliases()

static char * handle_voicemail_show_aliases ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Show a list of voicemail zones in the CLI.

Definition at line 13921 of file app_voicemail.c.

13922{
13923 struct ao2_iterator aliases;
13924 struct alias_mailbox_mapping *mapping;
13925#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
13926 char *res = CLI_SUCCESS;
13927
13928 switch (cmd) {
13929 case CLI_INIT:
13930 e->command = "voicemail show aliases";
13931 e->usage =
13932 "Usage: voicemail show aliases\n"
13933 " Lists mailbox aliases\n";
13934 return NULL;
13935 case CLI_GENERATE:
13936 return NULL;
13937 }
13938
13939 if (a->argc != 3)
13940 return CLI_SHOWUSAGE;
13941
13943 ast_cli(a->fd, "Aliases are not enabled\n");
13944 return res;
13945 }
13946
13947 ast_cli(a->fd, "Aliases context: %s\n", aliasescontext);
13948 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, "Alias", "Mailbox");
13949
13951 while ((mapping = ao2_iterator_next(&aliases))) {
13952 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);
13953 ao2_ref(mapping, -1);
13954 }
13956
13957 return res;
13958}
#define ALIASES_OUTPUT_FORMAT
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static struct progalias aliases[]
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821

References a, alias_mailbox_mapping::alias, alias_mailbox_mappings, aliases, ALIASES_OUTPUT_FORMAT, aliasescontext, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, alias_mailbox_mapping::mailbox, NULL, and ast_cli_entry::usage.

◆ handle_voicemail_show_mailbox()

static char * handle_voicemail_show_mailbox ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 12161 of file app_voicemail.c.

12162{
12163 switch (cmd) {
12164 case CLI_INIT:
12165 e->command = "voicemail show mailbox";
12166 e->usage =
12167 "Usage: voicemail show mailbox <mailbox> <context>\n"
12168 " Show contents of mailbox <mailbox>@<context>\n";
12169 return NULL;
12170 case CLI_GENERATE:
12172 case CLI_HANDLER:
12173 break;
12174 }
12175
12176 if (a->argc != 5) {
12177 return CLI_SHOWUSAGE;
12178 }
12179
12181 return CLI_FAILURE;
12182 }
12183
12184 return CLI_SUCCESS;
12185}
static int show_messages_for_mailbox(struct ast_cli_args *a)
static char * complete_voicemail_show_mailbox(struct ast_cli_args *a)

References a, CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_show_mailbox(), NULL, show_messages_for_mailbox(), and ast_cli_entry::usage.

◆ handle_voicemail_show_users()

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

Show a list of voicemail users in the CLI.

Definition at line 13809 of file app_voicemail.c.

13810{
13811 struct ast_vm_user *vmu;
13812#define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
13813 const char *context = NULL;
13814 int users_counter = 0;
13815
13816 switch (cmd) {
13817 case CLI_INIT:
13818 e->command = "voicemail show users [for]";
13819 e->usage =
13820 "Usage: voicemail show users [for <context>]\n"
13821 " Lists all mailboxes currently set up\n";
13822 return NULL;
13823 case CLI_GENERATE:
13824 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
13825 }
13826
13827 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
13828 return CLI_SHOWUSAGE;
13829 if (a->argc == 5) {
13830 if (strcmp(a->argv[3],"for"))
13831 return CLI_SHOWUSAGE;
13832 context = a->argv[4];
13833 }
13834
13835 if (ast_check_realtime("voicemail")) {
13836 if (!context) {
13837 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
13838 return CLI_SHOWUSAGE;
13839 }
13840 return show_users_realtime(a->fd, context);
13841 }
13842
13844 if (AST_LIST_EMPTY(&users)) {
13845 ast_cli(a->fd, "There are no voicemail users currently defined\n");
13847 return CLI_FAILURE;
13848 }
13849 if (!context) {
13850 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
13851 } else {
13852 int count = 0;
13853 AST_LIST_TRAVERSE(&users, vmu, list) {
13854 if (!strcmp(context, vmu->context)) {
13855 count++;
13856 break;
13857 }
13858 }
13859 if (count) {
13860 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
13861 } else {
13862 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
13864 return CLI_FAILURE;
13865 }
13866 }
13867 AST_LIST_TRAVERSE(&users, vmu, list) {
13868 int newmsgs = 0, oldmsgs = 0;
13869 char count[12], tmp[256] = "";
13870
13871 if (!context || !strcmp(context, vmu->context)) {
13872 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
13873 inboxcount(tmp, &newmsgs, &oldmsgs);
13874 snprintf(count, sizeof(count), "%d", newmsgs);
13875 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
13876 users_counter++;
13877 }
13878 }
13880 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
13881 return CLI_SUCCESS;
13882}
#define HVSU_OUTPUT_FORMAT
static char * complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
static char * show_users_realtime(int fd, const char *context)

References a, ast_check_realtime(), ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_voicemail_show_users(), ast_vm_user::context, ast_vm_user::fullname, HVSU_OUTPUT_FORMAT, inboxcount(), ast_vm_user::list, ast_vm_user::mailbox, NULL, show_users_realtime(), ast_cli_entry::usage, and ast_vm_user::zonetag.

◆ handle_voicemail_show_zones()

static char * handle_voicemail_show_zones ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Show a list of voicemail zones in the CLI.

Definition at line 13885 of file app_voicemail.c.

13886{
13887 struct vm_zone *zone;
13888#define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
13889 char *res = CLI_SUCCESS;
13890
13891 switch (cmd) {
13892 case CLI_INIT:
13893 e->command = "voicemail show zones";
13894 e->usage =
13895 "Usage: voicemail show zones\n"
13896 " Lists zone message formats\n";
13897 return NULL;
13898 case CLI_GENERATE:
13899 return NULL;
13900 }
13901
13902 if (a->argc != 3)
13903 return CLI_SHOWUSAGE;
13904
13906 if (!AST_LIST_EMPTY(&zones)) {
13907 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
13908 AST_LIST_TRAVERSE(&zones, zone, list) {
13909 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
13910 }
13911 } else {
13912 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
13913 res = CLI_FAILURE;
13914 }
13916
13917 return res;
13918}
#define HVSZ_OUTPUT_FORMAT
char msg_format[512]
char name[80]
char timezone[80]

References a, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, HVSZ_OUTPUT_FORMAT, vm_zone::list, vm_zone::msg_format, vm_zone::name, NULL, vm_zone::timezone, and ast_cli_entry::usage.

◆ has_voicemail()

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

6499{
6500 char tmp[256], *tmp2 = tmp, *box, *context;
6501 ast_copy_string(tmp, mailbox, sizeof(tmp));
6502 if (ast_strlen_zero(folder)) {
6503 folder = "INBOX";
6504 }
6505 while ((box = strsep(&tmp2, ",&"))) {
6506 if ((context = strchr(box, '@')))
6507 *context++ = '\0';
6508 else
6509 context = "default";
6510 if (__has_voicemail(context, box, folder, 1))
6511 return 1;
6512 /* If we are checking INBOX, we should check Urgent as well */
6513 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
6514 return 1;
6515 }
6516 }
6517 return 0;
6518}
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)

References __has_voicemail(), ast_copy_string(), ast_strlen_zero(), alias_mailbox_mapping::mailbox, and strsep().

Referenced by ast_app_has_voicemail().

◆ inboxcount()

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

Definition at line 6598 of file app_voicemail.c.

6599{
6600 int urgentmsgs = 0;
6601 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
6602 if (newmsgs) {
6603 *newmsgs += urgentmsgs;
6604 }
6605 return res;
6606}

References inboxcount2(), and alias_mailbox_mapping::mailbox.

Referenced by append_vmu_info_astman(), ast_app_inboxcount(), forward_message(), handle_voicemail_show_users(), leave_voicemail(), and msg_create_from_file().

◆ inboxcount2()

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

6529{
6530 char tmp[256];
6531 char *context;
6532
6533 /* If no mailbox, return immediately */
6534 if (ast_strlen_zero(mailbox)) {
6535 return 0;
6536 }
6537
6538 if (newmsgs) {
6539 *newmsgs = 0;
6540 }
6541 if (oldmsgs) {
6542 *oldmsgs = 0;
6543 }
6544 if (urgentmsgs) {
6545 *urgentmsgs = 0;
6546 }
6547
6548 if (strchr(mailbox, ',')) {
6549 int tmpnew, tmpold, tmpurgent;
6550 char *mb, *cur;
6551
6552 ast_copy_string(tmp, mailbox, sizeof(tmp));
6553 mb = tmp;
6554 while ((cur = strsep(&mb, ", "))) {
6555 if (!ast_strlen_zero(cur)) {
6556 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) {
6557 return -1;
6558 } else {
6559 if (newmsgs) {
6560 *newmsgs += tmpnew;
6561 }
6562 if (oldmsgs) {
6563 *oldmsgs += tmpold;
6564 }
6565 if (urgentmsgs) {
6566 *urgentmsgs += tmpurgent;
6567 }
6568 }
6569 }
6570 }
6571 return 0;
6572 }
6573
6574 ast_copy_string(tmp, mailbox, sizeof(tmp));
6575
6576 if ((context = strchr(tmp, '@'))) {
6577 *context++ = '\0';
6578 } else {
6579 context = "default";
6580 }
6581
6582 if (newmsgs) {
6583 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
6584 }
6585 if (oldmsgs) {
6586 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
6587 }
6588 if (urgentmsgs) {
6589 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
6590 }
6591
6592 return 0;
6593}

References __has_voicemail(), ast_copy_string(), ast_strlen_zero(), inboxcount2(), alias_mailbox_mapping::mailbox, NULL, and strsep().

Referenced by append_mailbox(), ast_app_inboxcount2(), inboxcount(), inboxcount2(), poll_subscribed_mailbox(), and run_externnotify().

◆ inprocess_cmp_fn()

static int inprocess_cmp_fn ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1312 of file app_voicemail.c.

1313{
1314 struct inprocess *i = obj, *j = arg;
1315 if (strcmp(i->mailbox, j->mailbox)) {
1316 return 0;
1317 }
1318 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
1319}
@ CMP_MATCH
Definition astobj2.h:1027
char mailbox[0]

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

Referenced by load_module().

◆ inprocess_count()

static int inprocess_count ( const char *  context,
const char *  mailbox,
int  delta 
)
static

Definition at line 1321 of file app_voicemail.c.

1322{
1323 int context_len = strlen(context) + 1;
1324 int mailbox_len = strlen(mailbox) + 1;
1325 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + context_len + mailbox_len);
1326 arg->context = arg->mailbox + mailbox_len;
1327 ast_copy_string(arg->mailbox, mailbox, mailbox_len); /* SAFE */
1328 ast_copy_string(arg->context, context, context_len); /* SAFE */
1330 if ((i = ao2_find(inprocess_container, arg, 0))) {
1331 int ret = ast_atomic_fetchadd_int(&i->count, delta);
1333 ao2_ref(i, -1);
1334 return ret;
1335 }
1336 if (delta < 0) {
1337 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
1338 }
1339 if (!(i = ao2_alloc(sizeof(*i) + context_len + mailbox_len, NULL))) {
1341 return 0;
1342 }
1343 i->context = i->mailbox + mailbox_len;
1344 ast_copy_string(i->mailbox, mailbox, mailbox_len); /* SAFE */
1345 ast_copy_string(i->context, context, context_len); /* SAFE */
1346 i->count = delta;
1349 ao2_ref(i, -1);
1350 return 0;
1351}
struct ao2_container * inprocess_container
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717

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

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

◆ inprocess_hash_fn()

static int inprocess_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 1306 of file app_voicemail.c.

1307{
1308 const struct inprocess *i = obj;
1309 return atoi(i->mailbox);
1310}

References inprocess::mailbox.

Referenced by load_module().

◆ invent_message()

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

Definition at line 6089 of file app_voicemail.c.

6090{
6091 int res;
6092 char fn[PATH_MAX];
6093 char dest[PATH_MAX];
6094
6095 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
6096
6097 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
6098 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
6099 return -1;
6100 }
6101
6102 RETRIEVE(fn, -1, ext, context);
6103 if (ast_fileexists(fn, NULL, NULL) > 0) {
6104 res = ast_stream_and_wait(chan, fn, ecodes);
6105 if (res) {
6106 DISPOSE(fn, -1);
6107 return res;
6108 }
6109 } else {
6110 /* Dispose just in case */
6111 DISPOSE(fn, -1);
6112 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
6113 if (res)
6114 return res;
6115 res = ast_say_digit_str(chan, ext, ecodes, ast_channel_language(chan));
6116 if (res)
6117 return res;
6118 }
6119 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
6120 return res;
6121}

References ast_channel_language(), ast_fileexists(), ast_log, AST_LOG_WARNING, ast_say_digit_str(), ast_stream_and_wait(), create_dirpath(), DISPOSE, ext, NULL, PATH_MAX, RETRIEVE, and VM_SPOOL_DIR.

Referenced by leave_voicemail().

◆ is_valid_dtmf()

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

1913{
1914 int i;
1915 char *local_key = ast_strdupa(key);
1916
1917 for (i = 0; i < strlen(key); ++i) {
1918 if (!strchr(VALID_DTMF, *local_key)) {
1919 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1920 return 0;
1921 }
1922 local_key++;
1923 }
1924 return 1;
1925}
#define VALID_DTMF

References ast_log, AST_LOG_WARNING, ast_strdupa, and VALID_DTMF.

Referenced by actual_load_config().

◆ last_message_index()

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

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

References ast_debug, and MAXMSGLIMIT.

◆ leave_voicemail()

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

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

References ast_answer(), ast_callerid_merge(), ast_canmatch_extension(), ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_redirecting(), ast_channel_unlock, ast_check_realtime(), ast_copy_string(), ast_debug, ast_destroy_realtime(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log, AST_LOG_ERROR, AST_LOG_NOTICE, AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_set_flag, AST_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_strlen_zero(), ast_test_flag, ast_trace, ast_unlock_path(), ast_update_realtime(), ast_verb, ast_waitstream(), vm_state::context, ast_vm_user::context, copy_message(), COUNT, create_dirpath(), DISPOSE, errno, ast_vm_user::exit, ext, find_user(), vm_state::fn, free_user(), generate_msg_id(), get_date(), ast_party_caller::id, inboxcount(), inprocess_count(), INTRO, invent_message(), LAST_MSG_INDEX, LOG_ERROR, LOG_WARNING, ast_vm_user::mailbox, make_file(), ast_vm_user::maxmsg, ast_vm_user::maxsecs, ast_vm_user::minsecs, MSG_ID_LEN, my_umask, name, vm_state::newmessages, notify_new_message(), NULL, ast_party_id::number, OPERATOR_EXIT, OPT_BUSY_GREETING, OPT_DTMFEXIT, OPT_MESSAGE_PRIORITY, OPT_MESSAGE_Urgent, OPT_SILENT, OPT_SILENT_IF_GREET, OPT_UNAVAIL_GREETING, options, PATH_MAX, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), play_record_review(), priority, RETRIEVE, S_COR, S_OR, SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, SENTINEL, STORE, ast_party_number::str, strsep(), transfer(), ast_party_number::valid, vm_lock_path(), VM_OPERATOR, VM_SPOOL_DIR, vmfmts, VOICEMAIL_DIR_MODE, and VOICEMAIL_FILE_MODE.

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

◆ load_aliases()

static void load_aliases ( struct ast_config cfg)
static

Definition at line 14763 of file app_voicemail.c.

14764{
14765 struct ast_variable *var;
14766
14768 return;
14769 }
14771 while (var) {
14772 struct alias_mailbox_mapping *mapping = alias_mailbox_mapping_create(var->name, var->value);
14773 if (mapping) {
14776 ao2_ref(mapping, -1);
14777 }
14778 var = var->next;
14779 }
14780}
static struct alias_mailbox_mapping * alias_mailbox_mapping_create(const char *alias, const char *mailbox)
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213

References alias_mailbox_mapping_create(), alias_mailbox_mappings, aliasescontext, ao2_link, ao2_ref, ast_strlen_zero(), ast_variable_browse(), mailbox_alias_mappings, and var.

Referenced by actual_load_config().

◆ load_config()

static int load_config ( int  reload)
static

Definition at line 14731 of file app_voicemail.c.

14732{
14733 return load_config_force(reload, 0);
14734}
static int load_config_force(int reload, int force)
Reload voicemail.conf.
static int reload(void)

References load_config_force(), and reload().

◆ load_config_force()

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

14703{
14704 struct ast_config *cfg;
14705 struct ast_flags config_flags = { reload && !force ? CONFIG_FLAG_FILEUNCHANGED : 0 };
14706 int res;
14707
14708 ast_unload_realtime("voicemail");
14709 ast_unload_realtime("voicemail_data");
14710
14711 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14713 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
14714 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14715 return 0;
14716 }
14717 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
14718 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14719 return 0;
14720 } else {
14722 }
14723
14724 res = actual_load_config(reload, cfg);
14725
14726 ast_config_destroy(cfg);
14727
14728 return res;
14729}
static int actual_load_config(int reload, struct ast_config *cfg)
#define VOICEMAIL_CONFIG
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_FLAG_FILEUNCHANGED

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

Referenced by load_config().

◆ load_module()

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

16249{
16250 int res;
16251 my_umask = umask(0);
16252 umask(my_umask);
16253
16256 if (!inprocess_container) {
16258 }
16259
16261 alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
16263 ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");
16266 }
16267 res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
16268 if (res) {
16269 ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");
16273 }
16274
16276 mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
16278 ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");
16280 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16283 }
16284 res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
16285 if (res) {
16286 ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");
16288 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16292 }
16293
16294 /* compute the location of the voicemail spool directory */
16295 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
16296
16297 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
16298 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
16299 }
16300
16301 if ((res = load_config(0))) {
16302 unload_module();
16304 }
16305
16319#ifdef TEST_FRAMEWORK
16320 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
16321 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
16322 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
16323 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
16324 res |= AST_TEST_REGISTER(test_voicemail_load_config);
16325 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
16326#endif
16327
16328 if (res) {
16329 ast_log(LOG_ERROR, "Failure registering applications, functions or tests\n");
16330 unload_module();
16332 }
16333
16334 /* ast_vm_register may return DECLINE if another module registered for vm */
16335 res = ast_vm_register(&vm_table);
16336 if (res) {
16337 ast_log(LOG_ERROR, "Failure registering as a voicemail provider\n");
16338 unload_module();
16340 }
16341
16342 /* ast_vm_greeter_register may return DECLINE if another module registered as a greeter */
16344 if (res) {
16345 ast_log(LOG_ERROR, "Failure registering as a greeter provider\n");
16346 unload_module();
16348 }
16349
16351
16352#ifdef TEST_FRAMEWORK
16353 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16354#endif
16355
16356 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
16357 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
16358
16360}
static int manager_voicemail_refresh(struct mansession *s, const struct message *m)
static int inprocess_hash_fn(const void *obj, const int flags)
static struct ast_custom_function vm_info_acf
static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
Manager list voicemail users command.
static const struct ast_vm_functions vm_table
static int vm_execmain(struct ast_channel *chan, const char *data)
#define MAPPING_BUCKETS
static int vmauthenticate(struct ast_channel *chan, const char *data)
static int vm_exec(struct ast_channel *chan, const char *data)
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 vm_playmsgexec(struct ast_channel *chan, const char *data)
static char * voicemail_app
static char * playmsg_app
static const struct ast_vm_greeter_functions vm_greeter_table
static int vmsayname_exec(struct ast_channel *chan, const char *data)
static int manager_voicemail_remove(struct mansession *s, const struct message *m)
static void print_mappings(void *v_obj, void *where, ao2_prnt_fn *prnt)
static struct ast_cli_entry cli_voicemail[]
static int manager_get_mailbox_summary(struct mansession *s, const struct message *m)
static char * sayname_app
static int inprocess_cmp_fn(void *obj, void *arg, int flags)
static int unload_module(void)
static int manager_status_voicemail_user(struct mansession *s, const struct message *m)
static char * vmauthenticate_app
static char * voicemailmain_app
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
#define ao2_cleanup(obj)
Definition astobj2.h:1934
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.
#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
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
#define ast_vm_register(vm_table)
See __ast_vm_register()
#define ast_vm_greeter_register(vm_table)
See __ast_vm_greeter_register()
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
#define EVENT_FLAG_CALL
Definition manager.h:76
#define EVENT_FLAG_USER
Definition manager.h:81
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
const char * ast_config_AST_SPOOL_DIR
Definition options.c:155
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1563
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_TEST_REGISTER(cb)
Definition test.h:127

References alias_mailbox_mappings, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_hash, ao2_container_register(), ao2_container_unregister(), ARRAY_LEN, ast_cli_register_multiple, ast_config_AST_SPOOL_DIR, ast_custom_function_register, ast_log, AST_LOG_WARNING, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_realtime_require_field(), ast_register_application_xml, ast_taskprocessor_get(), AST_TEST_REGISTER, ast_vm_greeter_register, ast_vm_register, cli_voicemail, EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, EVENT_FLAG_USER, inprocess_cmp_fn(), inprocess_container, inprocess_hash_fn(), load_config(), LOG_ERROR, mailbox_alias_mappings, manager_get_mailbox_summary(), manager_list_voicemail_users(), manager_status_voicemail_user(), manager_voicemail_forward(), manager_voicemail_move(), manager_voicemail_refresh(), manager_voicemail_remove(), MAPPING_BUCKETS, mwi_subscription_tps, my_umask, NULL, playmsg_app, print_mappings(), RQ_CHAR, RQ_UINTEGER3, sayname_app, SENTINEL, unload_module(), vm_exec(), vm_execmain(), vm_greeter_table, vm_info_acf, vm_playmsgexec(), VM_SPOOL_DIR, vm_table, vmauthenticate(), vmauthenticate_app, vmsayname_exec(), voicemail_app, and voicemailmain_app.

◆ load_users()

static void load_users ( struct ast_config cfg)
static

Definition at line 14817 of file app_voicemail.c.

14818{
14819 struct ast_variable *var;
14820 char *cat = NULL;
14821
14822 while ((cat = ast_category_browse(cfg, cat))) {
14823 if (strcasecmp(cat, "general") == 0
14824 || strcasecmp(cat, aliasescontext) == 0
14825 || strcasecmp(cat, "zonemessages") == 0) {
14826 continue;
14827 }
14828
14829 var = ast_variable_browse(cfg, cat);
14830 while (var) {
14831 append_mailbox(cat, var->name, var->value);
14832 var = var->next;
14833 }
14834 }
14835}
static int append_mailbox(const char *context, const char *box, const char *data)
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324

References aliasescontext, append_mailbox(), ast_category_browse(), ast_variable_browse(), NULL, and var.

◆ load_zonemessages()

static void load_zonemessages ( struct ast_config cfg)
static

Definition at line 14782 of file app_voicemail.c.

14783{
14784 struct ast_variable *var;
14785
14786 var = ast_variable_browse(cfg, "zonemessages");
14787 while (var) {
14788 if (var->value) {
14789 struct vm_zone *z;
14790 char *msg_format, *tzone;
14791 char storage[strlen(var->value) + 1];
14792
14793 z = ast_malloc(sizeof(*z));
14794 if (!z) {
14795 return;
14796 }
14797
14798 strcpy(storage, var->value); /* safe */
14799 msg_format = storage;
14800 tzone = strsep(&msg_format, "|,");
14801 if (msg_format) {
14802 ast_copy_string(z->name, var->name, sizeof(z->name));
14803 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
14808 } else {
14809 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
14810 ast_free(z);
14811 }
14812 }
14813 var = var->next;
14814 }
14815}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191

References ast_copy_string(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log, AST_LOG_WARNING, ast_malloc, ast_variable_browse(), vm_zone::list, vm_zone::msg_format, vm_zone::name, strsep(), vm_zone::timezone, and var.

Referenced by actual_load_config().

◆ make_dir()

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

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

Parameters
destThe variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
lenThe length of the path string that was written out.
context
ext
folder

The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns
zero on success, -1 on error.

Definition at line 2190 of file app_voicemail.c.

2191{
2192 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
2193}

References ext, len(), and VM_SPOOL_DIR.

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

◆ make_email_file()

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_id

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

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

References add_email_attachment(), ast_channel_priority(), ast_channel_unref, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, ast_dummy_channel_alloc, ast_free, ast_localtime(), ast_log, AST_LOG_WARNING, ast_random(), ast_str_buffer(), ast_str_create, ast_str_encode_mime(), ast_str_quote(), ast_str_set(), ast_str_substitute_variables(), ast_strdupa, ast_strftime(), ast_strftime_locale(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), check_mime(), CONFIG_FLAG_NOCACHE, ast_channel::context, ast_vm_user::context, ast_vm_user::email, email, ast_vm_user::emailbody, emailbody, emaildateformat, ast_vm_user::emailsubject, emailsubject, ENDL, ast_vm_user::fromstring, fromstring, ast_vm_user::fullname, globalflags, ast_vm_user::locale, ast_vm_user::mailbox, make_dir(), make_file(), MAXHOSTNAMELEN, NULL, prep_email_sub_vars(), S_OR, strip_control_and_high(), strsep(), valid_config(), VM_PBXSKIP, and vmu_tm().

Referenced by sendmail().

◆ make_file()

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

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

Parameters
destThe variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
lenThe length of the path string that was written out.
dir
num

The path is constructed as VM_SPOOL_DIRcontext/ext/folder

Returns
zero on success, -1 on error.

Definition at line 2207 of file app_voicemail.c.

2208{
2209 return snprintf(dest, len, "%s/msg%04d", dir, num);
2210}

References len().

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

◆ manager_get_mailbox_summary()

static int manager_get_mailbox_summary ( struct mansession s,
const struct message m 
)
static

Definition at line 14476 of file app_voicemail.c.

14477{
14478 struct ast_vm_user *vmu = NULL;
14479 const char *id = astman_get_header(m, "ActionID");
14480 char actionid[128];
14481 struct ast_vm_user svm;
14482
14483 const char *context = astman_get_header(m, "Context");
14484 const char *mailbox = astman_get_header(m, "Mailbox");
14485
14487 astman_send_error(s, m, "Need 'Context' and 'Mailbox' parameters.");
14488 return 0;
14489 }
14490
14491 actionid[0] = '\0';
14492 if (!ast_strlen_zero(id)) {
14493 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14494 }
14495
14496 /* find user */
14497 memset(&svm, 0, sizeof(svm));
14498 vmu = find_user(&svm, context, mailbox);
14499 if (!vmu) {
14500 /* could not find it */
14501 astman_send_ack(s, m, "There is no voicemail user matching the given user.");
14502 return 0;
14503 }
14504
14505 /* Append the mailbox details */
14506 if (!append_vmbox_info_astman(s, m, vmu, "VoicemailBoxDetail", actionid)) {
14507 astman_send_error(s, m, "Unable to get mailbox info for the given user.");
14508 }
14509
14510 free_user(vmu);
14511 return 0;
14512}
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.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:2000
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2032
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1661

References append_vmbox_info_astman(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_vm_user::context, find_user(), free_user(), ast_vm_user::mailbox, and NULL.

Referenced by load_module().

◆ manager_list_voicemail_users()

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

Manager list voicemail users command.

Definition at line 14435 of file app_voicemail.c.

14436{
14437 struct ast_vm_user *vmu = NULL;
14438 const char *id = astman_get_header(m, "ActionID");
14439 char actionid[128];
14440 int num_users = 0;
14441 int ret;
14442
14443 actionid[0] = '\0';
14444 if (!ast_strlen_zero(id)) {
14445 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14446 }
14447
14449
14450 if (AST_LIST_EMPTY(&users)) {
14451 astman_send_ack(s, m, "There are no voicemail users currently defined.");
14453 return RESULT_SUCCESS;
14454 }
14455
14456 astman_send_listack(s, m, "Voicemail user list will follow", "start");
14457
14458 AST_LIST_TRAVERSE(&users, vmu, list) {
14459 /* append vmu info event */
14460 ret = append_vmu_info_astman(s, vmu, "VoicemailUserEntry", actionid);
14461 if(ret == 0) {
14462 ast_log(LOG_ERROR, "Could not append voicemail user info.");
14463 continue;
14464 }
14465 ++num_users;
14466 }
14467
14468 astman_send_list_complete_start(s, m, "VoicemailUserEntryComplete", num_users);
14470
14472
14473 return RESULT_SUCCESS;
14474}
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.
#define RESULT_SUCCESS
Definition cli.h:40

References append_vmu_info_astman(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_vm_user::list, LOG_ERROR, NULL, and RESULT_SUCCESS.

Referenced by load_module().

◆ manager_match_mailbox()

static int manager_match_mailbox ( struct ast_mwi_state mwi_state,
void *  data 
)
static

Definition at line 14351 of file app_voicemail.c.

14352{
14353 const char *context = astman_get_header(data, "Context");
14354 const char *mailbox = astman_get_header(data, "Mailbox");
14355 const char *at;
14356
14357 if (!ast_strlen_zero(mwi_state->uniqueid)) {
14358 if (
14359 /* First case: everything matches */
14360 (ast_strlen_zero(context) && ast_strlen_zero(mailbox)) ||
14361 /* Second case: match the mailbox only */
14362 (ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
14363 (at = strchr(mwi_state->uniqueid, '@')) &&
14364 strncmp(mailbox, mwi_state->uniqueid, at - mwi_state->uniqueid) == 0) ||
14365 /* Third case: match the context only */
14366 (!ast_strlen_zero(context) && ast_strlen_zero(mailbox) &&
14367 (at = strchr(mwi_state->uniqueid, '@')) &&
14368 strcmp(context, at + 1) == 0) ||
14369 /* Final case: match an exact specified mailbox */
14370 (!ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
14371 (at = strchr(mwi_state->uniqueid, '@')) &&
14372 strncmp(mailbox, mwi_state->uniqueid, at - mwi_state->uniqueid) == 0 &&
14373 strcmp(context, at + 1) == 0)
14374 ) {
14375 poll_subscribed_mailbox(mwi_state, NULL);
14376 }
14377 }
14378
14379 return 0;
14380}
static int poll_subscribed_mailbox(struct ast_mwi_state *mwi_state, void *data)
const ast_string_field uniqueid
Definition mwi.h:458

References ast_strlen_zero(), astman_get_header(), NULL, poll_subscribed_mailbox(), and ast_mwi_state::uniqueid.

Referenced by manager_voicemail_refresh().

◆ manager_status_voicemail_user()

static int manager_status_voicemail_user ( struct mansession s,
const struct message m 
)
static

Definition at line 14389 of file app_voicemail.c.

14390{
14391 struct ast_vm_user *vmu = NULL;
14392 const char *id = astman_get_header(m, "ActionID");
14393 char actionid[128];
14394 struct ast_vm_user svm;
14395 int ret;
14396
14397 const char *context = astman_get_header(m, "Context");
14398 const char *mailbox = astman_get_header(m, "Mailbox");
14399
14401 astman_send_error(s, m, "Need 'Context' and 'Mailbox' parameters.");
14402 return RESULT_SUCCESS;
14403 }
14404
14405 actionid[0] = '\0';
14406 if (!ast_strlen_zero(id)) {
14407 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14408 }
14409
14410 /* find user */
14411 memset(&svm, 0, sizeof(svm));
14412 vmu = find_user(&svm, context, mailbox);
14413 if (!vmu) {
14414 /* could not find it */
14415 astman_send_ack(s, m, "There is no voicemail user of the given info.");
14416 return RESULT_SUCCESS;
14417 }
14418
14419 astman_send_listack(s, m, "Voicemail user detail will follow", "start");
14420
14421 /* append vmu info event */
14422 ret = append_vmu_info_astman(s, vmu, "VoicemailUserDetail", actionid);
14423 free_user(vmu);
14424 if(ret == 0) {
14425 ast_log(LOG_ERROR, "Could not append voicemail user info.");
14426 }
14427
14428 astman_send_list_complete_start(s, m, "VoicemailUserDetailComplete", 1);
14430
14431 return RESULT_SUCCESS;
14432}

References append_vmu_info_astman(), ast_log, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_vm_user::context, find_user(), free_user(), LOG_ERROR, ast_vm_user::mailbox, NULL, and RESULT_SUCCESS.

Referenced by load_module().

◆ manager_voicemail_forward()

static int manager_voicemail_forward ( struct mansession s,
const struct message m 
)
static

Definition at line 14585 of file app_voicemail.c.

14586{
14587 const char *from_mailbox = astman_get_header(m, "Mailbox");
14588 const char *from_context = astman_get_header(m, "Context");
14589 const char *from_folder = astman_get_header(m, "Folder");
14590 const char *id[] = { astman_get_header(m, "ID") };
14591 const char *to_mailbox = astman_get_header(m, "ToMailbox");
14592 const char *to_context = astman_get_header(m, "ToContext");
14593 const char *to_folder = astman_get_header(m, "ToFolder");
14594
14595 if (ast_strlen_zero(from_mailbox)) {
14596 astman_send_error(s, m, "Mailbox not specified, required");
14597 return 0;
14598 }
14599 if (ast_strlen_zero(from_context)) {
14600 astman_send_error(s, m, "Context not specified, required");
14601 return 0;
14602 }
14603 if (ast_strlen_zero(from_folder)) {
14604 astman_send_error(s, m, "Folder not specified, required");
14605 return 0;
14606 }
14607 if (ast_strlen_zero(id[0])) {
14608 astman_send_error(s, m, "ID not specified, required");
14609 return 0;
14610 }
14611 if (ast_strlen_zero(to_mailbox)) {
14612 astman_send_error(s, m, "ToMailbox not specified, required");
14613 return 0;
14614 }
14615 if (ast_strlen_zero(to_context)) {
14616 astman_send_error(s, m, "ToContext not specified, required");
14617 return 0;
14618 }
14619 if (ast_strlen_zero(to_folder)) {
14620 astman_send_error(s, m, "ToFolder not specified, required");
14621 return 0;
14622 }
14623
14624 if (vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1, id, 0)) {
14625 astman_send_ack(s, m, "Message forward failed\n");
14626 } else {
14627 astman_send_ack(s, m, "Message forward successful\n");
14628 }
14629
14630 return 0;
14631}

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and vm_msg_forward().

Referenced by load_module().

◆ manager_voicemail_move()

static int manager_voicemail_move ( struct mansession s,
const struct message m 
)
static

Definition at line 14514 of file app_voicemail.c.

14515{
14516 const char *mailbox = astman_get_header(m, "Mailbox");
14517 const char *context = astman_get_header(m, "Context");
14518 const char *from_folder = astman_get_header(m, "Folder");
14519 const char *id[] = { astman_get_header(m, "ID") };
14520 const char *to_folder = astman_get_header(m, "ToFolder");
14521
14522 if (ast_strlen_zero(mailbox)) {
14523 astman_send_error(s, m, "Mailbox not specified, required");
14524 return 0;
14525 }
14526 if (ast_strlen_zero(context)) {
14527 astman_send_error(s, m, "Context not specified, required");
14528 return 0;
14529 }
14530 if (ast_strlen_zero(from_folder)) {
14531 astman_send_error(s, m, "Folder not specified, required");
14532 return 0;
14533 }
14534 if (ast_strlen_zero(id[0])) {
14535 astman_send_error(s, m, "ID not specified, required");
14536 return 0;
14537 }
14538 if (ast_strlen_zero(to_folder)) {
14539 astman_send_error(s, m, "ToFolder not specified, required");
14540 return 0;
14541 }
14542
14543 if (vm_msg_move(mailbox, context, 1, from_folder, id, to_folder)) {
14544 astman_send_ack(s, m, "Message move failed\n");
14545 } else {
14546 astman_send_ack(s, m, "Message move successful\n");
14547 }
14548
14549 return 0;
14550}
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)

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_vm_user::context, ast_vm_user::mailbox, and vm_msg_move().

Referenced by load_module().

◆ manager_voicemail_refresh()

static int manager_voicemail_refresh ( struct mansession s,
const struct message m 
)
static

Definition at line 14382 of file app_voicemail.c.

14383{
14385 astman_send_ack(s, m, "Refresh sent");
14386 return RESULT_SUCCESS;
14387}
static int manager_match_mailbox(struct ast_mwi_state *mwi_state, void *data)

References ast_mwi_state_callback_all(), astman_send_ack(), manager_match_mailbox(), and RESULT_SUCCESS.

Referenced by load_module().

◆ manager_voicemail_remove()

static int manager_voicemail_remove ( struct mansession s,
const struct message m 
)
static

Definition at line 14552 of file app_voicemail.c.

14553{
14554 const char *mailbox = astman_get_header(m, "Mailbox");
14555 const char *context = astman_get_header(m, "Context");
14556 const char *folder = astman_get_header(m, "Folder");
14557 const char *id[] = { astman_get_header(m, "ID") };
14558
14559 if (ast_strlen_zero(mailbox)) {
14560 astman_send_error(s, m, "Mailbox not specified, required");
14561 return 0;
14562 }
14563 if (ast_strlen_zero(context)) {
14564 astman_send_error(s, m, "Context not specified, required");
14565 return 0;
14566 }
14567 if (ast_strlen_zero(folder)) {
14568 astman_send_error(s, m, "Folder not specified, required");
14569 return 0;
14570 }
14571 if (ast_strlen_zero(id[0])) {
14572 astman_send_error(s, m, "ID not specified, required");
14573 return 0;
14574 }
14575
14576 if (vm_msg_remove(mailbox, context, 1, folder, id)) {
14577 astman_send_ack(s, m, "Message remove failed\n");
14578 } else {
14579 astman_send_ack(s, m, "Message remove successful\n");
14580 }
14581
14582 return 0;
14583}
static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[])

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_vm_user::context, ast_vm_user::mailbox, and vm_msg_remove().

Referenced by load_module().

◆ mb_poll_thread()

static void * mb_poll_thread ( void *  data)
static

Definition at line 14019 of file app_voicemail.c.

14020{
14021 while (poll_thread_run) {
14022 struct timespec ts = { 0, };
14023 struct timeval wait;
14024
14026
14027 if (!poll_thread_run) {
14028 break;
14029 }
14030
14032 ts.tv_sec = wait.tv_sec;
14033 ts.tv_nsec = wait.tv_usec * 1000;
14034
14038 }
14039
14040 return NULL;
14041}
static ast_mutex_t poll_lock
static unsigned char poll_thread_run
static ast_cond_t poll_cond
#define ast_cond_timedwait(cond, mutex, time)
Definition lock.h:213
void ast_mwi_state_callback_subscribed(on_mwi_state handler, void *data)
For each managed mailbox that has a subscriber call the given handler.
Definition mwi.c:348
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2280

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_mwi_state_callback_subscribed(), ast_samp2tv(), ast_tvadd(), ast_tvnow(), NULL, poll_cond, poll_freq, poll_lock, poll_subscribed_mailbox(), and poll_thread_run.

Referenced by start_poll_thread().

◆ mbox()

static const char * mbox ( struct ast_vm_user vmu,
int  id 
)
static

Definition at line 2233 of file app_voicemail.c.

2234{
2235#ifdef IMAP_STORAGE
2236 if (vmu && id == 0) {
2237 return vmu->imapfolder;
2238 }
2239#endif
2240 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
2241}

References ARRAY_LEN, id, and mailbox_folders.

Referenced by adsi_load_vmail(), copy_message(), get_folder(), get_folder_ja(), notify_new_message(), open_mailbox(), save_to_folder(), vm_execmain(), and vm_index_to_foldername().

◆ message_range_and_existence_check()

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

17227{
17228 int i;
17229 int res = 0;
17230 for (i = 0; i < num_msgs; ++i) {
17231 const char *msg_id = msg_ids[i];
17232 int found = 0;
17233 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17234 const char *other_msg_id;
17235 char filename[PATH_MAX];
17236 struct ast_config *msg_cfg;
17237 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17238
17239 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
17240 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
17241 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
17242 msg_cfg = ast_config_load(filename, config_flags);
17243 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17244 DISPOSE(vms->curdir, vms->curmsg);
17245 res = -1;
17246 goto done;
17247 }
17248
17249 other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
17250
17251 if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17252 /* Message found. We can get out of this inner loop
17253 * and move on to the next message to find
17254 */
17255 found = 1;
17256 msg_nums[i] = vms->curmsg;
17257 ast_config_destroy(msg_cfg);
17258 DISPOSE(vms->curdir, vms->curmsg);
17259 break;
17260 }
17261 ast_config_destroy(msg_cfg);
17262 DISPOSE(vms->curdir, vms->curmsg);
17263 }
17264 if (!found) {
17265 /* If we can't find one of the message IDs requested, then OH NO! */
17266 res = -1;
17267 goto done;
17268 }
17269 }
17270
17271done:
17272 return res;
17273}

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

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

◆ messagecount()

static int messagecount ( const char *  mailbox_id,
const char *  folder 
)
static

Definition at line 6422 of file app_voicemail.c.

6423{
6424 char *context;
6425 char *mailbox;
6426
6427 if (ast_strlen_zero(mailbox_id)
6428 || separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
6429 return 0;
6430 }
6431
6432 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
6433}

References __has_voicemail(), ast_strdupa, ast_strlen_zero(), and separate_mailbox().

Referenced by acf_vm_info(), and ast_app_messagecount().

◆ move_message_from_mailbox()

static int move_message_from_mailbox ( struct ast_cli_args a)
static

Definition at line 12079 of file app_voicemail.c.

12080{
12081 const char *mailbox = a->argv[2];
12082 const char *context = a->argv[3];
12083 const char *from_folder = a->argv[4];
12084 const char *id[] = { a->argv[5] };
12085 const char *to_folder = a->argv[6];
12086 int ret = vm_msg_move(mailbox, context, 1, from_folder, id, to_folder);
12087 if (ret) {
12088 ast_cli(a->fd, "Error moving message %s from mailbox %s@%s %s to %s\n",
12089 id[0], mailbox, context, from_folder, to_folder);
12090 } else {
12091 ast_cli(a->fd, "Moved message %s from mailbox %s@%s %s to %s\n",
12092 id[0], mailbox, context, from_folder, to_folder);
12093 }
12094 return ret;
12095}

References a, ast_cli(), and vm_msg_move().

Referenced by handle_voicemail_move_message().

◆ msg_create_from_file()

static int msg_create_from_file ( struct ast_vm_recording_data recdata)
static

Definition at line 6689 of file app_voicemail.c.

6690{
6691 /* voicemail recipient structure */
6692 struct ast_vm_user *recipient; /* points to svm once it's been created */
6693 struct ast_vm_user svm; /* struct storing the voicemail recipient */
6694
6695 /* File paths */
6696 char tmpdir[PATH_MAX]; /* directory temp files are stored in */
6697 char tmptxtfile[PATH_MAX]; /* tmp file for voicemail txt file */
6698 char desttxtfile[PATH_MAX]; /* final destination for txt file */
6699 char tmpaudiofile[PATH_MAX]; /* tmp file where audio is stored */
6700 char dir[PATH_MAX]; /* destination for tmp files on completion */
6701 char destination[PATH_MAX]; /* destination with msgXXXX. Basically <dir>/msgXXXX */
6702
6703 /* stuff that only seems to be needed for IMAP */
6704 #ifdef IMAP_STORAGE
6705 struct vm_state *vms = NULL;
6706 char ext_context[256] = "";
6707 int newmsgs = 0;
6708 int oldmsgs = 0;
6709 #endif
6710
6711 /* miscellaneous operational variables */
6712 int res = 0; /* Used to store error codes from functions */
6713 int txtdes /* File descriptor for the text file used to write the voicemail info */;
6714 FILE *txt; /* FILE pointer to text file used to write the voicemail info */
6715 char date[256]; /* string used to hold date of the voicemail (only used for ODBC) */
6716 int msgnum; /* the 4 digit number designated to the voicemail */
6717 int duration = 0; /* Length of the audio being recorded in seconds */
6718 struct ast_filestream *recording_fs; /*used to read the recording to get duration data */
6719
6720 /* We aren't currently doing anything with category, since it comes from a channel variable and
6721 * this function doesn't use channels, but this function could add that as an argument later. */
6722 const char *category = NULL; /* pointless for now */
6723 char msg_id[MSG_ID_LEN];
6724
6725 /* Start by checking to see if the file actually exists... */
6726 if (!(ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL))) {
6727 ast_log(LOG_ERROR, "File: %s not found.\n", recdata->recording_file);
6728 return -1;
6729 }
6730
6731 memset(&svm, 0, sizeof(svm));
6732 if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) {
6733 ast_log(LOG_ERROR, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
6734 return -1;
6735 }
6736
6737 /* determine duration in seconds */
6738 if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
6739 if (!ast_seekstream(recording_fs, 0, SEEK_END)) {
6740 long framelength = ast_tellstream(recording_fs);
6741 int sample_rate = ast_ratestream(recording_fs);
6742 if (sample_rate) {
6743 duration = (int) (framelength / sample_rate);
6744 } else {
6745 ast_log(LOG_ERROR,"Unable to determine sample rate of recording %s\n", recdata->recording_file);
6746 }
6747 }
6748 ast_closestream(recording_fs);
6749 }
6750
6751 /* If the duration was below the minimum duration for the user, let's just drop the whole thing now */
6752 if (duration < recipient->minsecs) {
6753 ast_log(LOG_NOTICE, "Copying recording to voicemail %s@%s skipped because duration was shorter than "
6754 "minmessage of recipient\n", recdata->mailbox, recdata->context);
6755 return -1;
6756 }
6757
6758 /* Note that this number must be dropped back to a net sum of zero before returning from this function */
6759
6760 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), recipient->context, recdata->mailbox, "tmp"))) {
6761 ast_log(LOG_ERROR, "Failed to make directory.\n");
6762 }
6763
6764 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
6765 txtdes = mkstemp(tmptxtfile);
6766 if (txtdes < 0) {
6767 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
6768 /* Something screwed up. Abort. */
6769 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
6770 free_user(recipient);
6771 return -1;
6772 }
6773
6774 /* Store information */
6775 txt = fdopen(txtdes, "w+");
6776 if (txt) {
6777 generate_msg_id(msg_id);
6778 get_date(date, sizeof(date));
6779 fprintf(txt,
6780 ";\n"
6781 "; Message Information file\n"
6782 ";\n"
6783 "[message]\n"
6784 "origmailbox=%s\n"
6785 "context=%s\n"
6786 "exten=%s\n"
6787 "rdnis=Unknown\n"
6788 "priority=%d\n"
6789 "callerchan=%s\n"
6790 "callerid=%s\n"
6791 "origdate=%s\n"
6792 "origtime=%ld\n"
6793 "category=%s\n"
6794 "msg_id=%s\n"
6795 "flag=\n" /* flags not supported in copy from file yet */
6796 "duration=%d\n", /* Don't have any reliable way to get duration of file. */
6797
6798 recdata->mailbox,
6799 S_OR(recdata->call_context, ""),
6800 S_OR(recdata->call_extension, ""),
6801 recdata->call_priority,
6802 S_OR(recdata->call_callerchan, "Unknown"),
6803 S_OR(recdata->call_callerid, "Unknown"),
6804 date, (long) time(NULL),
6805 S_OR(category, ""),
6806 msg_id,
6807 duration);
6808
6809 /* Since we are recording from a file, we shouldn't need to do anything else with
6810 * this txt file */
6811 fclose(txt);
6812
6813 } else {
6814 ast_log(LOG_WARNING, "Error opening text file for output\n");
6815 if (ast_check_realtime("voicemail_data")) {
6816 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
6817 }
6818 free_user(recipient);
6819 return -1;
6820 }
6821
6822 /* At this point, the actual creation of a voicemail message should be finished.
6823 * Now we just need to copy the files being recorded into the receiving folder. */
6824
6825 create_dirpath(dir, sizeof(dir), recipient->context, recipient->mailbox, recdata->folder);
6826
6827#ifdef IMAP_STORAGE
6828 /* make recipient info into an inboxcount friendly string */
6829 snprintf(ext_context, sizeof(ext_context), "%s@%s", recipient->mailbox, recipient->context);
6830
6831 /* Is ext a mailbox? */
6832 /* must open stream for this user to get info! */
6833 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
6834 if (res < 0) {
6835 ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
6836 free_user(recipient);
6837 unlink(tmptxtfile);
6838 return -1;
6839 }
6840 if (!(vms = get_vm_state_by_mailbox(recipient->mailbox, recipient->context, 0))) {
6841 /* It is possible under certain circumstances that inboxcount did not
6842 * create a vm_state when it was needed. This is a catchall which will
6843 * rarely be used.
6844 */
6845 if (!(vms = create_vm_state_from_user(recipient))) {
6846 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
6847 free_user(recipient);
6848 unlink(tmptxtfile);
6849 return -1;
6850 }
6851 }
6852 vms->newmessages++;
6853
6854 /* here is a big difference! We add one to it later */
6855 msgnum = newmsgs + oldmsgs;
6856 ast_debug(3, "Messagecount set to %d\n", msgnum);
6857 snprintf(destination, sizeof(destination), "%simap/msg%s%04d", VM_SPOOL_DIR, recipient->mailbox, msgnum);
6858
6859 /* Check to see if we have enough room in the mailbox. If not, spit out an error and end
6860 * Note that imap_check_limits raises inprocess_count if successful */
6861 if ((res = imap_check_limits(NULL, vms, recipient, msgnum))) {
6862 ast_log(LOG_NOTICE, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
6863 inprocess_count(recipient->mailbox, recipient->context, -1);
6864 free_user(recipient);
6865 unlink(tmptxtfile);
6866 return -1;
6867 }
6868
6869#else
6870
6871 /* Check to see if the mailbox is full for ODBC/File storage */
6872 ast_debug(3, "mailbox = %d : inprocess = %d\n", COUNT(recipient, dir),
6873 inprocess_count(recipient->mailbox, recipient->context, 0));
6874 if (COUNT(recipient, dir) > recipient->maxmsg - inprocess_count(recipient->mailbox, recipient->context, +1)) {
6875 ast_log(AST_LOG_WARNING, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
6876 inprocess_count(recipient->mailbox, recipient->context, -1);
6877 free_user(recipient);
6878 unlink(tmptxtfile);
6879 return -1;
6880 }
6881
6882 msgnum = LAST_MSG_INDEX(dir) + 1;
6883#endif
6884
6885 /* Lock the directory receiving the voicemail since we want it to still exist when we attempt to copy the voicemail.
6886 * We need to unlock it before we return. */
6887 if (vm_lock_path(dir)) {
6888 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6889 /* Delete files */
6890 ast_filedelete(tmptxtfile, NULL);
6891 unlink(tmptxtfile);
6892 free_user(recipient);
6893 return -1;
6894 }
6895
6896 make_file(destination, sizeof(destination), dir, msgnum);
6897
6898 make_file(tmpaudiofile, sizeof(tmpaudiofile), tmpdir, msgnum);
6899
6900 if (ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
6901 ast_log(LOG_ERROR, "Audio file failed to copy to tmp dir. Probably low disk space.\n");
6902
6903 inprocess_count(recipient->mailbox, recipient->context, -1);
6904 ast_unlock_path(dir);
6905 free_user(recipient);
6906 unlink(tmptxtfile);
6907 return -1;
6908 }
6909
6910 /* Alright, try to copy to the destination folder now. */
6911 if (ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
6912 ast_log(LOG_ERROR, "Audio file failed to move to destination directory. Permissions/Overlap?\n");
6913 inprocess_count(recipient->mailbox, recipient->context, -1);
6914 ast_unlock_path(dir);
6915 free_user(recipient);
6916 unlink(tmptxtfile);
6917 return -1;
6918 }
6919
6920 snprintf(desttxtfile, sizeof(desttxtfile), "%s.txt", destination);
6921 rename(tmptxtfile, desttxtfile);
6922
6923 if (chmod(desttxtfile, VOICEMAIL_FILE_MODE) < 0) {
6924 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno));
6925 }
6926
6927
6928 ast_unlock_path(dir);
6929 inprocess_count(recipient->mailbox, recipient->context, -1);
6930
6931 /* If we copied something, we should store it either to ODBC or IMAP if we are using those. The STORE macro allows us
6932 * to do both with one line and is also safe to use with file storage mode. Also, if we are using ODBC, now is a good
6933 * time to create the voicemail database entry. */
6934 if (ast_fileexists(destination, NULL, NULL) > 0) {
6935 struct ast_channel *chan = NULL;
6936 char fmt[80];
6937 char clid[80];
6938 char cidnum[80], cidname[80];
6939 int send_email;
6940
6941 if (ast_check_realtime("voicemail_data")) {
6942 get_date(date, sizeof(date));
6943 ast_store_realtime("voicemail_data",
6944 "origmailbox", recdata->mailbox,
6945 "context", S_OR(recdata->context, ""),
6946 "exten", S_OR(recdata->call_extension, ""),
6947 "priority", recdata->call_priority,
6948 "callerchan", S_OR(recdata->call_callerchan, "Unknown"),
6949 "callerid", S_OR(recdata->call_callerid, "Unknown"),
6950 "origdate", date,
6951 "origtime", time(NULL),
6952 "category", S_OR(category, ""),
6953 "filename", tmptxtfile,
6954 "duration", duration,
6955 SENTINEL);
6956 }
6957
6958 STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
6959
6960 send_email = ast_test_flag(recipient, VM_EMAIL_EXT_RECS);
6961
6962 if (send_email) {
6963 /* Send an email if possible, fall back to just notifications if not. */
6964 ast_copy_string(fmt, recdata->recording_ext, sizeof(fmt));
6965 ast_copy_string(clid, recdata->call_callerid, sizeof(clid));
6966 ast_callerid_split(clid, cidname, sizeof(cidname), cidnum, sizeof(cidnum));
6967
6968 /* recdata->call_callerchan itself no longer exists, so we can't use the real channel. Use a dummy one. */
6969 chan = ast_dummy_channel_alloc();
6970 }
6971 if (chan) {
6972 notify_new_message(chan, recipient, NULL, msgnum, duration, fmt, cidnum, cidname, "");
6973 ast_channel_unref(chan);
6974 } else {
6975 if (send_email) { /* We tried and failed. */
6976 ast_log(LOG_WARNING, "Failed to allocate dummy channel, email will not be sent\n");
6977 }
6978 notify_new_state(recipient);
6979 }
6980 }
6981
6982 free_user(recipient);
6983 unlink(tmptxtfile);
6984 return 0;
6985}
static void notify_new_state(struct ast_vm_user *vmu)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition callerid.c:1292
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition file.c:1104
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition file.c:1094
struct ast_filestream * ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts reading from a file.
Definition file.c:1405
int ast_ratestream(struct ast_filestream *fs)
Return the sample rate of the stream's format.
Definition file.c:1109
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1130
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition mod_format.h:101
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field context
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field mailbox

References ast_callerid_split(), ast_channel_unref, ast_check_realtime(), ast_closestream(), ast_copy_string(), ast_debug, ast_destroy_realtime(), ast_dummy_channel_alloc, ast_filecopy(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_log, AST_LOG_ERROR, AST_LOG_WARNING, ast_ratestream(), ast_readfile(), ast_seekstream(), ast_store_realtime(), ast_tellstream(), ast_test_flag, ast_unlock_path(), ast_vm_recording_data::call_callerchan, ast_vm_recording_data::call_callerid, ast_vm_recording_data::call_context, ast_vm_recording_data::call_extension, ast_vm_recording_data::call_priority, ast_vm_user::context, ast_vm_recording_data::context, COUNT, create_dirpath(), errno, find_user(), ast_vm_recording_data::folder, free_user(), generate_msg_id(), get_date(), inboxcount(), inprocess_count(), LAST_MSG_INDEX, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_vm_user::mailbox, ast_vm_recording_data::mailbox, make_file(), ast_vm_user::maxmsg, MSG_ID_LEN, my_umask, vm_state::newmessages, notify_new_message(), notify_new_state(), NULL, PATH_MAX, ast_vm_recording_data::recording_ext, ast_vm_recording_data::recording_file, S_OR, SENTINEL, STORE, VM_EMAIL_EXT_RECS, vm_lock_path(), VM_SPOOL_DIR, VOICEMAIL_DIR_MODE, and VOICEMAIL_FILE_MODE.

◆ mwi_handle_subscribe()

static void mwi_handle_subscribe ( const char *  id,
struct ast_mwi_subscriber sub 
)
static

Definition at line 14126 of file app_voicemail.c.

14127{
14128 void *data = ast_mwi_subscriber_data(sub);
14129
14130 /* Don't bump data's reference. We'll just use the one returned above */
14132 /* A reference was returned for data when retrieving, so remove it on error */
14133 ao2_ref(data, -1);
14134 }
14135}
static int mwi_handle_subscribe2(void *data)
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
Definition mwi.c:269
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
#define ast_taskprocessor_push(tps, task_exe, datap)

References ao2_ref, ast_mwi_subscriber_data(), ast_taskprocessor_push, mwi_handle_subscribe2(), mwi_subscription_tps, and sub.

◆ mwi_handle_subscribe2()

static int mwi_handle_subscribe2 ( void *  data)
static

Definition at line 14119 of file app_voicemail.c.

14120{
14122 ao2_ref(data, -1);
14123 return 0;
14124}

References ao2_ref, NULL, and poll_subscribed_mailbox().

Referenced by mwi_handle_subscribe().

◆ mwi_handle_unsubscribe()

static void mwi_handle_unsubscribe ( const char *  id,
struct ast_mwi_subscriber sub 
)
static

Definition at line 14108 of file app_voicemail.c.

14109{
14110 void *data = ast_mwi_subscriber_data(sub);
14111
14112 /* Don't bump data's reference. We'll just use the one returned above */
14114 /* A reference was returned for data when retrieving, so remove it on error */
14115 ao2_ref(data, -1);
14116 }
14117}
static int mwi_handle_unsubscribe2(void *data)

References ao2_ref, ast_mwi_subscriber_data(), ast_taskprocessor_push, mwi_handle_unsubscribe2(), mwi_subscription_tps, and sub.

◆ mwi_handle_unsubscribe2()

static int mwi_handle_unsubscribe2 ( void *  data)
static

Definition at line 14089 of file app_voicemail.c.

14090{
14091 struct ast_mwi_state *mwi_state = data;
14092
14093 /*
14094 * Go ahead and clear the implicit MWI publisher here to avoid a leak. If a backing
14095 * configuration is available it'll re-initialize (reset the cached state) on its
14096 * next publish.
14097 */
14099
14100#ifdef IMAP_STORAGE
14101 imap_close_subscribed_mailbox(mwi_state, NULL);
14102#endif
14103
14104 ao2_ref(mwi_state, -1);
14105 return 0;
14106}
The structure that contains MWI state.
Definition mwi.h:455

References ao2_ref, ast_delete_mwi_state_full(), NULL, and ast_mwi_state::uniqueid.

Referenced by mwi_handle_unsubscribe().

◆ notify_new_message()

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

8592{
8593 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
8594 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8595 const char *category;
8596 char *myserveremail = serveremail;
8597
8598 ast_channel_lock(chan);
8599 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
8600 category = ast_strdupa(category);
8601 }
8602 ast_channel_unlock(chan);
8603
8604#ifndef IMAP_STORAGE
8605 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
8606#else
8607 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
8608#endif
8609 make_file(fn, sizeof(fn), todir, msgnum);
8610 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
8611
8612 if (!ast_strlen_zero(vmu->attachfmt)) {
8613 if (strstr(fmt, vmu->attachfmt))
8614 fmt = vmu->attachfmt;
8615 else
8616 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);
8617 }
8618
8619 /* Attach only the first format */
8620 fmt = ast_strdupa(fmt);
8621 stringp = fmt;
8622 strsep(&stringp, "|");
8623
8624 if (!ast_strlen_zero(vmu->serveremail))
8625 myserveremail = vmu->serveremail;
8626
8627 if (!ast_strlen_zero(vmu->email)) {
8628 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
8629 char *msg_id = NULL;
8630#ifdef IMAP_STORAGE
8631 struct ast_config *msg_cfg;
8632 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8633 char filename[PATH_MAX];
8634
8635 snprintf(filename, sizeof(filename), "%s.txt", fn);
8636 msg_cfg = ast_config_load(filename, config_flags);
8637 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8638 msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
8639 ast_config_destroy(msg_cfg);
8640 }
8641#endif
8642
8643 if (attach_user_voicemail)
8644 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
8645
8646 /* XXX possible imap issue, should category be NULL XXX */
8647 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);
8648
8649 if (attach_user_voicemail)
8650 DISPOSE(todir, msgnum);
8651 }
8652
8653 if (!ast_strlen_zero(vmu->pager)) {
8654 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
8655 }
8656
8657 if (ast_test_flag(vmu, VM_DELETE))
8658 DELETE(todir, msgnum, fn, vmu);
8659
8660 /* Leave voicemail for someone */
8661 if (ast_app_has_voicemail(ext_context, NULL))
8662 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
8663
8664 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
8665 run_externnotify(vmu->context, vmu->mailbox, flag);
8666
8667#ifdef IMAP_STORAGE
8668 vm_delete(fn); /* Delete the file, but not the IMAP message */
8669 if (ast_test_flag(vmu, VM_DELETE)) { /* Delete the IMAP message if delete = yes */
8670 vm_imap_delete(NULL, vms->curmsg, vmu);
8671 vms->newmessages--; /* Fix new message count */
8672 }
8673#endif
8674
8675 return 0;
8676}
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)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
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"....
Definition main/app.c:582
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

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

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

◆ notify_new_state()

static void notify_new_state ( struct ast_vm_user vmu)
static

Definition at line 17275 of file app_voicemail.c.

17276{
17277 int new = 0, old = 0, urgent = 0;
17278 char ext_context[1024];
17279
17280 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
17281 run_externnotify(vmu->context, vmu->mailbox, NULL);
17282 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
17283 queue_mwi_event(NULL, ext_context, urgent, new, old);
17284}

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

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

◆ open_mailbox()

static int open_mailbox ( struct vm_state vms,
struct ast_vm_user vmu,
int  box 
)
static

Definition at line 9538 of file app_voicemail.c.

9539{
9540 int count_msg, last_msg;
9541 SCOPE_ENTER(3, "user: %s dir: %s msg: %d box %d\n",
9542 vms->username, vms->curdir, vms->curmsg, box);
9543
9544 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
9545
9546 /* Rename the member vmbox HERE so that we don't try to return before
9547 * we know what's going on.
9548 */
9549 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
9550
9551 /* Faster to make the directory than to check if it exists. */
9552 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
9553
9554 /* traverses directory using readdir (or select query for ODBC) */
9555 count_msg = COUNT(vmu, vms->curdir);
9556 if (count_msg < 0) {
9557 SCOPE_EXIT_RTN_VALUE(count_msg, "msgs: %d\n", count_msg);
9558 } else {
9559 vms->lastmsg = count_msg - 1;
9560 }
9561
9562 if (vm_allocate_dh(vms, vmu, count_msg)) {
9563 SCOPE_EXIT_RTN_VALUE(-1, "failed to allocate dh\n");
9564 }
9565
9566 /*
9567 The following test is needed in case sequencing gets messed up.
9568 There appears to be more than one way to mess up sequence, so
9569 we will not try to find all of the root causes--just fix it when
9570 detected.
9571 */
9572
9573 if (vm_lock_path(vms->curdir)) {
9574 SCOPE_EXIT_LOG_RTN_VALUE(ERROR_LOCK_PATH, AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
9575 }
9576
9577 /* for local storage, checks directory for messages up to MAXMSGLIMIT */
9578 last_msg = LAST_MSG_INDEX(vms->curdir);
9579 ast_unlock_path(vms->curdir);
9580
9581 if (last_msg < -1) {
9582 SCOPE_EXIT_RTN_VALUE(last_msg, "last msg: %d\n", last_msg);
9583 } else if (vms->lastmsg != last_msg) {
9584 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
9585 resequence_mailbox(vmu, vms->curdir, count_msg);
9586 }
9587
9588 SCOPE_EXIT_RTN_VALUE(0, "Done\n");
9589}
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg)
static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
char vmbox[PATH_MAX]

References ast_copy_string(), ast_log, AST_LOG_ERROR, ast_unlock_path(), ast_vm_user::context, COUNT, create_dirpath(), vm_state::curbox, vm_state::curdir, vm_state::curmsg, ERROR_LOCK_PATH, LAST_MSG_INDEX, vm_state::lastmsg, LOG_NOTICE, ast_vm_user::maxmsg, mbox(), resequence_mailbox(), SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, vm_state::username, vm_allocate_dh(), vm_lock_path(), and vm_state::vmbox.

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

◆ play_message()

static int play_message ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms 
)
static

Definition at line 9284 of file app_voicemail.c.

9285{
9286 int res = 0;
9287 char filename[PATH_MAX], *cid;
9288 const char *origtime, *context, *category, *duration, *flag;
9289 struct ast_config *msg_cfg;
9290 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
9291 SCOPE_ENTER(3, "%s: user: %s dir: %s msg: %d\n", ast_channel_name(chan),
9292 vms->username, vms->curdir, vms->curmsg);
9293
9294 vms->starting = 0;
9295 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
9296 adsi_message(chan, vms);
9297 if (!vms->curmsg) {
9298 res = wait_file2(chan, vms, "vm-first"); /* "First" */
9299 } else if (vms->curmsg == vms->lastmsg) {
9300 res = wait_file2(chan, vms, "vm-last"); /* "last" */
9301 }
9302
9303 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
9304 SCOPE_CALL(-1, RETRIEVE, vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
9305 msg_cfg = ast_config_load(filename, config_flags);
9306 if (!valid_config(msg_cfg)) {
9307 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
9308 return 0;
9309 }
9310 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
9311
9312 /* Play the word urgent if we are listening to urgent messages */
9313 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
9314 res = wait_file2(chan, vms, "vm-Urgent"); /* "urgent" */
9315 }
9316
9317 if (!res) {
9318 /* XXX Why are we playing messages above, and then playing the same language-specific stuff here? */
9319 /* POLISH syntax */
9320 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9321 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9322 int ten, one;
9323 char nextmsg[256];
9324 ten = (vms->curmsg + 1) / 10;
9325 one = (vms->curmsg + 1) % 10;
9326
9327 if (vms->curmsg < 20) {
9328 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
9329 res = wait_file2(chan, vms, nextmsg);
9330 } else {
9331 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
9332 res = wait_file2(chan, vms, nextmsg);
9333 if (one > 0) {
9334 if (!res) {
9335 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
9336 res = wait_file2(chan, vms, nextmsg);
9337 }
9338 }
9339 }
9340 }
9341 if (!res)
9342 res = wait_file2(chan, vms, "vm-message");
9343 /* HEBREW syntax */
9344 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
9345 if (!vms->curmsg) {
9346 res = wait_file2(chan, vms, "vm-message");
9347 res = wait_file2(chan, vms, "vm-first");
9348 } else if (vms->curmsg == vms->lastmsg) {
9349 res = wait_file2(chan, vms, "vm-message");
9350 res = wait_file2(chan, vms, "vm-last");
9351 } else {
9352 res = wait_file2(chan, vms, "vm-message");
9353 res = wait_file2(chan, vms, "vm-number");
9354 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9355 }
9356 /* ICELANDIC syntax */
9357 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) {
9358 res = wait_file2(chan, vms, "vm-message");
9359 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9360 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "n");
9361 }
9362 /* VIETNAMESE syntax */
9363 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
9364 if (!vms->curmsg) {
9365 res = wait_file2(chan, vms, "vm-message");
9366 res = wait_file2(chan, vms, "vm-first");
9367 } else if (vms->curmsg == vms->lastmsg) {
9368 res = wait_file2(chan, vms, "vm-message");
9369 res = wait_file2(chan, vms, "vm-last");
9370 } else {
9371 res = wait_file2(chan, vms, "vm-message");
9372 res = wait_file2(chan, vms, "vm-number");
9373 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9374 }
9375 } else {
9376 if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
9377 res = wait_file2(chan, vms, "vm-meddelandet"); /* "message" */
9378 } else { /* DEFAULT syntax */
9379 res = wait_file2(chan, vms, "vm-message");
9380 }
9381 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9382 if (!res) {
9383 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
9384 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9385 }
9386 }
9387 }
9388 }
9389
9390 if (!valid_config(msg_cfg)) {
9391 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
9392 }
9393
9394 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
9395 SCOPE_CALL(-1, DISPOSE, vms->curdir, vms->curmsg);
9396 ast_config_destroy(msg_cfg);
9397 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING, "No origtime?!\n");
9398 }
9399
9400 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
9401 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
9402 category = ast_variable_retrieve(msg_cfg, "message", "category");
9403
9404 context = ast_variable_retrieve(msg_cfg, "message", "context");
9405 if (!res) {
9406 res = play_message_category(chan, category);
9407 }
9408 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
9409 res = play_message_datetime(chan, vmu, origtime, filename);
9410 }
9411 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
9412 res = play_message_callerid(chan, vms, cid, context, 0, 0);
9413 }
9414 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
9415 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
9416 }
9417 /* Allow pressing '1' to skip envelope / callerid */
9418 if (res == '1') {
9419 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
9420 res = 0;
9421 }
9422 ast_config_destroy(msg_cfg);
9423
9424 if (!res) {
9425 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
9426#ifdef IMAP_STORAGE
9427 ast_mutex_lock(&vms->lock);
9428#endif
9429 vms->heard[vms->curmsg] = 1;
9430#ifdef IMAP_STORAGE
9431 ast_mutex_unlock(&vms->lock);
9432 /*IMAP storage stores any prepended message from a forward
9433 * as a separate file from the rest of the message
9434 */
9435 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
9436 wait_file(chan, vms, vms->introfn);
9437 }
9438#endif
9439 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
9440 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
9441 res = 0;
9442 }
9443 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
9444 isprint(res) ? res : '?', isprint(res) ? res : '?');
9445 }
9446 SCOPE_CALL(-1, DISPOSE, vms->curdir, vms->curmsg);
9447 SCOPE_EXIT_RTN_VALUE(res, "Done: RC: %d\n", res);
9448}
static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
static int play_message_category(struct ast_channel *chan, const char *category)
static void adsi_message(struct ast_channel *chan, struct vm_state *vms)

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

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

◆ play_message_by_id()

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

11895{
11896 struct vm_state vms;
11897 struct ast_vm_user *vmu = NULL, vmus;
11898 int res = 0;
11899 int open = 0;
11900 int played = 0;
11901 int i;
11902
11903 memset(&vmus, 0, sizeof(vmus));
11904 memset(&vms, 0, sizeof(vms));
11905
11906 if (!(vmu = find_user(&vmus, context, mailbox))) {
11907 goto play_msg_cleanup;
11908 }
11909
11910 /* Iterate through every folder, find the msg, and play it */
11911 for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
11912 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
11913 vms.lastmsg = -1;
11914
11915 /* open the mailbox state */
11916 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
11917 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
11918 res = -1;
11919 goto play_msg_cleanup;
11920 }
11921 open = 1;
11922
11923 /* play msg if it exists in this mailbox */
11924 if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
11925 played = 1;
11926 }
11927
11928 /* close mailbox */
11929 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
11930 res = -1;
11931 goto play_msg_cleanup;
11932 }
11933 open = 0;
11934 }
11935
11936play_msg_cleanup:
11937 if (!played) {
11938 res = -1;
11939 }
11940
11941 if (vmu && open) {
11942 close_mailbox(&vms, vmu);
11943 }
11944
11945#ifdef IMAP_STORAGE
11946 if (vmu) {
11947 vmstate_delete(&vms);
11948 }
11949#endif
11950
11951 free_user(vmu);
11952
11953 return res;
11954}
static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
static int play_message_by_id_helper(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, const char *msg_id)

References ARRAY_LEN, ast_copy_string(), ast_log, close_mailbox(), ast_vm_user::context, ERROR_LOCK_PATH, find_user(), free_user(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, mailbox_folders, NULL, open_mailbox(), play_message_by_id_helper(), and vm_state::username.

Referenced by vm_playmsgexec().

◆ play_message_by_id_helper()

static int play_message_by_id_helper ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
const char *  msg_id 
)
static

Definition at line 11851 of file app_voicemail.c.

11855{
11856 if (message_range_and_existence_check(vms, &msg_id, 1, &vms->curmsg, vmu)) {
11857 return -1;
11858 }
11859 /* Found the msg, so play it back */
11860
11861 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
11862
11863#ifdef IMAP_STORAGE
11864 /*IMAP storage stores any prepended message from a forward
11865 * as a separate file from the rest of the message
11866 */
11867 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
11868 wait_file(chan, vms, vms->introfn);
11869 }
11870#endif
11871 RETRIEVE(vms->curdir,vms->curmsg,vmu->mailbox, vmu->context);
11872
11873 if ((wait_file(chan, vms, vms->fn)) < 0) {
11874 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
11875 } else {
11876#ifdef IMAP_STORAGE
11877 ast_mutex_lock(&vms->lock);
11878#endif
11879 vms->heard[vms->curmsg] = 1;
11880#ifdef IMAP_STORAGE
11881 ast_mutex_unlock(&vms->lock);
11882#endif
11883 }
11884 DISPOSE(vms->curdir, vms->curmsg);
11885 return 0;
11886}
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.

References ast_fileexists(), ast_log, AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, vm_state::fn, vm_state::heard, ast_vm_user::mailbox, make_file(), message_range_and_existence_check(), NULL, RETRIEVE, and wait_file().

Referenced by play_message_by_id().

◆ play_message_callerid()

static int play_message_callerid ( struct ast_channel chan,
struct vm_state vms,
char *  cid,
const char *  context,
int  callback,
int  saycidnumber 
)
static

Definition at line 9157 of file app_voicemail.c.

9158{
9159 int res = 0;
9160 int i;
9161 char *callerid, *name;
9162 char prefile[PATH_MAX] = "";
9163
9164 /* If voicemail cid is not enabled, or we didn't get cid or context from
9165 * the attribute file, leave now.
9166 *
9167 * TODO Still need to change this so that if this function is called by the
9168 * message envelope (and someone is explicitly requesting to hear the CID),
9169 * it does not check to see if CID is enabled in the config file.
9170 */
9171 if ((cid == NULL)||(context == NULL))
9172 return res;
9173
9174 /* Strip off caller ID number from name */
9175 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
9176 ast_callerid_parse(cid, &name, &callerid);
9177 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
9178 /* Check for internal contexts and only */
9179 /* say extension when the call didn't come from an internal context in the list */
9180 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
9181 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
9182 if ((strcmp(cidinternalcontexts[i], context) == 0))
9183 break;
9184 }
9185 if (i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
9186 if (!res) {
9187 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
9188 if (!ast_strlen_zero(prefile)) {
9189 /* See if we can find a recorded name for this callerid
9190 * and if found, use that instead of saying number. */
9191 if (ast_fileexists(prefile, NULL, NULL) > 0) {
9192 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
9193 if (!callback)
9194 res = wait_file2(chan, vms, "vm-from");
9195 res = ast_stream_and_wait(chan, prefile, "");
9196 } else {
9197 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
9198 /* Say "from extension" as one saying to sound smoother */
9199 if (!callback)
9200 res = wait_file2(chan, vms, "vm-from-extension");
9201 res = ast_say_digit_str(chan, callerid, "", ast_channel_language(chan));
9202 }
9203 }
9204 }
9205 } else if (!res) {
9206 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
9207 /* If there is a recording for this numeric callerid then play that */
9208 if (!callback) {
9209 /* See if we can find a recorded name for this person instead of their extension number */
9210 snprintf(prefile, sizeof(prefile), "%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
9211 if (!saycidnumber && ast_fileexists(prefile, NULL, NULL) > 0) {
9212 ast_verb(3, "Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
9213 wait_file2(chan, vms, "vm-from");
9214 res = ast_stream_and_wait(chan, prefile, "");
9215 ast_verb(3, "Played recorded name result '%d'\n", res);
9216 } else {
9217 /* Since this is all nicely figured out, why not say "from phone number" in this case" */
9218 wait_file2(chan, vms, "vm-from-phonenumber");
9219 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
9220 }
9221 } else {
9222 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
9223 }
9224 }
9225 } else {
9226 /* Number unknown */
9227 ast_debug(1, "VM-CID: From an unknown number\n");
9228 /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
9229 res = wait_file2(chan, vms, "vm-unknown-caller");
9230 }
9231 return res;
9232}

References ast_callerid_parse(), ast_channel_language(), ast_config_AST_SPOOL_DIR, ast_debug, AST_DIGIT_ANY, ast_fileexists(), ast_say_digit_str(), ast_stream_and_wait(), ast_strlen_zero(), ast_verb, callback(), cidinternalcontexts, MAX_NUM_CID_CONTEXTS, name, NULL, PATH_MAX, VM_SPOOL_DIR, and wait_file2().

Referenced by advanced_options(), and play_message().

◆ play_message_category()

static int play_message_category ( struct ast_channel chan,
const char *  category 
)
static

Definition at line 9064 of file app_voicemail.c.

9065{
9066 int res = 0;
9067
9068 if (!ast_strlen_zero(category))
9069 res = ast_play_and_wait(chan, category);
9070
9071 if (res) {
9072 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
9073 res = 0;
9074 }
9075
9076 return res;
9077}

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

Referenced by play_message().

◆ play_message_datetime()

static int play_message_datetime ( struct ast_channel chan,
struct ast_vm_user vmu,
const char *  origtime,
const char *  filename 
)
static

Definition at line 9079 of file app_voicemail.c.

9080{
9081 int res = 0;
9082 struct vm_zone *the_zone = NULL;
9083 time_t t;
9084
9085 if (ast_get_time_t(origtime, &t, 0, NULL)) {
9086 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
9087 return 0;
9088 }
9089
9090 /* Does this user have a timezone specified? */
9091 if (!ast_strlen_zero(vmu->zonetag)) {
9092 /* Find the zone in the list */
9093 struct vm_zone *z;
9096 if (!strcmp(z->name, vmu->zonetag)) {
9097 the_zone = z;
9098 break;
9099 }
9100 }
9102 }
9103
9104/* No internal variable parsing for now, so we'll comment it out for the time being */
9105#if 0
9106 /* Set the DIFF_* variables */
9107 ast_localtime(&t, &time_now, NULL);
9108 tv_now = ast_tvnow();
9109 ast_localtime(&tv_now, &time_then, NULL);
9110
9111 /* Day difference */
9112 if (time_now.tm_year == time_then.tm_year)
9113 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
9114 else
9115 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
9116 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
9117
9118 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
9119#endif
9120 if (the_zone) {
9121 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
9122 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
9123 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9124 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
9125 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
9126 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
9127 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9128 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
9129 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
9130 } else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
9131 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "PHM q 'jp-ni' 'vm-received'", NULL);
9132 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
9133 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
9134 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
9135 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9136 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
9137 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q HM", NULL);
9138 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* Brazilian PORTUGUESE syntax */
9139 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
9140 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
9141 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL);
9142 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
9143 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "qR 'vm-received'", NULL);
9144 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
9145 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
9146 } else {
9147 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL);
9148 }
9149#if 0
9150 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
9151#endif
9152 return res;
9153}
SAY_EXTERN int(* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format)
Definition say.h:208
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
Definition utils.c:2480

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

Referenced by advanced_options(), and play_message().

◆ play_message_duration()

static int play_message_duration ( struct ast_channel chan,
struct vm_state vms,
const char *  duration,
int  minduration 
)
static

Definition at line 9234 of file app_voicemail.c.

9235{
9236 int res = 0;
9237 int durationm;
9238 int durations;
9239 /* Verify that we have a duration for the message */
9240 if (duration == NULL)
9241 return res;
9242
9243 /* Convert from seconds to minutes */
9244 durations = atoi(duration);
9245 durationm = (durations / 60);
9246
9247 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
9248
9249 if ((!res) && (durationm >= minduration)) {
9250 res = wait_file2(chan, vms, "vm-duration");
9251
9252 /* POLISH syntax */
9253 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9254 div_t num = div(durationm, 10);
9255
9256 if (durationm == 1) {
9257 res = ast_play_and_wait(chan, "digits/1z");
9258 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
9259 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9260 if (num.rem == 2) {
9261 if (!num.quot) {
9262 res = ast_play_and_wait(chan, "digits/2-ie");
9263 } else {
9264 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
9265 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
9266 }
9267 } else {
9268 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9269 }
9270 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
9271 } else {
9272 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9273 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
9274 }
9275 /* DEFAULT syntax */
9276 } else {
9277 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9278 res = wait_file2(chan, vms, "vm-minutes");
9279 }
9280 }
9281 return res;
9282}
static int say_and_wait(struct ast_channel *chan, int num, const char *language)

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

Referenced by play_message().

◆ play_record_review()

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

Definition at line 16631 of file app_voicemail.c.

16634{
16635 /* Record message & let caller review or re-record it, or set options if applicable */
16636 int res = 0;
16637 int cmd = 0;
16638 int max_attempts = 3;
16639 int attempts = 0;
16640 int recorded = 0;
16641 int msg_exists = 0;
16642 signed char zero_gain = 0;
16643 char tempfile[PATH_MAX];
16644 char *acceptdtmf = "#";
16645 char *canceldtmf = "";
16646 int canceleddtmf = 0;
16647 SCOPE_ENTER(3, "%s: rf: %s fmt: %s type: %s vmu: %s\n",
16648 ast_channel_name(chan), recordfile, fmt, outsidecaller ? "msg" : "greeting",
16649 vmu->mailbox);
16650 /* Note that urgent and private are for flagging messages as such in the future */
16651
16652 /* barf if no pointer passed to store duration in */
16653 if (duration == NULL) {
16654 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s\n", "Error play_record_review called without duration pointer\n");
16655 }
16656
16657 if (!outsidecaller)
16658 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
16659 else
16660 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
16661
16662 cmd = '3'; /* Want to start by recording */
16663
16664 while ((cmd >= 0) && (cmd != 't')) {
16665 switch (cmd) {
16666 case '1':
16667 if (!msg_exists) {
16668 /* In this case, 1 is to record a message */
16669 cmd = '3';
16670 break;
16671 } else {
16672 /* Otherwise 1 is to save the existing message */
16673 ast_verb(3, "Saving message as is\n");
16674 if (!outsidecaller) {
16675 ast_trace(-1, "Renaming greeting '%s' to '%s'\n", tempfile, recordfile);
16676 ast_filerename(tempfile, recordfile, NULL);
16677 }
16678 if (!forwardintro) {
16679 ast_stream_and_wait(chan, "vm-msgsaved", "");
16680 }
16681 if (!outsidecaller) {
16682 /* Saves to IMAP server only if imapgreeting=yes */
16683 ast_trace(-1, "Saving greeting '%s'\n", recordfile);
16684 SCOPE_CALL(-1, STORE, recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id);
16685 SCOPE_CALL(-1, DISPOSE, recordfile, -1);
16686 }
16687 cmd = 't';
16688 SCOPE_EXIT_RTN_VALUE(res, "Message saved to %s\n", recordfile);
16689 }
16690 case '2':
16691 /* Review */
16692 ast_verb(3, "Reviewing the message\n");
16693 ast_trace(-1, "Reviewing '%s'\n", tempfile);
16694 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
16695 break;
16696 case '3':
16697 msg_exists = 0;
16698 /* Record */
16699 if (recorded == 1)
16700 ast_verb(3, "Re-recording the message\n");
16701 else
16702 ast_verb(3, "Recording the message\n");
16703
16704 if (recorded && outsidecaller) {
16705 if (forwardintro) {
16706 cmd = ast_play_and_wait(chan, "vm-record-prepend");
16707 } else {
16708 cmd = ast_play_and_wait(chan, INTRO);
16709 }
16710 cmd = ast_play_and_wait(chan, "beep");
16711 }
16712 if (cmd == -1) {
16713 /* User has hung up, no options to give */
16714 ast_filedelete(tempfile, NULL);
16715 SCOPE_EXIT_RTN_VALUE(cmd, "User hung up before message could be rerecorded. Deleted '%s'\n", tempfile);
16716 }
16717 recorded = 1;
16718 /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
16719 if (record_gain)
16720 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
16721 if (ast_test_flag(vmu, VM_OPERATOR))
16722 canceldtmf = "0";
16723 ast_trace(-1, "Recording '%s'\n", tempfile);
16724 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
16725 if (strchr(canceldtmf, cmd)) {
16726 /* need this flag here to distinguish between pressing '0' during message recording or after */
16727 canceleddtmf = 1;
16728 }
16729 if (record_gain)
16730 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
16731 if (cmd == -1) {
16732 /* User has hung up, no options to give */
16733 if (!outsidecaller) {
16734 /* user was recording a greeting and they hung up, so let's delete the recording. */
16735 ast_filedelete(tempfile, NULL);
16736 }
16737 SCOPE_EXIT_RTN_VALUE(cmd, "User hung up after recording. %s %s\n",
16738 outsidecaller ? "Saved message " : "Deleted greeting \n", tempfile);
16739 }
16740 if (cmd == '0') {
16741 break;
16742 } else if (cmd == '*') {
16743 break;
16744#if 0
16745 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
16746 /* Message is too short */
16747 ast_verb(3, "Message too short\n");
16748 cmd = ast_play_and_wait(chan, "vm-tooshort");
16749 cmd = ast_filedelete(tempfile, NULL);
16750 break;
16751 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
16752 /* Message is all silence */
16753 ast_verb(3, "Nothing recorded\n");
16754 cmd = ast_filedelete(tempfile, NULL);
16755 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
16756 if (!cmd)
16757 cmd = ast_play_and_wait(chan, "vm-speakup");
16758 break;
16759#endif
16760 } else {
16761 /* If all is well, a message exists */
16762 msg_exists = 1;
16763 cmd = 0;
16764 }
16765 break;
16766 case '4':
16767 if (outsidecaller && ast_test_flag(vmu, VM_MARK_URGENT)) { /* only mark vm messages */
16768 /* Mark Urgent */
16769 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
16770 ast_verb(3, "marking message as Urgent\n");
16771 res = ast_play_and_wait(chan, "vm-marked-urgent");
16772 strcpy(flag, "Urgent");
16773 } else if (flag) {
16774 ast_verb(3, "UNmarking message as Urgent\n");
16775 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
16776 strcpy(flag, "");
16777 } else {
16778 ast_play_and_wait(chan, "vm-sorry");
16779 }
16780 cmd = 0;
16781 } else {
16782 cmd = ast_play_and_wait(chan, "vm-sorry");
16783 }
16784 break;
16785 case '5':
16786 case '6':
16787 case '7':
16788 case '8':
16789 case '9':
16790 case '*':
16791 case '#':
16792 cmd = ast_play_and_wait(chan, "vm-sorry");
16793 break;
16794#if 0
16795/* XXX Commented out for the moment because of the dangers of deleting
16796 a message while recording (can put the message numbers out of sync) */
16797 case '*':
16798 /* Cancel recording, delete message, offer to take another message*/
16799 cmd = ast_play_and_wait(chan, "vm-deleted");
16800 cmd = ast_filedelete(tempfile, NULL);
16801 if (outsidecaller) {
16802 res = vm_exec(chan, NULL);
16803 return res;
16804 }
16805 else
16806 return 1;
16807#endif
16808 case '0':
16809 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
16810 cmd = ast_play_and_wait(chan, "vm-sorry");
16811 break;
16812 }
16813 if (msg_exists || recorded) {
16814 ast_trace(-1, "Reviewing '%s'\n", tempfile);
16815 cmd = ast_play_and_wait(chan, "vm-saveoper");
16816 if (!cmd)
16817 cmd = ast_waitfordigit(chan, 3000);
16818 if (cmd == '1') {
16819 ast_trace(-1, "Saving '%s' to '%s'\n", tempfile, recordfile);
16820 ast_filerename(tempfile, recordfile, NULL);
16821 ast_play_and_wait(chan, "vm-msgsaved");
16822 cmd = '0';
16823 } else if (cmd == '4') {
16824 if (flag) {
16825 ast_play_and_wait(chan, "vm-marked-urgent");
16826 strcpy(flag, "Urgent");
16827 }
16828 ast_play_and_wait(chan, "vm-msgsaved");
16829 cmd = '0';
16830 } else {
16831 ast_trace(-1, "Deleting '%s'\n", tempfile);
16832 ast_play_and_wait(chan, "vm-deleted");
16833 SCOPE_CALL(-1, DELETE, tempfile, -1, tempfile, vmu);
16834 SCOPE_CALL(-1, DISPOSE, tempfile, -1);
16835 cmd = '0';
16836 }
16837 }
16838 return cmd;
16839 default:
16840 /* If the caller is an outside caller and the review option is enabled or it's forward intro
16841 allow them to review the message, but let the owner of the box review
16842 their OGM's */
16843 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW) && !forwardintro) {
16844 SCOPE_EXIT_RTN_VALUE(cmd, "Done. Outside caller, review not set, no forwardintro\n");
16845 }
16846 if (msg_exists) {
16847 cmd = ast_play_and_wait(chan, "vm-review");
16848 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_MARK_URGENT)) {
16849 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
16850 cmd = ast_play_and_wait(chan, "vm-review-urgent");
16851 } else if (flag) {
16852 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
16853 }
16854 }
16855 } else {
16856 cmd = ast_play_and_wait(chan, "vm-torerecord");
16857 if (!cmd)
16858 cmd = ast_waitfordigit(chan, 600);
16859 }
16860
16861 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
16862 cmd = ast_play_and_wait(chan, "vm-reachoper");
16863 if (!cmd)
16864 cmd = ast_waitfordigit(chan, 600);
16865 }
16866#if 0
16867 if (!cmd)
16868 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
16869#endif
16870 if (!cmd)
16871 cmd = ast_waitfordigit(chan, 6000);
16872 if (!cmd) {
16873 attempts++;
16874 }
16875 if (attempts > max_attempts) {
16876 cmd = 't';
16877 }
16878 }
16879 }
16880 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
16881 /* Hang up or timeout, so delete the recording. */
16882 ast_trace(-1, "Deleting '%s' on hangup or timeout\n", tempfile);
16883 ast_filedelete(tempfile, NULL);
16884 }
16885
16886 if (cmd != 't' && outsidecaller)
16887 ast_play_and_wait(chan, "vm-goodbye");
16888
16889 SCOPE_EXIT_RTN_VALUE(cmd, "Done\n");
16890}
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:7496
int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
Record a file based on input from a channel This function will play "auth-thankyou" upon successful r...
Definition main/app.c:2150
@ AST_RECORD_IF_EXISTS_OVERWRITE
#define AST_OPTION_RXGAIN

References ast_channel_name(), ast_channel_setoption(), ast_copy_string(), AST_DIGIT_ANY, ast_filedelete(), ast_filerename(), AST_OPTION_RXGAIN, ast_play_and_record_full(), ast_play_and_wait(), AST_RECORD_IF_EXISTS_OVERWRITE, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_trace, ast_verb, ast_waitfordigit(), ast_vm_user::context, DELETE, DISPOSE, INTRO, LOG_WARNING, ast_vm_user::mailbox, maxsilence, NULL, PATH_MAX, leave_vm_options::record_gain, SCOPE_CALL, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, silencethreshold, STORE, vm_exec(), VM_MARK_URGENT, VM_OPERATOR, and VM_REVIEW.

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

◆ poll_subscribed_mailbox()

static int poll_subscribed_mailbox ( struct ast_mwi_state mwi_state,
void *  data 
)
static

Definition at line 13994 of file app_voicemail.c.

13995{
13996 int new = 0, old = 0, urgent = 0;
13997
13998 if (!mwi_state) {
13999 /* This should only occur due to allocation failure of a default mwi state object */
14000 return 0;
14001 }
14002
14003 inboxcount2(mwi_state->uniqueid, &urgent, &new, &old);
14004
14005#ifdef IMAP_STORAGE
14006 if (imap_poll_logout) {
14007 imap_logout(mwi_state->uniqueid);
14008 }
14009#endif
14010
14011 if (urgent != mwi_state->urgent_msgs || new != mwi_state->new_msgs || old != mwi_state->old_msgs) {
14012 queue_mwi_event(NULL, mwi_state->uniqueid, urgent, new, old);
14013 run_externnotify(NULL, mwi_state->uniqueid, NULL);
14014 }
14015
14016 return 0;
14017}
int urgent_msgs
Definition mwi.h:464
int old_msgs
Definition mwi.h:460
int new_msgs
Definition mwi.h:459

References inboxcount2(), ast_mwi_state::new_msgs, NULL, ast_mwi_state::old_msgs, queue_mwi_event(), run_externnotify(), ast_mwi_state::uniqueid, and ast_mwi_state::urgent_msgs.

Referenced by manager_match_mailbox(), mb_poll_thread(), and mwi_handle_subscribe2().

◆ populate_defaults()

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

1524{
1527 if (saydurationminfo) {
1529 }
1530 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
1531 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
1532 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
1533 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
1534 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
1535 if (vmminsecs) {
1536 vmu->minsecs = vmminsecs;
1537 }
1538 if (vmmaxsecs) {
1539 vmu->maxsecs = vmmaxsecs;
1540 }
1541 if (maxmsg) {
1542 vmu->maxmsg = maxmsg;
1543 }
1544 if (maxdeletedmsg) {
1546 }
1547 vmu->volgain = volgain;
1548 ast_free(vmu->email);
1549 vmu->email = NULL;
1550 ast_free(vmu->emailsubject);
1551 vmu->emailsubject = NULL;
1552 ast_free(vmu->emailbody);
1553 vmu->emailbody = NULL;
1554#ifdef IMAP_STORAGE
1555 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
1556 ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
1557 ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
1558 ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
1559#endif
1560}
#define ast_copy_flags(dest, src, flagz)
Definition utils.h:85
#define AST_FLAGS_ALL
Definition utils.h:217

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

Referenced by append_mailbox(), and find_user_realtime().

◆ prep_email_sub_vars()

static void prep_email_sub_vars ( struct ast_channel ast,
struct ast_vm_user vmu,
int  msgnum,
char *  context,
char *  mailbox,
const char *  fromfolder,
char *  cidnum,
char *  cidname,
char *  dur,
char *  date,
const char *  category,
const char *  flag 
)
static

Definition at line 5245 of file app_voicemail.c.

5246{
5247 char callerid[256];
5248 char num[12];
5249 char fromdir[256], fromfile[256];
5250 struct ast_config *msg_cfg;
5251 const char *origcallerid, *origtime;
5252 char origcidname[80], origcidnum[80], origdate[80];
5253 int inttime;
5254 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
5255
5256 /* Prepare variables for substitution in email body and subject */
5257 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
5258 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
5259 snprintf(num, sizeof(num), "%d", msgnum);
5260 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
5261 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
5262 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
5263 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
5264 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
5265 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
5266 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
5267 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
5268 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
5269 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
5270
5271 /* Retrieve info from VM attribute file */
5272 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
5273 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
5274 if (strlen(fromfile) < sizeof(fromfile) - 5) {
5275 strcat(fromfile, ".txt");
5276 }
5277 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
5278 ast_debug(1, "Config load for message text file '%s' failed\n", fromfile);
5279 return;
5280 }
5281
5282 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
5283 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
5284 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
5285 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
5286 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
5287 }
5288
5289 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
5290 struct timeval tv = { inttime, };
5291 struct ast_tm tm;
5292 ast_localtime(&tv, &tm, NULL);
5293 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
5294 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
5295 }
5296 ast_config_destroy(msg_cfg);
5297}

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

Referenced by make_email_file(), and sendpage().

◆ print_mappings()

static void print_mappings ( void *  v_obj,
void *  where,
ao2_prnt_fn prnt 
)
static

Definition at line 16224 of file app_voicemail.c.

16225{
16226 struct alias_mailbox_mapping *mapping = v_obj;
16227
16228 if (!mapping) {
16229 return;
16230 }
16231 prnt(where, "Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);
16232}

References alias_mailbox_mapping::alias, and alias_mailbox_mapping::mailbox.

Referenced by load_module().

◆ queue_mwi_event()

static void queue_mwi_event ( const char *  channel_id,
const char *  box,
int  urgent,
int  new,
int  old 
)
static

Definition at line 8546 of file app_voicemail.c.

8547{
8548 char *mailbox;
8549 char *context;
8550
8551 if (separate_mailbox(ast_strdupa(box), &mailbox, &context)) {
8552 return;
8553 }
8554
8555 ast_debug(3, "Queueing event for mailbox %s New: %d Old: %d\n", box, new + urgent, old);
8556 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
8557
8559 struct ao2_iterator *aliases;
8560 struct mailbox_alias_mapping *mapping;
8561
8563 while ((mapping = ao2_iterator_next(aliases))) {
8564 char alias[strlen(mapping->alias) + 1];
8565 strcpy(alias, mapping->alias); /* safe */
8566 mailbox = NULL;
8567 context = NULL;
8568 ast_debug(3, "Found alias mapping: %s -> %s\n", mapping->alias, box);
8569 separate_mailbox(alias, &mailbox, &context);
8570 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
8571 ao2_ref(mapping, -1);
8572 }
8574 }
8575}
#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id)
Publish a MWI state update associated with some channel.
Definition mwi.h:395

References mailbox_alias_mapping::alias, aliases, aliasescontext, ao2_find, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, ast_debug, ast_publish_mwi_state_channel, ast_strdupa, ast_strlen_zero(), mailbox_alias_mapping::mailbox, mailbox_alias_mappings, NULL, OBJ_MULTIPLE, OBJ_SEARCH_KEY, and separate_mailbox().

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

◆ read_password_from_file()

static void read_password_from_file ( const char *  secretfn,
char *  password,
int  passwordlen 
)
static

Definition at line 15512 of file app_voicemail.c.

15512 {
15513 struct ast_config *pwconf;
15514 struct ast_flags config_flags = { 0 };
15515
15516 pwconf = ast_config_load(secretfn, config_flags);
15517 if (valid_config(pwconf)) {
15518 const char *val = ast_variable_retrieve(pwconf, "general", "password");
15519 if (val) {
15520 ast_copy_string(password, val, passwordlen);
15521 ast_config_destroy(pwconf);
15522 return;
15523 }
15524 ast_config_destroy(pwconf);
15525 }
15526 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
15527}

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

Referenced by append_mailbox().

◆ reload()

static int reload ( void  )
static

Definition at line 16166 of file app_voicemail.c.

16167{
16168 return load_config(1);
16169}

References load_config().

Referenced by load_config(), and load_config_force().

◆ remove_message_from_mailbox()

static int remove_message_from_mailbox ( struct ast_cli_args a)
static

Definition at line 12097 of file app_voicemail.c.

12098{
12099 const char *mailbox = a->argv[2];
12100 const char *context = a->argv[3];
12101 const char *folder = a->argv[4];
12102 const char *id[] = { a->argv[5] };
12103 int ret = vm_msg_remove(mailbox, context, 1, folder, id);
12104 if (ret) {
12105 ast_cli(a->fd, "Error removing message %s from mailbox %s@%s %s\n",
12106 id[0], mailbox, context, folder);
12107 } else {
12108 ast_cli(a->fd, "Removed message %s from mailbox %s@%s %s\n",
12109 id[0], mailbox, context, folder);
12110 }
12111 return ret;
12112}

References a, ast_cli(), and vm_msg_remove().

Referenced by handle_voicemail_remove_message().

◆ rename_file()

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

5035{
5036 char stxt[PATH_MAX];
5037 char dtxt[PATH_MAX];
5038 ast_filerename(sfn, dfn, NULL);
5039 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
5040 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
5041 if (ast_check_realtime("voicemail_data")) {
5042 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
5043 }
5044 rename(stxt, dtxt);
5045}

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

◆ resequence_mailbox()

static int resequence_mailbox ( struct ast_vm_user vmu,
char *  dir,
int  stopcount 
)
static

Definition at line 7593 of file app_voicemail.c.

7594{
7595 /* we know the actual number of messages, so stop process when number is hit */
7596
7597 int x, dest;
7598 char sfn[PATH_MAX];
7599 char dfn[PATH_MAX];
7600
7601 if (vm_lock_path(dir)) {
7602 return ERROR_LOCK_PATH;
7603 }
7604
7605 for (x = 0, dest = 0; dest != stopcount && x < MAXMSGLIMIT; x++) {
7606 make_file(sfn, sizeof(sfn), dir, x);
7607 if (EXISTS(dir, x, sfn, NULL)) {
7608
7609 if (x != dest) {
7610 make_file(dfn, sizeof(dfn), dir, dest);
7611 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
7612 }
7613
7614 dest++;
7615 }
7616 }
7617 ast_unlock_path(dir);
7618
7619 return dest;
7620}

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

Referenced by open_mailbox().

◆ reset_user_pw()

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
newpass

This does the actual change password work, called by the vm_change_password() function.

Returns
zero on success, -1 on error.

Definition at line 2049 of file app_voicemail.c.

2050{
2051 /* This function could be made to generate one from a database, too */
2052 struct ast_vm_user *cur;
2053 int res = -1;
2055 AST_LIST_TRAVERSE(&users, cur, list) {
2056 if ((!context || !strcasecmp(context, cur->context)) &&
2057 (!strcasecmp(mailbox, cur->mailbox)))
2058 break;
2059 }
2060 if (cur) {
2061 ast_copy_string(cur->password, newpass, sizeof(cur->password));
2062 res = 0;
2063 }
2065 if (!res) {
2066 struct ast_json *json_object;
2067
2068 json_object = ast_json_pack("{s: s, s: s, s: s}",
2069 "Context", S_OR(context, "default"),
2070 "Mailbox", mailbox,
2071 "NewPassword", newpass);
2072 ast_manager_publish_event("VoicemailPasswordChange", EVENT_FLAG_SYSTEM | EVENT_FLAG_USER, json_object);
2073 ast_json_unref(json_object);
2074 }
2075 return res;
2076}
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition manager.c:646
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
Abstract JSON element (object, array, string, int, ...).

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, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, ast_vm_user::list, ast_vm_user::mailbox, ast_vm_user::password, and S_OR.

Referenced by vm_change_password(), and vm_change_password_shell().

◆ run_externnotify()

static void run_externnotify ( const char *  context,
const char *  extension,
const char *  flag 
)
static

Definition at line 6608 of file app_voicemail.c.

6609{
6610 char arguments[255];
6611 char ext_context[256] = "";
6612 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
6613 struct ast_smdi_mwi_message *mwi_msg;
6614
6615 if (!ast_strlen_zero(context))
6616 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
6617 else
6618 ast_copy_string(ext_context, extension, sizeof(ext_context));
6619
6620 if (smdi_iface) {
6621 if (ast_app_has_voicemail(ext_context, NULL))
6623 else
6625
6627 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
6628 if (!strncmp(mwi_msg->cause, "INV", 3))
6629 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
6630 else if (!strncmp(mwi_msg->cause, "BLK", 3))
6631 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
6632 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
6633 ao2_ref(mwi_msg, -1);
6634 } else {
6635 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
6636 }
6637 }
6638
6640 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
6641 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
6642 } else {
6643 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
6644 externnotify, S_OR(context, "\"\""),
6645 extension, newvoicemails,
6646 oldvoicemails, urgentvoicemails);
6647 ast_debug(1, "Executing %s\n", arguments);
6648 ast_safe_system(arguments);
6649 }
6650 }
6651}
#define SMDI_MWI_WAIT_TIMEOUT
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
Definition res_smdi.c:320
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
Set the MWI indicator for a mailbox.
Definition res_smdi.c:315
struct ast_smdi_mwi_message *AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout, const char *station)
Definition res_smdi.c:562
An SMDI message waiting indicator message.
Definition smdi.h:51
char cause[SMDI_MWI_FAIL_CAUSE_LEN+1]
Definition smdi.h:54
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition smdi.h:53

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

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

◆ save_to_folder()

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

7631{
7632#ifdef IMAP_STORAGE
7633 /* we must use mbox(x) folder names, and copy the message there */
7634 /* simple. huh? */
7635 char sequence[10];
7636 char mailbox[256];
7637 int res;
7638 int curr_mbox;
7639
7640 /* get the real IMAP message number for this message */
7641 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
7642
7643 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
7644 ast_mutex_lock(&vms->lock);
7645 /* if save to Old folder, put in INBOX as read */
7646 if (box == OLD_FOLDER) {
7647 mail_setflag(vms->mailstream, sequence, "\\Seen");
7648 } else if (box == NEW_FOLDER) {
7649 mail_clearflag(vms->mailstream, sequence, "\\Seen");
7650 }
7651 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
7652 ast_mutex_unlock(&vms->lock);
7653 return 0;
7654 }
7655
7656 /* get the current mailbox so that we can point the mailstream back to it later */
7657 curr_mbox = get_folder_by_name(vms->curbox);
7658
7659 /* Create the folder if it doesn't exist */
7660 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */
7661 if (vms->mailstream && !mail_status(vms->mailstream, mailbox, SA_UIDNEXT)) {
7662 if (mail_create(vms->mailstream, mailbox) != NIL) {
7663 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
7664 }
7665 }
7666
7667 /* restore previous mbox stream */
7668 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7669 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
7670 res = -1;
7671 } else {
7672 if (move) {
7673 res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box));
7674 } else {
7675 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
7676 }
7677 }
7678 ast_mutex_unlock(&vms->lock);
7679 return res;
7680#else
7681 char *dir = vms->curdir;
7682 char *username = vms->username;
7683 char *context = vmu->context;
7684 char sfn[PATH_MAX];
7685 char dfn[PATH_MAX];
7686 char ddir[PATH_MAX];
7687 const char *dbox = mbox(vmu, box);
7688 int x, i;
7689 SCOPE_ENTER(3, "dir: %s msg: %d box: %d dbox: %s move? %d \n", dir, msg, box, dbox, move);
7690
7691 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
7692 ast_trace(-1, "ddir: %s\n", ddir);
7693
7694 if (vm_lock_path(ddir)) {
7695 SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH, "Failed to lock path %s\n", ddir);
7696 }
7697
7698 x = LAST_MSG_INDEX(ddir) + 1;
7699
7700 if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/
7701 ast_trace(-1, "Deleting message %d\n", msg);
7702 x--;
7703 for (i = 1; i <= x; i++) {
7704 /* Push files down a "slot". The oldest file (msg0000) will be deleted. */
7705 make_file(sfn, sizeof(sfn), ddir, i);
7706 make_file(dfn, sizeof(dfn), ddir, i - 1);
7707 if (EXISTS(ddir, i, sfn, NULL)) {
7708 SCOPE_CALL(-1, RENAME, ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
7709 } else
7710 break;
7711 }
7712 } else {
7713 if (x >= vmu->maxmsg) {
7714 ast_unlock_path(ddir);
7715 SCOPE_EXIT_RTN_VALUE(ERROR_MAX_MSGS, "Max messages reached\n");
7716 }
7717 }
7718 make_file(sfn, sizeof(sfn), dir, msg);
7719 make_file(dfn, sizeof(dfn), ddir, x);
7720 if (strcmp(sfn, dfn)) {
7721 ast_trace(-1, "Copying message '%s' to '%s'\n", sfn, dfn);
7722 SCOPE_CALL(-1, COPY, dir, msg, ddir, x, username, context, sfn, dfn);
7723 }
7724 ast_unlock_path(ddir);
7725
7726 if (newmsg) {
7727 *newmsg = x;
7728 }
7729 SCOPE_EXIT_RTN_VALUE(0, "Done\n");
7730#endif
7731}
static int get_folder_by_name(const char *name)

References ast_debug, ast_log, AST_LOG_ERROR, AST_LOG_NOTICE, ast_mutex_lock, ast_mutex_unlock, ast_trace, ast_unlock_path(), ast_vm_user::context, COPY, create_dirpath(), vm_state::curbox, vm_state::curdir, ERROR_LOCK_PATH, ERROR_MAX_MSGS, EXISTS, get_folder_by_name(), LAST_MSG_INDEX, ast_vm_user::mailbox, make_file(), ast_vm_user::maxdeletedmsg, ast_vm_user::maxmsg, mbox(), NEW_FOLDER, NULL, OLD_FOLDER, PATH_MAX, RENAME, SCOPE_CALL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, vm_state::username, and vm_lock_path().

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

◆ say_and_wait()

static int say_and_wait ( struct ast_channel chan,
int  num,
const char *  language 
)
static

◆ sayname()

static int sayname ( struct ast_channel chan,
const char *  mailbox,
const char *  context 
)
static

Definition at line 15475 of file app_voicemail.c.

15476{
15477 int res = -1;
15478 char dir[PATH_MAX];
15479 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
15480 ast_debug(2, "About to try retrieving name file %s\n", dir);
15481 RETRIEVE(dir, -1, mailbox, context);
15482 if (ast_fileexists(dir, NULL, NULL)) {
15483 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
15484 }
15485 DISPOSE(dir, -1);
15486 return res;
15487}

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

Referenced by ast_app_sayname(), vm_sayname(), and vmsayname_exec().

◆ sendmail()

static int sendmail ( char *  srcemail,
struct ast_vm_user vmu,
int  msgnum,
char *  context,
char *  mailbox,
const char *  fromfolder,
char *  cidnum,
char *  cidname,
char *  attach,
char *  attach2,
char *  format,
int  duration,
int  attach_user_voicemail,
struct ast_channel chan,
const char *  category,
const char *  flag,
const char *  msg_id 
)
static

Definition at line 5870 of file app_voicemail.c.

5887{
5888 FILE *p = NULL;
5889 char tmp[80] = "/tmp/astmail-XXXXXX";
5890 char tmp2[256];
5891 char *stringp;
5892
5893 if (vmu && ast_strlen_zero(vmu->email)) {
5894 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
5895 return(0);
5896 }
5897
5898 /* Mail only the first format */
5899 format = ast_strdupa(format);
5900 stringp = format;
5901 strsep(&stringp, "|");
5902
5903 if (!strcmp(format, "wav49"))
5904 format = "WAV";
5905 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
5906 /* Make a temporary file instead of piping directly to sendmail, in case the mail
5907 command hangs */
5908 if ((p = ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
5909 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5910 return -1;
5911 } else {
5912 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag, msg_id);
5913 fclose(p);
5914 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
5915 ast_safe_system(tmp2);
5916 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
5917 }
5918 return 0;
5919}
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.
FILE * ast_file_mkftemp(char *template_name, mode_t mode)
same as mkstemp, but return a FILE
Definition file.c:188

References ast_debug, ast_file_mkftemp(), ast_log, AST_LOG_WARNING, ast_safe_system(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_vm_user::email, globalflags, ast_vm_user::mailbox, mailcmd, make_email_file(), my_umask, NULL, strsep(), VM_ATTACH, and VOICEMAIL_FILE_MODE.

Referenced by forward_message(), and notify_new_message().

◆ sendpage()

static int sendpage ( char *  srcemail,
char *  pager,
int  msgnum,
char *  context,
char *  mailbox,
const char *  fromfolder,
char *  cidnum,
char *  cidname,
int  duration,
struct ast_vm_user vmu,
const char *  category,
const char *  flag 
)
static

Definition at line 5921 of file app_voicemail.c.

5922{
5923 char enc_cidnum[256], enc_cidname[256];
5924 char date[256];
5925 char host[MAXHOSTNAMELEN] = "";
5926 char who[256];
5927 char dur[PATH_MAX];
5928 char tmp[80] = "/tmp/astmail-XXXXXX";
5929 char tmp2[PATH_MAX];
5930 struct ast_tm tm;
5931 FILE *p;
5932 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
5933
5934 if (!str1 || !str2) {
5935 ast_free(str1);
5936 ast_free(str2);
5937 return -1;
5938 }
5939
5940 if (cidnum) {
5941 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
5942 }
5943 if (cidname) {
5944 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
5945 }
5946
5947 if ((p = ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
5948 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5949 ast_free(str1);
5950 ast_free(str2);
5951 return -1;
5952 }
5953 gethostname(host, sizeof(host)-1);
5954 if (strchr(srcemail, '@')) {
5955 ast_copy_string(who, srcemail, sizeof(who));
5956 } else {
5957 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
5958 }
5959 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
5960 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
5961 fprintf(p, "Date: %s\n", date);
5962
5963 /* Reformat for custom pager format */
5964 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
5965
5967 struct ast_channel *ast;
5968 if ((ast = ast_dummy_channel_alloc())) {
5969 char *ptr;
5970 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5972
5973 if (check_mime(ast_str_buffer(str1))) {
5974 int first_line = 1;
5975 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
5976 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
5977 *ptr = '\0';
5978 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
5979 first_line = 0;
5980 /* Substring is smaller, so this will never grow */
5981 ast_str_set(&str2, 0, "%s", ptr + 1);
5982 }
5983 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
5984 } else {
5985 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
5986 }
5987 ast = ast_channel_unref(ast);
5988 } else {
5989 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
5990 }
5991 } else {
5992 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
5993 }
5994
5995 if (check_mime(vmu->fullname)) {
5996 int first_line = 1;
5997 char *ptr;
5998 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
5999 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
6000 *ptr = '\0';
6001 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
6002 first_line = 0;
6003 /* Substring is smaller, so this will never grow */
6004 ast_str_set(&str2, 0, "%s", ptr + 1);
6005 }
6006 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
6007 } else {
6008 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
6009 }
6010
6012 struct ast_channel *ast;
6013 if ((ast = ast_dummy_channel_alloc())) {
6014 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
6016 if (check_mime(ast_str_buffer(str1))) {
6017 int first_line = 1;
6018 char *ptr;
6019 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
6020 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
6021 *ptr = '\0';
6022 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
6023 first_line = 0;
6024 /* Substring is smaller, so this will never grow */
6025 ast_str_set(&str2, 0, "%s", ptr + 1);
6026 }
6027 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
6028 } else {
6029 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
6030 }
6031 ast = ast_channel_unref(ast);
6032 } else {
6033 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
6034 }
6035 } else {
6036 if (ast_strlen_zero(flag)) {
6037 fprintf(p, "Subject: New VM" ENDL);
6038 } else {
6039 fprintf(p, "Subject: New %s VM" ENDL, flag);
6040 }
6041 }
6042
6043 /* End of headers */
6044 fputs(ENDL, p);
6045
6046 if (pagerbody) {
6047 struct ast_channel *ast;
6048 if ((ast = ast_dummy_channel_alloc())) {
6049 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
6051 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
6052 ast = ast_channel_unref(ast);
6053 } else {
6054 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
6055 }
6056 } else {
6057 fprintf(p, "New %s long %s msg in box %s\n"
6058 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
6059 }
6060
6061 fclose(p);
6062 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
6063 ast_safe_system(tmp2);
6064 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
6065 ast_free(str1);
6066 ast_free(str2);
6067 return 0;
6068}

References ast_channel_unref, ast_copy_string(), ast_debug, ast_dummy_channel_alloc, ast_file_mkftemp(), ast_free, ast_log, AST_LOG_WARNING, ast_safe_system(), ast_str_buffer(), ast_str_create, ast_str_encode_mime(), ast_str_quote(), ast_str_set(), ast_str_substitute_variables(), ast_strftime(), ast_strftime_locale(), ast_strlen_zero(), check_mime(), ast_channel::context, ENDL, ast_vm_user::fullname, ast_vm_user::locale, mailcmd, MAXHOSTNAMELEN, my_umask, NULL, pagerbody, pagerdateformat, pagerfromstring, pagersubject, PATH_MAX, prep_email_sub_vars(), S_OR, strip_control_and_high(), vmu_tm(), and VOICEMAIL_FILE_MODE.

Referenced by notify_new_message().

◆ separate_mailbox()

static int separate_mailbox ( char *  mailbox_id,
char **  mailbox,
char **  context 
)
static

Definition at line 1282 of file app_voicemail.c.

1283{
1284 if (ast_strlen_zero(mailbox_id) || !mailbox || !context) {
1285 return -1;
1286 }
1287 *context = mailbox_id;
1288 *mailbox = strsep(context, "@");
1289 if (ast_strlen_zero(*mailbox)) {
1290 return -1;
1291 }
1292 if (ast_strlen_zero(*context)) {
1293 *context = "default";
1294 }
1295 return 0;
1296}

References ast_strlen_zero(), and strsep().

Referenced by __has_voicemail(), acf_vm_info(), find_user(), messagecount(), queue_mwi_event(), vm_sayname(), and vmsayname_exec().

◆ show_mailbox_details()

static int show_mailbox_details ( struct ast_cli_args a)
static

Definition at line 11995 of file app_voicemail.c.

11996{
11997#define VMBOX_STRING_HEADER_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11998#define VMBOX_STRING_DATA_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11999
12000 const char *mailbox = a->argv[3];
12001 const char *context = a->argv[4];
12002 struct vm_state vms;
12003 struct ast_vm_user *vmu = NULL, vmus;
12004 memset(&vmus, 0, sizeof(vmus));
12005 memset(&vms, 0, sizeof(vms));
12006
12007 if (!(vmu = find_user(&vmus, context, mailbox))) {
12008 ast_cli(a->fd, "Can't find voicemail user %s@%s\n", mailbox, context);
12009 return -1;
12010 }
12011
12012 ast_cli(a->fd, VMBOX_STRING_HEADER_FORMAT, "Full Name", "Email", "Pager", "Language", "Locale", "Time Zone");
12013 ast_cli(a->fd, VMBOX_STRING_DATA_FORMAT, vmu->fullname, vmu->email, vmu->pager, vmu->language, vmu->locale, vmu->zonetag);
12014
12015 return 0;
12016}
#define VMBOX_STRING_DATA_FORMAT
#define VMBOX_STRING_HEADER_FORMAT

References a, ast_cli(), ast_vm_user::context, ast_vm_user::email, find_user(), ast_vm_user::fullname, ast_vm_user::language, ast_vm_user::locale, ast_vm_user::mailbox, NULL, ast_vm_user::pager, VMBOX_STRING_DATA_FORMAT, VMBOX_STRING_HEADER_FORMAT, and ast_vm_user::zonetag.

Referenced by show_messages_for_mailbox().

◆ show_mailbox_snapshot()

static int show_mailbox_snapshot ( struct ast_cli_args a)
static

Definition at line 12018 of file app_voicemail.c.

12019{
12020#define VM_STRING_HEADER_FORMAT "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
12021 const char *mailbox = a->argv[3];
12022 const char *context = a->argv[4];
12023 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
12024 struct ast_vm_msg_snapshot *msg;
12025 int i;
12026
12027 /* Take a snapshot of the mailbox and walk through each folder's contents */
12028 mailbox_snapshot = ast_vm_mailbox_snapshot_create(mailbox, context, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
12029 if (!mailbox_snapshot) {
12030 ast_cli(a->fd, "Can't create snapshot for voicemail user %s@%s\n", mailbox, context);
12031 return -1;
12032 }
12033
12034 ast_cli(a->fd, VM_STRING_HEADER_FORMAT, "Folder", "Caller ID", "Date", "Duration", "Flag", "ID");
12035
12036 for (i = 0; i < mailbox_snapshot->folders; i++) {
12037 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
12038 ast_cli(a->fd, VM_STRING_HEADER_FORMAT, msg->folder_name, msg->callerid, msg->origdate, msg->duration,
12039 msg->flag, msg->msg_id);
12040 }
12041 }
12042
12043 ast_cli(a->fd, "%d Message%s Total\n", mailbox_snapshot->total_msg_num, ESS(mailbox_snapshot->total_msg_num));
12044 /* done, destroy. */
12045 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
12046
12047 return 0;
12048}
#define VM_STRING_HEADER_FORMAT
#define ESS(x)
Definition cli.h:59

References a, ast_cli(), AST_LIST_TRAVERSE, ast_vm_mailbox_snapshot_create(), ast_vm_mailbox_snapshot_destroy(), AST_VM_SNAPSHOT_SORT_BY_ID, ast_vm_user::context, ESS, ast_vm_mailbox_snapshot::folders, ast_vm_user::mailbox, ast_vm_msg_snapshot::msg, NULL, ast_vm_mailbox_snapshot::total_msg_num, and VM_STRING_HEADER_FORMAT.

Referenced by show_messages_for_mailbox().

◆ show_messages_for_mailbox()

static int show_messages_for_mailbox ( struct ast_cli_args a)
static

Definition at line 12050 of file app_voicemail.c.

12051{
12052 if (show_mailbox_details(a)){
12053 return -1;
12054 }
12055 ast_cli(a->fd, "\n");
12056 return show_mailbox_snapshot(a);
12057}
static int show_mailbox_snapshot(struct ast_cli_args *a)
static int show_mailbox_details(struct ast_cli_args *a)

References a, ast_cli(), show_mailbox_details(), and show_mailbox_snapshot().

Referenced by handle_voicemail_show_mailbox().

◆ show_users_realtime()

static char * show_users_realtime ( int  fd,
const char *  context 
)
static

Definition at line 13741 of file app_voicemail.c.

13742{
13743 struct ast_config *cfg;
13744 const char *cat = NULL;
13745
13746 if (!(cfg = ast_load_realtime_multientry("voicemail",
13747 "context", context, SENTINEL))) {
13748 return CLI_FAILURE;
13749 }
13750
13751 ast_cli(fd,
13752 "\n"
13753 "=============================================================\n"
13754 "=== Configured Voicemail Users ==============================\n"
13755 "=============================================================\n"
13756 "===\n");
13757
13758 while ((cat = ast_category_browse(cfg, cat))) {
13759 struct ast_variable *var = NULL;
13760 ast_cli(fd,
13761 "=== Mailbox ...\n"
13762 "===\n");
13763 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
13764 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
13765 ast_cli(fd,
13766 "===\n"
13767 "=== ---------------------------------------------------------\n"
13768 "===\n");
13769 }
13770
13771 ast_cli(fd,
13772 "=============================================================\n"
13773 "\n");
13774
13775 ast_config_destroy(cfg);
13776
13777 return CLI_SUCCESS;
13778}
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.

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

Referenced by handle_voicemail_show_users().

◆ start_poll_thread()

static void start_poll_thread ( void  )
static

Definition at line 14142 of file app_voicemail.c.

14143{
14144 int errcode;
14146
14147 poll_thread_run = 1;
14148
14149 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
14150 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
14151 }
14152}
struct ast_mwi_observer mwi_observer
static void * mb_poll_thread(void *data)
int ast_mwi_add_observer(struct ast_mwi_observer *observer)
Add an observer to receive MWI state related events.
Definition mwi.c:301
#define ast_pthread_create(a, b, c, d)
Definition utils.h:624

References ast_log, ast_mwi_add_observer(), ast_pthread_create, LOG_ERROR, mb_poll_thread(), mwi_observer, NULL, poll_thread, and poll_thread_run.

Referenced by actual_load_config().

◆ stop_poll_thread()

static void stop_poll_thread ( void  )
static

Definition at line 14154 of file app_voicemail.c.

14155{
14156 poll_thread_run = 0;
14157
14161
14162 pthread_join(poll_thread, NULL);
14164
14166}
#define ast_cond_signal(cond)
Definition lock.h:210
void ast_mwi_remove_observer(struct ast_mwi_observer *observer)
Remove an MWI state observer.
Definition mwi.c:307

References ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, ast_mwi_remove_observer(), AST_PTHREADT_NULL, mwi_observer, NULL, poll_cond, poll_lock, poll_thread, and poll_thread_run.

Referenced by actual_load_config(), and unload_module().

◆ strip_control_and_high()

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

1364{
1365 char *bufptr = buf;
1366 for (; *input; input++) {
1367 if (*input < 32) {
1368 continue;
1369 }
1370 *bufptr++ = *input;
1371 if (bufptr == buf + buflen - 1) {
1372 break;
1373 }
1374 }
1375 *bufptr = '\0';
1376 return buf;
1377}

References buf.

Referenced by make_email_file(), and sendpage().

◆ substitute_escapes()

static const char * substitute_escapes ( const char *  value)
static

Definition at line 14655 of file app_voicemail.c.

14656{
14657 char *current;
14658
14659 /* Add 16 for fudge factor */
14660 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
14661
14663
14664 /* Substitute strings \r, \n, and \t into the appropriate characters */
14665 for (current = (char *) value; *current; current++) {
14666 if (*current == '\\') {
14667 current++;
14668 if (!*current) {
14669 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
14670 break;
14671 }
14672 switch (*current) {
14673 case '\\':
14674 ast_str_append(&str, 0, "\\");
14675 break;
14676 case 'r':
14677 ast_str_append(&str, 0, "\r");
14678 break;
14679 case 'n':
14680#ifdef IMAP_STORAGE
14681 if (!str->used || str->str[str->used - 1] != '\r') {
14682 ast_str_append(&str, 0, "\r");
14683 }
14684#endif
14685 ast_str_append(&str, 0, "\n");
14686 break;
14687 case 't':
14688 ast_str_append(&str, 0, "\t");
14689 break;
14690 default:
14691 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
14692 break;
14693 }
14694 } else {
14695 ast_str_append(&str, 0, "%c", *current);
14696 }
14697 }
14698
14699 return ast_str_buffer(str);
14700}
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909

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

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

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 16171 of file app_voicemail.c.

16172{
16173 int res;
16174
16181 res |= ast_manager_unregister("VoicemailUsersList");
16182 res |= ast_manager_unregister("VoicemailUserStatus");
16183 res |= ast_manager_unregister("VoicemailRefresh");
16184 res |= ast_manager_unregister("VoicemailBoxSummary");
16185 res |= ast_manager_unregister("VoicemailMove");
16186 res |= ast_manager_unregister("VoicemailRemove");
16187 res |= ast_manager_unregister("VoicemailForward");
16188#ifdef TEST_FRAMEWORK
16189 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
16190 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
16191 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
16192 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
16193 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
16194 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
16195#endif
16199#ifdef TEST_FRAMEWORK
16200 ast_uninstall_vm_test_functions();
16201#endif
16203
16204 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16206 ao2_container_unregister("voicemail_mailbox_alias_mappings");
16208
16211
16213 ast_unload_realtime("voicemail");
16214 ast_unload_realtime("voicemail_data");
16215
16216#ifdef IMAP_STORAGE
16217 ast_mwi_state_callback_all(imap_close_subscribed_mailbox, NULL);
16218#endif
16219 free_vm_users();
16220 free_vm_zones();
16221 return res;
16222}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7716
void ast_vm_greeter_unregister(const char *module_name)
Unregister the specified voicemail greeter provider.
Definition main/app.c:511
void ast_vm_unregister(const char *module_name)
Unregister the specified voicemail provider.
Definition main/app.c:400
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * module_name
The name of the module that provides the voicemail functionality.
const char * module_name
The name of the module that provides the voicemail greeter functionality.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128

References alias_mailbox_mappings, ao2_cleanup, ao2_container_unregister(), ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_manager_unregister(), ast_mwi_state_callback_all(), AST_PTHREADT_NULL, ast_taskprocessor_unreference(), AST_TEST_UNREGISTER, ast_unload_realtime(), ast_unregister_application(), ast_vm_greeter_unregister(), ast_vm_unregister(), cli_voicemail, free_vm_users(), free_vm_zones(), inprocess_container, mailbox_alias_mappings, ast_vm_functions::module_name, ast_vm_greeter_functions::module_name, mwi_subscription_tps, NULL, playmsg_app, poll_thread, sayname_app, stop_poll_thread(), vm_greeter_table, vm_info_acf, vm_table, vmauthenticate_app, voicemail_app, and voicemailmain_app.

Referenced by load_module().

◆ valid_config()

static int valid_config ( const struct ast_config cfg)
inlinestatic

Check if configuration file is valid.

Definition at line 2081 of file app_voicemail.c.

2082{
2083 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
2084}

References CONFIG_STATUS_FILEINVALID.

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

◆ vm_allocate_dh()

static int vm_allocate_dh ( struct vm_state vms,
struct ast_vm_user vmu,
int  count_msg 
)
static

Definition at line 2293 of file app_voicemail.c.

2293 {
2294
2295 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
2296
2297 /* remove old allocation */
2298 if (vms->deleted) {
2299 ast_free(vms->deleted);
2300 vms->deleted = NULL;
2301 }
2302 if (vms->heard) {
2303 ast_free(vms->heard);
2304 vms->heard = NULL;
2305 }
2306 vms->dh_arraysize = 0;
2307
2308 if (arraysize > 0) {
2309 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
2310 return -1;
2311 }
2312 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
2313 ast_free(vms->deleted);
2314 vms->deleted = NULL;
2315 return -1;
2316 }
2317 vms->dh_arraysize = arraysize;
2318 }
2319
2320 return 0;
2321}

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

Referenced by open_mailbox().

◆ vm_authenticate()

static int vm_authenticate ( struct ast_channel chan,
char *  mailbox,
int  mailbox_size,
struct ast_vm_user res_vmu,
const char *  context,
const char *  prefix,
int  skipuser,
int  max_logins,
int  silent 
)
static

Definition at line 11716 of file app_voicemail.c.

11719{
11720 int useadsi = 0, valid = 0, logretries = 0;
11721 char password[AST_MAX_EXTENSION], *passptr = NULL;
11722 struct ast_vm_user vmus, *vmu = NULL;
11723
11724 /* If ADSI is supported, setup login screen */
11725 adsi_begin(chan, &useadsi);
11726 if (!skipuser && useadsi)
11727 adsi_login(chan);
11728 if (!silent && !skipuser && ast_streamfile(chan, vm_login, ast_channel_language(chan))) {
11729 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
11730 return -1;
11731 }
11732
11733 /* Authenticate them and get their mailbox/password */
11734
11735 while (!valid && (logretries < max_logins)) {
11736 /* Prompt for, and read in the username */
11737 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
11738 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
11739 return -1;
11740 }
11741 if (ast_strlen_zero(mailbox)) {
11742 if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
11743 ast_copy_string(mailbox, ast_channel_caller(chan)->id.number.str, mailbox_size);
11744 } else {
11745 ast_verb(3, "Username not entered\n");
11746 return -1;
11747 }
11748 } else if (mailbox[0] == '*') {
11749 /* user entered '*' */
11750 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
11751 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
11752 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11753 return -1;
11754 }
11755 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
11756 mailbox[0] = '\0';
11757 }
11758
11759 if (useadsi)
11760 adsi_password(chan);
11761
11762 if (!ast_strlen_zero(prefix)) {
11763 char fullusername[80];
11764
11765 ast_copy_string(fullusername, prefix, sizeof(fullusername));
11766 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
11767 ast_copy_string(mailbox, fullusername, mailbox_size);
11768 }
11769
11770 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
11771 memset(&vmus, 0, sizeof(vmus));
11772 vmu = find_user(&vmus, context, mailbox);
11773 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
11774 /* saved password is blank, so don't bother asking */
11775 password[0] = '\0';
11776 } else {
11778 if (!ast_check_hangup(chan)) {
11779 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
11780 }
11781 free_user(vmu);
11782 return -1;
11783 }
11784 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
11785 ast_log(AST_LOG_NOTICE, "Unable to read password\n");
11786 free_user(vmu);
11787 return -1;
11788 } else if (password[0] == '*') {
11789 /* user entered '*' */
11790 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
11791 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
11792 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11793 mailbox[0] = '*';
11794 free_user(vmu);
11795 return -1;
11796 }
11797 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
11798 mailbox[0] = '\0';
11799 /* if the password entered was '*', do not let a user mailbox be created if the extension 'a' is not defined */
11800 free_user(vmu);
11801 vmu = NULL;
11802 }
11803 }
11804
11805 if (vmu) {
11806 passptr = vmu->password;
11807 if (passptr[0] == '-') passptr++;
11808 }
11809 if (vmu && !strcmp(passptr, password))
11810 valid++;
11811 else {
11812 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
11813 if (!ast_strlen_zero(prefix))
11814 mailbox[0] = '\0';
11815 }
11816 logretries++;
11817 if (!valid) {
11818 if (skipuser || logretries >= max_logins) {
11819 if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) {
11820 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
11821 free_user(vmu);
11822 return -1;
11823 }
11824 if (ast_waitstream(chan, "")) { /* Channel is hung up */
11825 free_user(vmu);
11826 return -1;
11827 }
11828 } else {
11829 if (useadsi)
11830 adsi_login(chan);
11831 if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) {
11832 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
11833 free_user(vmu);
11834 return -1;
11835 }
11836 }
11837 }
11838 }
11839 if (!valid && (logretries >= max_logins)) {
11840 ast_stopstream(chan);
11841 ast_play_and_wait(chan, "vm-goodbye");
11842 free_user(vmu);
11843 return -1;
11844 }
11845 if (vmu && !skipuser) {
11846 *res_vmu = *vmu;
11847 }
11848 return 0;
11849}
static void adsi_password(struct ast_channel *chan)
static void adsi_begin(struct ast_channel *chan, int *useadsi)
static void adsi_login(struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:446
static char prefix[MAX_PREFIX]
Definition http.c:145

References adsi_begin(), adsi_login(), adsi_password(), ast_channel_caller(), ast_channel_context(), ast_channel_language(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_log, AST_LOG_NOTICE, AST_LOG_WARNING, AST_MAX_EXTENSION, ast_play_and_wait(), ast_readstring(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), ast_vm_user::context, find_user(), free_user(), ast_vm_user::mailbox, NULL, ast_vm_user::password, prefix, S_COR, vm_login, and vm_password.

Referenced by vm_execmain(), and vmauthenticate().

◆ vm_browse_messages()

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

11694{
11695 if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH */
11696 return vm_browse_messages_es(chan, vms, vmu);
11697 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK */
11698 return vm_browse_messages_gr(chan, vms, vmu);
11699 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW */
11700 return vm_browse_messages_he(chan, vms, vmu);
11701 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN */
11702 return vm_browse_messages_it(chan, vms, vmu);
11703 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE */
11704 return vm_browse_messages_ja(chan, vms, vmu);
11705 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE */
11706 return vm_browse_messages_pt(chan, vms, vmu);
11707 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE */
11708 return vm_browse_messages_vi(chan, vms, vmu);
11709 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) */
11710 return vm_browse_messages_zh(chan, vms, vmu);
11711 } else { /* Default to English syntax */
11712 return vm_browse_messages_en(chan, vms, vmu);
11713 }
11714}
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_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_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_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_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_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_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
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.

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

Referenced by vm_execmain().

◆ vm_browse_messages_en()

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

11506{
11507 int cmd = 0;
11508
11509 if (vms->lastmsg > -1) {
11510 cmd = play_message(chan, vmu, vms);
11511 } else {
11512 cmd = ast_play_and_wait(chan, "vm-youhave");
11513 if (!cmd)
11514 cmd = ast_play_and_wait(chan, "vm-no");
11515 if (!cmd) {
11516 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11517 cmd = ast_play_and_wait(chan, vms->fn);
11518 }
11519 if (!cmd)
11520 cmd = ast_play_and_wait(chan, "vm-messages");
11521 }
11522 return cmd;
11523}
static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_es()

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

11587{
11588 int cmd;
11589
11590 if (vms->lastmsg > -1) {
11591 cmd = play_message(chan, vmu, vms);
11592 } else {
11593 cmd = ast_play_and_wait(chan, "vm-youhaveno");
11594 if (!cmd)
11595 cmd = ast_play_and_wait(chan, "vm-messages");
11596 if (!cmd) {
11597 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11598 cmd = ast_play_and_wait(chan, vms->fn);
11599 }
11600 }
11601 return cmd;
11602}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_gr()

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

11454{
11455 int cmd = 0;
11456
11457 if (vms->lastmsg > -1) {
11458 cmd = play_message(chan, vmu, vms);
11459 } else {
11460 cmd = ast_play_and_wait(chan, "vm-youhaveno");
11461 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
11462 if (!cmd) {
11463 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
11464 cmd = ast_play_and_wait(chan, vms->fn);
11465 }
11466 if (!cmd)
11467 cmd = ast_play_and_wait(chan, "vm-messages");
11468 } else {
11469 if (!cmd)
11470 cmd = ast_play_and_wait(chan, "vm-messages");
11471 if (!cmd) {
11472 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11473 cmd = ast_play_and_wait(chan, vms->fn);
11474 }
11475 }
11476 }
11477 return cmd;
11478}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_he()

static int vm_browse_messages_he ( struct ast_channel chan,
struct vm_state vms,
struct ast_vm_user vmu 
)
static

Definition at line 11481 of file app_voicemail.c.

11482{
11483 int cmd = 0;
11484
11485 if (vms->lastmsg > -1) {
11486 cmd = play_message(chan, vmu, vms);
11487 } else {
11488 if (!strcasecmp(vms->fn, "INBOX")) {
11489 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
11490 } else {
11491 cmd = ast_play_and_wait(chan, "vm-nomessages");
11492 }
11493 }
11494 return cmd;
11495}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_it()

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

11534{
11535 int cmd;
11536
11537 if (vms->lastmsg > -1) {
11538 cmd = play_message(chan, vmu, vms);
11539 } else {
11540 cmd = ast_play_and_wait(chan, "vm-no");
11541 if (!cmd)
11542 cmd = ast_play_and_wait(chan, "vm-message");
11543 if (!cmd) {
11544 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11545 cmd = ast_play_and_wait(chan, vms->fn);
11546 }
11547 }
11548 return cmd;
11549}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_ja()

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

11560{
11561 int cmd = 0;
11562
11563 if (vms->lastmsg > -1) {
11564 cmd = play_message(chan, vmu, vms);
11565 } else {
11566 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11567 cmd = ast_play_and_wait(chan, vms->fn);
11568 if (!cmd)
11569 cmd = ast_play_and_wait(chan, "vm-messages");
11570 if (!cmd)
11571 cmd = ast_play_and_wait(chan, "jp-wa");
11572 if (!cmd)
11573 cmd = ast_play_and_wait(chan, "jp-arimasen");
11574 }
11575 return cmd;
11576}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_pt()

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

11613{
11614 int cmd;
11615
11616 if (vms->lastmsg > -1) {
11617 cmd = play_message(chan, vmu, vms);
11618 } else {
11619 cmd = ast_play_and_wait(chan, "vm-no");
11620 if (!cmd) {
11621 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11622 cmd = ast_play_and_wait(chan, vms->fn);
11623 }
11624 if (!cmd)
11625 cmd = ast_play_and_wait(chan, "vm-messages");
11626 }
11627 return cmd;
11628}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_vi()

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

11667{
11668 int cmd = 0;
11669
11670 if (vms->lastmsg > -1) {
11671 cmd = play_message(chan, vmu, vms);
11672 } else {
11673 cmd = ast_play_and_wait(chan, "vm-no");
11674 if (!cmd) {
11675 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11676 cmd = ast_play_and_wait(chan, vms->fn);
11677 }
11678 }
11679 return cmd;
11680}

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

Referenced by vm_browse_messages().

◆ vm_browse_messages_zh()

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

11639{
11640 int cmd;
11641
11642 if (vms->lastmsg > -1) {
11643 cmd = play_message(chan, vmu, vms);
11644 } else {
11645 cmd = ast_play_and_wait(chan, "vm-you");
11646 if (!cmd)
11647 cmd = ast_play_and_wait(chan, "vm-haveno");
11648 if (!cmd)
11649 cmd = ast_play_and_wait(chan, "vm-messages");
11650 if (!cmd) {
11651 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11652 cmd = ast_play_and_wait(chan, vms->fn);
11653 }
11654 }
11655 return cmd;
11656}

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

Referenced by vm_browse_messages().

◆ vm_change_password()

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

2094{
2095 struct ast_config *cfg = NULL;
2096 struct ast_category *cat = NULL;
2097 char *category = NULL;
2098 const char *tmp = NULL;
2099 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
2100 char secretfn[PATH_MAX] = "";
2101 int found = 0;
2102
2103 if (!change_password_realtime(vmu, newpassword))
2104 return;
2105
2106 /* check if we should store the secret in the spool directory next to the messages */
2107 switch (vmu->passwordlocation) {
2108 case OPT_PWLOC_SPOOLDIR:
2109 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
2110 if (write_password_to_file(secretfn, newpassword) == 0) {
2111 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
2112 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
2113 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2114 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2115 break;
2116 } else {
2117 ast_log(LOG_WARNING, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2118 }
2119 /* Fall-through */
2121 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
2122 while ((category = ast_category_browse(cfg, category))) {
2123 if (!strcasecmp(category, vmu->context)) {
2124 const char *value = NULL;
2125 char *new = NULL;
2126 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
2127 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
2128 break;
2129 }
2130 value = strstr(tmp, ",");
2131 if (!value) {
2132 new = ast_malloc(strlen(newpassword) + 1);
2133 sprintf(new, "%s", newpassword);
2134 } else {
2135 new = ast_malloc((strlen(value) + strlen(newpassword) + 1));
2136 sprintf(new, "%s%s", newpassword, value);
2137 }
2138 if (!(cat = ast_category_get(cfg, category, NULL))) {
2139 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
2140 ast_free(new);
2141 break;
2142 }
2143 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
2144 found = 1;
2145 ast_free(new);
2146 }
2147 }
2148 /* save the results */
2149 if (found) {
2150 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2151 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2152 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2153 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "app_voicemail");
2154 ast_config_destroy(cfg);
2155 break;
2156 }
2157
2158 ast_config_destroy(cfg);
2159 }
2160 break;
2161 }
2162}
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
Performs a change of the voicemail password in the realtime engine.
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
Resets a user password to a specified password.
static int write_password_to_file(const char *secretfn, const char *password)
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.
@ CONFIG_FLAG_WITHCOMMENTS

References ast_category_browse(), ast_category_get(), ast_config_destroy(), ast_config_load, ast_config_text_file_save(), ast_copy_string(), ast_free, ast_log, AST_LOG_WARNING, ast_malloc, ast_test_suite_event_notify, ast_variable_retrieve(), ast_variable_update(), ast_verb, change_password_realtime(), CONFIG_FLAG_WITHCOMMENTS, ast_vm_user::context, LOG_WARNING, ast_vm_user::mailbox, NULL, OPT_PWLOC_SPOOLDIR, OPT_PWLOC_VOICEMAILCONF, ast_vm_user::password, ast_vm_user::passwordlocation, PATH_MAX, reset_user_pw(), valid_config(), value, VM_SPOOL_DIR, VOICEMAIL_CONFIG, and write_password_to_file().

Referenced by vm_newuser_setup(), and vm_options().

◆ vm_change_password_shell()

static void vm_change_password_shell ( struct ast_vm_user vmu,
char *  newpassword 
)
static

Definition at line 2164 of file app_voicemail.c.

2165{
2166 char buf[255];
2167 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
2168 ast_debug(1, "External password: %s\n",buf);
2169 if (!ast_safe_system(buf)) {
2170 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
2171 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
2172 /* Reset the password in memory, too */
2173 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
2174 }
2175}

References ast_copy_string(), ast_debug, ast_safe_system(), ast_test_suite_event_notify, buf, ast_vm_user::context, ext_pass_cmd, ast_vm_user::mailbox, ast_vm_user::password, and reset_user_pw().

Referenced by vm_newuser_setup(), and vm_options().

◆ vm_check_password_shell()

static char * vm_check_password_shell ( char *  command,
char *  buf,
size_t  len 
)
static

Definition at line 1711 of file app_voicemail.c.

1712{
1713 int fds[2], pid = 0;
1714
1715 memset(buf, 0, len);
1716
1717 if (pipe(fds)) {
1718 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
1719 } else {
1720 /* good to go*/
1721 pid = ast_safe_fork(0);
1722
1723 if (pid < 0) {
1724 /* ok maybe not */
1725 close(fds[0]);
1726 close(fds[1]);
1727 snprintf(buf, len, "FAILURE: Fork failed");
1728 } else if (pid) {
1729 /* parent */
1730 close(fds[1]);
1731 if (read(fds[0], buf, len) < 0) {
1732 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
1733 }
1734 close(fds[0]);
1735 } else {
1736 /* child */
1738 AST_APP_ARG(v)[20];
1739 );
1740 char *mycmd = ast_strdupa(command);
1741
1742 close(fds[0]);
1743 dup2(fds[1], STDOUT_FILENO);
1744 close(fds[1]);
1745 ast_close_fds_above_n(STDOUT_FILENO);
1746
1747 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
1748
1749 execv(arg.v[0], arg.v);
1750 printf("FAILURE: %s", strerror(errno));
1751 _exit(0);
1752 }
1753 }
1754 return buf;
1755}
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child.
Definition main/app.c:3208
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition main/app.c:3203

References AST_APP_ARG, ast_close_fds_above_n(), AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_APP_ARGS, ast_safe_fork(), ast_strdupa, buf, errno, len(), and LOG_WARNING.

Referenced by check_password().

◆ vm_delete()

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

5223{
5224 char *txt;
5225 int txtsize = 0;
5226 int res = 0;
5227 SCOPE_ENTER(3, "file: %s\n", file);
5228
5229 txtsize = (strlen(file) + 5)*sizeof(char);
5230 txt = ast_alloca(txtsize);
5231 /* Sprintf here would safe because we alloca'd exactly the right length,
5232 * but trying to eliminate all sprintf's anyhow
5233 */
5234 if (ast_check_realtime("voicemail_data")) {
5235 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
5236 }
5237 snprintf(txt, txtsize, "%s.txt", file);
5238 ast_trace(-1, "unlinking '%s'\n", txt);
5239 unlink(txt);
5240 ast_trace(-1, "deleting sound files '%s'\n", file);
5241 res = ast_filedelete(file, NULL);
5242 SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d\n", res);
5243}

References ast_alloca, ast_check_realtime(), ast_destroy_realtime(), ast_filedelete(), ast_trace, ast_variable::file, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and SENTINEL.

Referenced by copy_message(), and notify_new_message().

◆ vm_exec()

static int vm_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 13205 of file app_voicemail.c.

13206{
13207 int res = 0;
13208 char *tmp;
13209 struct leave_vm_options leave_options;
13210 struct ast_flags flags = { 0 };
13211 char *opts[OPT_ARG_ARRAY_SIZE];
13213 AST_APP_ARG(argv0);
13214 AST_APP_ARG(argv1);
13215 );
13216 SCOPE_ENTER(3, "%s\n", ast_channel_name(chan));
13217
13218 memset(&leave_options, 0, sizeof(leave_options));
13219
13220 if (!ast_strlen_zero(data)) {
13221 tmp = ast_strdupa(data);
13223 if (args.argc == 2) {
13224 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
13225 SCOPE_EXIT_RTN_VALUE(-1, "parse options failed for '%s'\n", args.argv1);
13226 }
13229 int gain;
13230
13231 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
13232 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
13233 } else {
13234 leave_options.record_gain = (signed char) gain;
13235 }
13236 }
13239 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
13240 }
13241 }
13242 if (ast_test_flag(&flags, OPT_BEEP)) { /* Use custom beep (or none at all) */
13243 leave_options.beeptone = opts[OPT_ARG_BEEP_TONE];
13244 } else { /* Use default beep */
13245 leave_options.beeptone = "beep";
13246 }
13247 } else {
13248 char temp[256];
13249 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
13250 if (res < 0) {
13251 SCOPE_EXIT_RTN_VALUE(res, "getdata failed. RC: %d", res);
13252 }
13253 if (ast_strlen_zero(temp)) {
13255 }
13256 args.argv0 = ast_strdupa(temp);
13257 }
13258
13259 if (ast_channel_state(chan) != AST_STATE_UP) {
13262 } else {
13263 ast_answer(chan);
13264 }
13265 }
13266
13267 res = SCOPE_CALL_WITH_INT_RESULT(-1, leave_voicemail, chan, args.argv0, &leave_options);
13268 if (res == 't') {
13269 ast_play_and_wait(chan, "vm-goodbye");
13270 res = 0;
13271 }
13272
13273 if (res == OPERATOR_EXIT) {
13274 res = 0;
13275 }
13276
13277 if (res == ERROR_LOCK_PATH) {
13278 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
13279 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
13280 res = 0;
13281 }
13282
13283 SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d", res);
13284}
static const struct ast_app_option vm_app_options[128]
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition channel.c:4332
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition main/app.c:188
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3067
@ AST_CONTROL_PROGRESS
unsigned int flags
Definition utils.h:221

References args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_channel_name(), AST_CONTROL_PROGRESS, ast_copy_flags, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log, AST_LOG_ERROR, AST_LOG_WARNING, ast_play_and_wait(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, leave_vm_options::beeptone, ERROR_LOCK_PATH, leave_vm_options::exitcontext, ast_flags::flags, leave_voicemail(), OPERATOR_EXIT, OPT_ARG_ARRAY_SIZE, OPT_ARG_BEEP_TONE, OPT_ARG_DTMFEXIT, OPT_ARG_RECORDGAIN, OPT_BEEP, OPT_BUSY_GREETING, OPT_DTMFEXIT, OPT_EARLYM_GREETING, OPT_MESSAGE_PRIORITY, OPT_MESSAGE_Urgent, OPT_RECORDGAIN, OPT_SILENT, OPT_SILENT_IF_GREET, OPT_UNAVAIL_GREETING, pbx_builtin_setvar_helper(), leave_vm_options::record_gain, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and vm_app_options.

Referenced by load_module(), and play_record_review().

◆ vm_execmain()

static int vm_execmain ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 12374 of file app_voicemail.c.

12375{
12376 /* XXX This is, admittedly, some pretty horrendous code. For some
12377 reason it just seemed a lot easier to do with GOTO's. I feel
12378 like I'm back in my GWBASIC days. XXX */
12379 int res = -1;
12380 int cmd = 0;
12381 int valid = 0;
12382 char prefixstr[80] ="";
12383 char ext_context[256]="";
12384 int box;
12385 int useadsi = 0;
12386 int skipuser = 0;
12387 struct vm_state vms = {{0}};
12388 struct ast_vm_user *vmu = NULL, vmus = {{0}};
12389 char *context = NULL;
12390 int silentexit = 0;
12391 struct ast_flags flags = { 0 };
12392 signed char record_gain = 0;
12393 int play_auto = 0;
12394 int play_folder = 0;
12395 int in_urgent = 0;
12396 int nodelete = 0;
12397#ifdef IMAP_STORAGE
12398 int deleted = 0;
12399#endif
12400 SCOPE_ENTER(3, "%s:\n", ast_channel_name(chan));
12401
12402 /* Add the vm_state to the active list and keep it active */
12403 vms.lastmsg = -1;
12404
12405 ast_test_suite_event_notify("START", "Message: vm_execmain started");
12406 if (ast_channel_state(chan) != AST_STATE_UP) {
12407 ast_debug(1, "Before ast_answer\n");
12408 ast_answer(chan);
12409 }
12410
12411 if (!ast_strlen_zero(data)) {
12412 char *opts[OPT_ARG_ARRAY_SIZE];
12413 char *parse;
12415 AST_APP_ARG(argv0);
12416 AST_APP_ARG(argv1);
12417 );
12418
12419 parse = ast_strdupa(data);
12420
12422
12423 if (args.argc == 2) {
12424 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
12425 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING, "Invalid option string '%s'\n", args.argv1);
12426 }
12428 int gain;
12429 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
12430 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
12431 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
12432 } else {
12433 record_gain = (signed char) gain;
12434 }
12435 } else {
12436 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
12437 }
12438 }
12440 play_auto = 1;
12441 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
12442 /* See if it is a folder name first */
12443 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
12444 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
12445 play_folder = -1;
12446 }
12447 } else {
12448 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
12449 }
12450 } else {
12451 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
12452 }
12453 if (play_folder > 9 || play_folder < 0) {
12455 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
12456 opts[OPT_ARG_PLAYFOLDER]);
12457 play_folder = 0;
12458 }
12459 }
12461 nodelete = 1;
12462 }
12463 } else {
12464 /* old style options parsing */
12465 while (*(args.argv0)) {
12466 if (*(args.argv0) == 's')
12468 else if (*(args.argv0) == 'p')
12470 else
12471 break;
12472 (args.argv0)++;
12473 }
12474
12475 }
12476
12477 valid = ast_test_flag(&flags, OPT_SILENT);
12478
12479 if ((context = strchr(args.argv0, '@')))
12480 *context++ = '\0';
12481
12483 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
12484 else
12485 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
12486
12487 if (!ast_strlen_zero(vms.username)) {
12488 if ((vmu = find_user(&vmus, context ,vms.username))) {
12489 skipuser++;
12490 } else {
12491 ast_log(LOG_WARNING, "Mailbox '%s%s%s' doesn't exist\n", vms.username, context ? "@": "", context ? context : "");
12492 valid = 0;
12493 }
12494 } else {
12495 valid = 0;
12496 }
12497 }
12498
12499 if (!valid)
12500 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
12501
12502 ast_trace(-1, "vm_authenticate user: %s\n", vms.username);
12503
12504 if (vms.username[0] == '*') {
12505 ast_trace(-1, "user pressed * in context '%s'\n", ast_channel_context(chan));
12506
12507 /* user entered '*' */
12508 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
12509 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
12510 res = 0; /* prevent hangup */
12511 goto out;
12512 }
12513 }
12514
12515 if (!res) {
12516 valid = 1;
12517 if (!skipuser)
12518 vmu = &vmus;
12519 } else {
12520 res = 0;
12521 }
12522
12523 /* If ADSI is supported, setup login screen */
12524 adsi_begin(chan, &useadsi);
12525
12526 if (!valid) {
12527 ast_trace(-1, "Invalid user\n");
12528 goto out;
12529 }
12530 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
12531
12532#ifdef IMAP_STORAGE
12533 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
12534 pthread_setspecific(ts_vmstate.key, &vms);
12535
12536 vms.interactive = 1;
12537 vms.updated = 1;
12538 if (vmu)
12539 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
12540 vmstate_insert(&vms);
12541 init_vm_state(&vms);
12542#endif
12543
12544 /* Set language from config to override channel language */
12545 if (!ast_strlen_zero(vmu->language)) {
12546 ast_channel_lock(chan);
12547 ast_channel_language_set(chan, vmu->language);
12548 ast_channel_unlock(chan);
12549 }
12550
12551 /* Retrieve urgent, old and new message counts */
12552 ast_trace(-1, "Before open_mailbox\n");
12553 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
12554 if (res < 0) {
12555 ast_trace(-1, "open mailbox: %d\n", res);
12556 goto out;
12557 }
12558 vms.oldmessages = vms.lastmsg + 1;
12559 ast_trace(-1, "Number of old messages: %d\n", vms.oldmessages);
12560 /* check INBOX */
12561 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12562 if (res < 0) {
12563 ast_trace(-1, "open mailbox: %d\n", res);
12564 goto out;
12565 }
12566 vms.newmessages = vms.lastmsg + 1;
12567 ast_trace(-1, "Number of new messages: %d\n", vms.newmessages);
12568 /* Start in Urgent */
12569 in_urgent = 1;
12570 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11); /*11 is the Urgent folder */
12571 if (res < 0) {
12572 ast_trace(-1, "open mailbox: %d\n", res);
12573 goto out;
12574 }
12575 vms.urgentmessages = vms.lastmsg + 1;
12576 ast_trace(-1, "Number of urgent messages: %d\n", vms.urgentmessages);
12577
12578 /* Select proper mailbox FIRST!! */
12579 if (play_auto) {
12580 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
12581 if (vms.urgentmessages) {
12582 in_urgent = 1;
12583 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11);
12584 } else {
12585 in_urgent = 0;
12586 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, play_folder);
12587 }
12588 if (res < 0) {
12589 ast_trace(-1, "open mailbox: %d\n", res);
12590 goto out;
12591 }
12592
12593 /* If there are no new messages, inform the user and hangup */
12594 if (vms.lastmsg == -1) {
12595 in_urgent = 0;
12596 cmd = vm_browse_messages(chan, &vms, vmu);
12597 res = 0;
12598 goto out;
12599 }
12600 } else {
12601 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
12602 /* If we only have old messages start here */
12603 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
12604 in_urgent = 0;
12605 play_folder = 1;
12606 if (res < 0)
12607 goto out;
12608 } else if (!vms.urgentmessages && vms.newmessages) {
12609 /* If we have new messages but none are urgent */
12610 in_urgent = 0;
12611 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12612 if (res < 0)
12613 goto out;
12614 }
12615 }
12616
12617 if (useadsi)
12618 adsi_status(chan, &vms);
12619 res = 0;
12620
12621 /* Check to see if this is a new user */
12622 if (!strcasecmp(vmu->mailbox, vmu->password) &&
12624 if (ast_play_and_wait(chan, vm_newuser) == -1)
12625 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
12626 cmd = vm_newuser_setup(chan, vmu, &vms, vmfmts, record_gain);
12627 if ((cmd == 't') || (cmd == '#')) {
12628 /* Timeout */
12629 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
12630 res = 0;
12631 ast_trace(-1, "Timeout\n");
12632 goto out;
12633 } else if (cmd < 0) {
12634 /* Hangup */
12635 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
12636 res = -1;
12637 ast_trace(-1, "Hangup\n");
12638 goto out;
12639 }
12640 }
12641#ifdef IMAP_STORAGE
12642 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
12643 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
12644 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
12645 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
12646 }
12647 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
12648 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
12649 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
12650 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
12651 }
12652#endif
12653
12654 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
12655 if (play_auto) {
12656 cmd = '1';
12657 } else {
12658 cmd = vm_intro(chan, vmu, &vms);
12659 }
12660 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
12661 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
12662
12663 vms.repeats = 0;
12664 vms.starting = 1;
12665 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
12666 /* Run main menu */
12667 ast_trace(-1, "Main menu: %d %c\n", cmd, (cmd >= 32 && cmd <= 126 ? cmd : ' '));
12668 switch (cmd) {
12669 case '1': /* First message */
12670 vms.curmsg = 0;
12671 /* Fall through */
12672 case '5': /* Play current message */
12673 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
12674 cmd = vm_browse_messages(chan, &vms, vmu);
12675 break;
12676 case '2': /* Change folders */
12677 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
12678 if (useadsi)
12679 adsi_folders(chan, 0, "Change to folder...");
12680
12681 cmd = get_folder2(chan, "vm-changeto", 0);
12682 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
12683 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
12684 if (cmd == '#') {
12685 cmd = 0;
12686 } else if (cmd > 0) {
12687 cmd = cmd - '0';
12688 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12689 if (res == ERROR_LOCK_PATH) {
12690 ast_trace(-1, "close mailbox: %d\n", res);
12691 goto out;
12692 }
12693 /* If folder is not urgent, set in_urgent to zero! */
12694 if (cmd != 11) in_urgent = 0;
12695 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, cmd);
12696 if (res < 0) {
12697 ast_trace(-1, "open mailbox: %d\n", res);
12698 goto out;
12699 }
12700 play_folder = cmd;
12701 cmd = 0;
12702 }
12703 if (useadsi)
12704 adsi_status2(chan, &vms);
12705
12706 if (!cmd) {
12707 cmd = vm_play_folder_name(chan, vms.vmbox);
12708 }
12709
12710 vms.starting = 1;
12711 vms.curmsg = 0;
12712 break;
12713 case '3': /* Advanced options */
12714 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
12715 cmd = 0;
12716 vms.repeats = 0;
12717 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
12718 switch (cmd) {
12719 case '1': /* Reply */
12720 if (vms.lastmsg > -1 && !vms.starting) {
12721 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
12722 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
12723 res = cmd;
12724 ast_trace(-1, "advanced options: %d\n", cmd);
12725 goto out;
12726 }
12727 } else {
12728 cmd = ast_play_and_wait(chan, "vm-sorry");
12729 }
12730 cmd = 't';
12731 break;
12732 case '2': /* Callback */
12733 if (!vms.starting)
12734 ast_verb(3, "Callback Requested\n");
12735 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
12736 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
12737 ast_trace(-1, "advanced options: %d\n", cmd);
12738 if (cmd == 9) {
12739 silentexit = 1;
12740 goto out;
12741 } else if (cmd == ERROR_LOCK_PATH) {
12742 res = cmd;
12743 goto out;
12744 }
12745 } else {
12746 cmd = ast_play_and_wait(chan, "vm-sorry");
12747 }
12748 cmd = 't';
12749 break;
12750 case '3': /* Envelope */
12751 if (vms.lastmsg > -1 && !vms.starting) {
12752 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
12753 if (cmd == ERROR_LOCK_PATH) {
12754 res = cmd;
12755 ast_trace(-1, "advanced options: %d\n", cmd);
12756 goto out;
12757 }
12758 } else {
12759 cmd = ast_play_and_wait(chan, "vm-sorry");
12760 }
12761 cmd = 't';
12762 break;
12763 case '4': /* Dialout */
12764 if (!ast_strlen_zero(vmu->dialout)) {
12765 cmd = dialout(chan, vmu, NULL, vmu->dialout);
12766 if (cmd == 9) {
12767 silentexit = 1;
12768 ast_trace(-1, "dialout: %d\n", cmd);
12769 goto out;
12770 }
12771 } else {
12772 cmd = ast_play_and_wait(chan, "vm-sorry");
12773 }
12774 cmd = 't';
12775 break;
12776
12777 case '5': /* Leave VoiceMail */
12778 if (ast_test_flag(vmu, VM_SVMAIL)) {
12779 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, forward_message, chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
12780 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
12781 res = cmd;
12782 ast_trace(-1, "forward message: %d\n", cmd);
12783 goto out;
12784 }
12785 } else {
12786 cmd = ast_play_and_wait(chan, "vm-sorry");
12787 }
12788 cmd = 't';
12789 break;
12790
12791 case '*': /* Return to main menu */
12792 cmd = 't';
12793 break;
12794
12795 default:
12796 cmd = 0;
12797 if (!vms.starting) {
12798 cmd = ast_play_and_wait(chan, "vm-toreply");
12799 }
12800 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
12801 cmd = ast_play_and_wait(chan, "vm-tocallback");
12802 }
12803 if (!cmd && !vms.starting) {
12804 cmd = ast_play_and_wait(chan, "vm-tohearenv");
12805 }
12806 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
12807 cmd = ast_play_and_wait(chan, "vm-tomakecall");
12808 }
12809 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
12810 cmd = ast_play_and_wait(chan, "vm-leavemsg");
12811 }
12812 if (!cmd) {
12813 cmd = ast_play_and_wait(chan, "vm-starmain");
12814 }
12815 if (!cmd) {
12816 cmd = ast_waitfordigit(chan, 6000);
12817 }
12818 if (!cmd) {
12819 vms.repeats++;
12820 }
12821 if (vms.repeats > 3) {
12822 cmd = 't';
12823 }
12824 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
12825 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
12826 }
12827 }
12828 if (cmd == 't') {
12829 cmd = 0;
12830 vms.repeats = 0;
12831 }
12832 break;
12833 case '4': /* Go to the previous message */
12834 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
12835 if (vms.curmsg > 0) {
12836 vms.curmsg--;
12837 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12838 } else {
12839 /* Check if we were listening to new
12840 messages. If so, go to Urgent messages
12841 instead of saying "no more messages"
12842 */
12843 if (in_urgent == 0 && vms.urgentmessages > 0) {
12844 /* Check for Urgent messages */
12845 in_urgent = 1;
12846 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12847 if (res == ERROR_LOCK_PATH) {
12848 ast_trace(-1, "close mailbox: %d\n", res);
12849 goto out;
12850 }
12851 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11); /* Open Urgent folder */
12852 if (res < 0) {
12853 ast_trace(-1, "open mailbox: %d\n", res);
12854 goto out;
12855 }
12856 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
12857 vms.curmsg = vms.lastmsg;
12858 if (vms.lastmsg < 0) {
12859 cmd = ast_play_and_wait(chan, "vm-nomore");
12860 }
12861 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12862 vms.curmsg = vms.lastmsg;
12863 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12864 } else {
12865 cmd = ast_play_and_wait(chan, "vm-nomore");
12866 }
12867 }
12868 break;
12869 case '6': /* Go to the next message */
12870 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
12871 if (vms.curmsg < vms.lastmsg) {
12872 vms.curmsg++;
12873 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12874 } else {
12875 if (in_urgent && vms.newmessages > 0) {
12876 /* Check if we were listening to urgent
12877 * messages. If so, go to regular new messages
12878 * instead of saying "no more messages"
12879 */
12880 in_urgent = 0;
12881 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12882 if (res == ERROR_LOCK_PATH) {
12883 ast_trace(-1, "close mailbox: %d\n", res);
12884 goto out;
12885 }
12886 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12887 if (res < 0) {
12888 ast_trace(-1, "open mailbox: %d\n", res);
12889 goto out;
12890 }
12891 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
12892 vms.curmsg = -1;
12893 if (vms.lastmsg < 0) {
12894 cmd = ast_play_and_wait(chan, "vm-nomore");
12895 }
12896 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12897 vms.curmsg = 0;
12898 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12899 } else {
12900 cmd = ast_play_and_wait(chan, "vm-nomore");
12901 }
12902 }
12903 break;
12904 case '7': /* Delete the current message */
12905 if (!nodelete && vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
12906 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
12907 if (useadsi)
12908 adsi_delete(chan, &vms);
12909 if (vms.deleted[vms.curmsg]) {
12910 if (play_folder == 0) {
12911 if (in_urgent) {
12912 vms.urgentmessages--;
12913 } else {
12914 vms.newmessages--;
12915 }
12916 }
12917 else if (play_folder == 1)
12918 vms.oldmessages--;
12919 cmd = ast_play_and_wait(chan, "vm-deleted");
12920 } else {
12921 if (play_folder == 0) {
12922 if (in_urgent) {
12923 vms.urgentmessages++;
12924 } else {
12925 vms.newmessages++;
12926 }
12927 }
12928 else if (play_folder == 1)
12929 vms.oldmessages++;
12930 cmd = ast_play_and_wait(chan, "vm-undeleted");
12931 }
12932 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
12933 if (vms.curmsg < vms.lastmsg) {
12934 vms.curmsg++;
12935 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12936 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12937 vms.curmsg = 0;
12938 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12939 } else {
12940 /* Check if we were listening to urgent
12941 messages. If so, go to regular new messages
12942 instead of saying "no more messages"
12943 */
12944 if (in_urgent == 1) {
12945 /* Check for new messages */
12946 in_urgent = 0;
12947 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12948 if (res == ERROR_LOCK_PATH) {
12949 ast_trace(-1, "close mailbox: %d\n", res);
12950 goto out;
12951 }
12952 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12953 if (res < 0) {
12954 ast_trace(-1, "open mailbox: %d\n", res);
12955 goto out;
12956 }
12957 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
12958 vms.curmsg = -1;
12959 if (vms.lastmsg < 0) {
12960 cmd = ast_play_and_wait(chan, "vm-nomore");
12961 }
12962 } else {
12963 cmd = ast_play_and_wait(chan, "vm-nomore");
12964 }
12965 }
12966 }
12967 } else /* Delete not valid if we haven't selected a message */
12968 cmd = 0;
12969#ifdef IMAP_STORAGE
12970 deleted = 1;
12971#endif
12972 break;
12973
12974 case '8': /* Forward the current message */
12975 if (vms.lastmsg > -1) {
12976 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, forward_message, chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
12977 if (cmd == ERROR_LOCK_PATH) {
12978 res = cmd;
12979 ast_trace(-1, "forward message: %d\n", res);
12980 goto out;
12981 }
12982 } else {
12983 /* Check if we were listening to urgent
12984 messages. If so, go to regular new messages
12985 instead of saying "no more messages"
12986 */
12987 if (in_urgent == 1 && vms.newmessages > 0) {
12988 /* Check for new messages */
12989 in_urgent = 0;
12990 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12991 if (res == ERROR_LOCK_PATH) {
12992 ast_trace(-1, "close mailbox: %d\n", res);
12993 goto out;
12994 }
12995 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12996 if (res < 0) {
12997 ast_trace(-1, "open mailbox: %d\n", res);
12998 goto out;
12999 }
13000 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
13001 vms.curmsg = -1;
13002 if (vms.lastmsg < 0) {
13003 cmd = ast_play_and_wait(chan, "vm-nomore");
13004 }
13005 } else {
13006 cmd = ast_play_and_wait(chan, "vm-nomore");
13007 }
13008 }
13009 break;
13010 case '9': /* Save message to folder */
13011 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
13012 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
13013 /* No message selected */
13014 cmd = 0;
13015 break;
13016 }
13017 if (useadsi)
13018 adsi_folders(chan, 1, "Save to folder...");
13019 cmd = get_folder2(chan, "vm-savefolder", 1);
13020 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
13021 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
13022 box = 0; /* Shut up compiler */
13023 if (cmd == '#') {
13024 cmd = 0;
13025 break;
13026 } else if (cmd > 0) {
13027 box = cmd = cmd - '0';
13028 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, save_to_folder, vmu, &vms, vms.curmsg, cmd, NULL, 0);
13029 if (cmd == ERROR_LOCK_PATH) {
13030 res = cmd;
13031 ast_trace(-1, "save to folder: %d\n", res);
13032 goto out;
13033#ifndef IMAP_STORAGE
13034 } else if (!cmd) {
13035 vms.deleted[vms.curmsg] = 1;
13036#endif
13037 } else {
13038 vms.deleted[vms.curmsg] = 0;
13039 vms.heard[vms.curmsg] = 0;
13040 }
13041 }
13042 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
13043 if (useadsi)
13044 adsi_message(chan, &vms);
13045 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
13046 if (!cmd) {
13047 cmd = ast_play_and_wait(chan, "vm-message");
13048 if (!cmd)
13049 cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
13050 if (!cmd)
13051 cmd = ast_play_and_wait(chan, "vm-savedto");
13052 if (!cmd)
13053 cmd = vm_play_folder_name(chan, vms.fn);
13054 } else {
13055 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
13056 }
13058 if (vms.curmsg < vms.lastmsg) {
13059 vms.curmsg++;
13060 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
13061 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
13062 vms.curmsg = 0;
13063 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
13064 } else {
13065 /* Check if we were listening to urgent
13066 messages. If so, go to regular new messages
13067 instead of saying "no more messages"
13068 */
13069 if (in_urgent == 1 && vms.newmessages > 0) {
13070 /* Check for new messages */
13071 in_urgent = 0;
13072 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
13073 if (res == ERROR_LOCK_PATH) {
13074 ast_trace(-1, "close mailbox: %d\n", res);
13075 goto out;
13076 }
13077 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
13078 if (res < 0) {
13079 ast_trace(-1, "open mailbox: %d\n", res);
13080 goto out;
13081 }
13082 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
13083 vms.curmsg = -1;
13084 if (vms.lastmsg < 0) {
13085 cmd = ast_play_and_wait(chan, "vm-nomore");
13086 }
13087 } else {
13088 cmd = ast_play_and_wait(chan, "vm-nomore");
13089 }
13090 }
13091 }
13092 break;
13093 case '*': /* Help */
13094 if (!vms.starting) {
13095 if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {
13096 cmd = vm_play_folder_name(chan, vms.vmbox);
13097 if (!cmd)
13098 cmd = ast_play_and_wait(chan, "jp-wa");
13099 if (!cmd)
13100 cmd = ast_play_and_wait(chan, "digits/1");
13101 if (!cmd)
13102 cmd = ast_play_and_wait(chan, "jp-wo");
13103 if (!cmd)
13104 cmd = ast_play_and_wait(chan, "silence/1");
13105 if (!cmd)
13106 cmd = ast_play_and_wait(chan, "vm-opts");
13107 if (!cmd)
13108 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent, nodelete);
13109 break;
13110 }
13111 cmd = ast_play_and_wait(chan, "vm-onefor");
13112 if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
13113 cmd = ast_play_and_wait(chan, "vm-for");
13114 }
13115 if (!cmd)
13116 cmd = vm_play_folder_name(chan, vms.vmbox);
13117 if (!cmd)
13118 cmd = ast_play_and_wait(chan, "vm-opts");
13119 if (!cmd)
13120 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent, nodelete);
13121 } else
13122 cmd = 0;
13123 break;
13124 case '0': /* Mailbox options */
13125 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, vm_options,chan, vmu, &vms, vmfmts, record_gain);
13126 if (useadsi)
13127 adsi_status(chan, &vms);
13128 /* Reopen play_folder */
13129 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, play_folder);
13130 if (res < 0) {
13131 ast_trace(-1, "open mailbox: %d\n", res);
13132 goto out;
13133 }
13134 vms.starting = 1;
13135 break;
13136 default: /* Nothing */
13137 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
13138 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent, nodelete);
13139 break;
13140 }
13141 }
13142 if ((cmd == 't') || (cmd == '#')) {
13143 /* Timeout */
13144 res = 0;
13145 } else {
13146 /* Hangup */
13147 res = -1;
13148 }
13149
13150out:
13151 if (res > -1) {
13152 ast_stopstream(chan);
13153 adsi_goodbye(chan);
13154 if (valid && res != OPERATOR_EXIT) {
13155 if (silentexit)
13156 res = ast_play_and_wait(chan, "vm-dialout");
13157 else
13158 res = ast_play_and_wait(chan, "vm-goodbye");
13159 }
13160 if ((valid && res > 0) || res == OPERATOR_EXIT) {
13161 res = 0;
13162 }
13163 if (useadsi)
13165 }
13166 if (vmu) {
13167 SCOPE_CALL(-1, close_mailbox, &vms, vmu);
13168 }
13169 if (valid) {
13170 int new = 0, old = 0, urgent = 0;
13171 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
13172 /* Urgent flag not passwd to externnotify here */
13173 run_externnotify(vmu->context, vmu->mailbox, NULL);
13174 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
13175 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgent, new, old);
13176 }
13177#ifdef IMAP_STORAGE
13178 /* expunge message - use UID Expunge if supported on IMAP server*/
13179 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
13180 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
13181 ast_mutex_lock(&vms.lock);
13182#ifdef HAVE_IMAP_TK2006
13183 if (LEVELUIDPLUS (vms.mailstream)) {
13184 mail_expunge_full(vms.mailstream, NIL, EX_UID);
13185 } else
13186#endif
13187 mail_expunge(vms.mailstream);
13188 ast_mutex_unlock(&vms.lock);
13189 }
13190 /* before we delete the state, we should copy pertinent info
13191 * back to the persistent model */
13192 if (vmu) {
13193 vmstate_delete(&vms);
13194 }
13195#endif
13196 if (vmu)
13197 free_user(vmu);
13198
13199#ifdef IMAP_STORAGE
13200 pthread_setspecific(ts_vmstate.key, NULL);
13201#endif
13202 SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d\n", res);
13203}
int ast_adsi_unload_session(struct ast_channel *chan)
Definition adsi.c:87
static void adsi_folders(struct ast_channel *chan, int start, char *label)
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_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Top level method to invoke the language variant vm_browse_messages_XX function.
static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
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 void adsi_status(struct ast_channel *chan, struct vm_state *vms)
static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
The advanced options within a message.
static int get_folder2(struct ast_channel *chan, char *fn, int start)
plays a prompt and waits for a keypress.
static void adsi_goodbye(struct ast_channel *chan)
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_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
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.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:8825
FILE * out
Definition utils/frame.c:33

References adsi_begin(), adsi_delete(), adsi_folders(), adsi_goodbye(), adsi_message(), adsi_status(), adsi_status2(), advanced_options(), args, ast_adsi_unload_session(), ast_answer(), AST_APP_ARG, ast_app_inboxcount2(), ast_app_parse_options(), ast_channel_context(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log, AST_LOG_WARNING, ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, ast_trace, ast_verb, ast_waitfordigit(), ast_vm_user::callback, close_mailbox(), vm_state::context, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, vm_state::deleted, dialout(), ast_vm_user::dialout, ERROR_LOCK_PATH, find_user(), ast_flags::flags, vm_state::fn, forward_message(), free_user(), get_folder2(), get_folder_by_name(), globalflags, vm_state::heard, ast_vm_user::language, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), maxlogins, ast_vm_user::maxmsg, mbox(), NEW_FOLDER, vm_state::newmessages, NULL, OLD_FOLDER, vm_state::oldmessages, open_mailbox(), OPERATOR_EXIT, OPT_ARG_ARRAY_SIZE, OPT_ARG_PLAYFOLDER, OPT_ARG_RECORDGAIN, OPT_AUTOPLAY, OPT_PREPEND_MAILBOX, OPT_READONLY, OPT_RECORDGAIN, OPT_SILENT, out, ast_vm_user::password, play_message(), queue_mwi_event(), vm_state::repeats, run_externnotify(), save_to_folder(), say_and_wait(), SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, vm_state::starting, vm_state::urgentmessages, vm_state::username, vm_app_options, vm_authenticate(), vm_browse_messages(), VM_FORCEGREET, VM_FORCENAME, vm_instructions(), vm_intro(), VM_MESSAGEWRAP, vm_newuser, vm_newuser_setup(), vm_options(), vm_play_folder_name(), VM_SKIPAFTERCMD, VM_SVMAIL, vm_state::vmbox, and vmfmts.

Referenced by load_module().

◆ vm_forwardoptions()

static int vm_forwardoptions ( struct ast_channel chan,
struct ast_vm_user vmu,
char *  curdir,
int  curmsg,
char *  vm_fmts,
char *  context,
signed char  record_gain,
long *  duration,
struct vm_state vms,
char *  flag 
)
static

presents the option to prepend to an existing message when forwarding it.

Parameters
chan
vmu
curdir
curmsg
vm_fmts
context
record_gain
duration
vms
flag

Presents a prompt for 1 to prepend the current message, 2 to forward the message without prepending, or * to return to the main menu.

This is invoked from forward_message() when performing a forward operation (option 8 from main menu).

Returns
zero on success, -1 on error.

Definition at line 8373 of file app_voicemail.c.

8376{
8377 int cmd = 0;
8378 int retries = 0, prepend_duration = 0, already_recorded = 0;
8379 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
8380 char textfile[PATH_MAX];
8381 struct ast_config *msg_cfg;
8382 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8383#ifndef IMAP_STORAGE
8384 signed char zero_gain = 0;
8385#else
8386 const char *msg_id = NULL;
8387#endif
8388 const char *duration_str;
8389 SCOPE_ENTER(3, "mbox: %s msgnum: %d curdir: %s", vmu->mailbox, curmsg, curdir);
8390
8391 /* Must always populate duration correctly */
8392 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
8393 ast_trace(-1, "msgfile: %s\n", msgfile);
8394 strcpy(textfile, msgfile);
8395 strcpy(backup, msgfile);
8396 strcpy(backup_textfile, msgfile);
8397 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
8398 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
8399 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8400
8401 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
8402 *duration = atoi(duration_str);
8403 } else {
8404 *duration = 0;
8405 }
8406
8407 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
8408 if (cmd)
8409 retries = 0;
8410 switch (cmd) {
8411 case '1':
8412
8413#ifdef IMAP_STORAGE
8414 /* Record new intro file */
8415 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8416 msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
8417 }
8418 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
8419 strncat(vms->introfn, "intro", sizeof(vms->introfn));
8420 ast_play_and_wait(chan, "vm-record-prepend");
8421 ast_play_and_wait(chan, "beep");
8422 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);
8423 if (cmd == -1) {
8424 break;
8425 }
8426 cmd = 't';
8427#else
8428
8429 /* prepend a message to the current message, update the metadata and return */
8430 ast_trace(-1, "Prepending to message %d\n", curmsg);
8431
8432 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
8433 ast_trace(-1, "msgfile: %s\n", msgfile);
8434
8435 strcpy(textfile, msgfile);
8436 strncat(textfile, ".txt", sizeof(textfile) - 1);
8437 *duration = 0;
8438
8439 /* if we can't read the message metadata, stop now */
8440 if (!valid_config(msg_cfg)) {
8441 cmd = 0;
8442 break;
8443 }
8444
8445 /* Back up the original file, so we can retry the prepend and restore it after forward. */
8446#ifndef IMAP_STORAGE
8447 if (already_recorded) {
8448 ast_trace(-1, "Restoring '%s' to '%s'\n", backup, msgfile);
8449 ast_filecopy(backup, msgfile, NULL);
8450 copy(backup_textfile, textfile);
8451 }
8452 else {
8453 ast_trace(-1, "Backing up '%s' to '%s'\n", backup, msgfile);
8454 ast_filecopy(msgfile, backup, NULL);
8455 copy(textfile, backup_textfile);
8456 }
8457#endif
8458 already_recorded = 1;
8459
8460 if (record_gain)
8461 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
8462
8463 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, ast_play_and_prepend, chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
8464
8465 if (cmd == 'S') { /* If we timed out, tell the user it didn't work properly and clean up the files */
8466 ast_stream_and_wait(chan, vm_pls_try_again, ""); /* this might be removed if a proper vm_prepend_timeout is ever recorded */
8468 ast_filerename(backup, msgfile, NULL);
8469 }
8470
8471 if (record_gain)
8472 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
8473
8474
8475 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
8476 *duration = atoi(duration_str);
8477
8478 if (prepend_duration) {
8479 struct ast_category *msg_cat;
8480 /* need enough space for a maximum-length message duration */
8481 char duration_buf[12];
8482
8483 *duration += prepend_duration;
8484 ast_trace(-1, "Prepending duration: %d total duration: %ld\n", prepend_duration, *duration);
8485 msg_cat = ast_category_get(msg_cfg, "message", NULL);
8486 snprintf(duration_buf, sizeof(duration_buf), "%ld", *duration);
8487 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
8488 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
8489 }
8490 }
8491
8492#endif
8493 break;
8494 case '2':
8495 /* NULL out introfile so we know there is no intro! */
8496#ifdef IMAP_STORAGE
8497 *vms->introfn = '\0';
8498#endif
8499 cmd = 't';
8500 break;
8501 case '*':
8502 cmd = '*';
8503 break;
8504 default:
8505 /* If time_out and return to menu, reset already_recorded */
8506 already_recorded = 0;
8507
8508 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
8509 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
8510 if (!cmd) {
8511 cmd = ast_play_and_wait(chan, "vm-starmain");
8512 /* "press star to return to the main menu" */
8513 }
8514 if (!cmd) {
8515 cmd = ast_waitfordigit(chan, 6000);
8516 }
8517 if (!cmd) {
8518 retries++;
8519 }
8520 if (retries > 3) {
8521 cmd = '*'; /* Let's cancel this beast */
8522 }
8523 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8524 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
8525 }
8526 }
8527
8528 if (valid_config(msg_cfg))
8529 ast_config_destroy(msg_cfg);
8530 if (prepend_duration)
8531 *duration = prepend_duration;
8532
8533 if (already_recorded && cmd == -1) {
8534 /* restore original message if prepention cancelled */
8535 ast_trace(-1, "Restoring '%s' to '%s'\n", backup, msgfile);
8536 ast_filerename(backup, msgfile, NULL);
8537 rename(backup_textfile, textfile);
8538 }
8539
8540 if (cmd == 't' || cmd == 'S') { /* XXX entering this block with a value of 'S' is probably no longer possible. */
8541 cmd = 0;
8542 }
8543 SCOPE_EXIT_RTN_VALUE(cmd, "Done. CMD: %d %c\n", cmd, cmd >= 32 && cmd < 127 ? cmd : '?');
8544}
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:2160

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_trace, ast_variable_retrieve(), ast_variable_update(), ast_waitfordigit(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, copy(), ast_vm_user::mailbox, make_file(), ast_vm_user::maxsecs, maxsilence, NULL, PATH_MAX, play_record_review(), SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, silencethreshold, valid_config(), vm_pls_try_again, and vm_prepend_timeout.

Referenced by forward_message().

◆ vm_index_to_foldername()

static const char * vm_index_to_foldername ( int  id)
static

Definition at line 2243 of file app_voicemail.c.

2244{
2245 return mbox(NULL, id);
2246}

References mbox(), and NULL.

◆ vm_instructions()

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

Definition at line 11124 of file app_voicemail.c.

11125{
11126 if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
11127 return vm_instructions_ja(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11128 } else if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
11129 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11130 } else { /* Default to ENGLISH */
11131 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11132 }
11133}
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_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)

References ast_channel_language(), vm_state::starting, vm_instructions_en(), vm_instructions_ja(), and vm_instructions_zh().

Referenced by vm_execmain().

◆ vm_instructions_en()

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

Definition at line 10914 of file app_voicemail.c.

10915{
10916 int res = 0;
10917 /* Play instructions and wait for new command */
10918 while (!res) {
10919 if (vms->starting) {
10920 if (vms->lastmsg > -1) {
10921 if (skipadvanced)
10922 res = ast_play_and_wait(chan, "vm-onefor-full");
10923 else
10924 res = ast_play_and_wait(chan, "vm-onefor");
10925 if (!res)
10926 res = vm_play_folder_name(chan, vms->vmbox);
10927 }
10928 if (!res) {
10929 if (skipadvanced)
10930 res = ast_play_and_wait(chan, "vm-opts-full");
10931 else
10932 res = ast_play_and_wait(chan, "vm-opts");
10933 }
10934 } else {
10935 /* Added for additional help */
10936 if (skipadvanced) {
10937 res = ast_play_and_wait(chan, "vm-onefor-full");
10938 if (!res)
10939 res = vm_play_folder_name(chan, vms->vmbox);
10940 res = ast_play_and_wait(chan, "vm-opts-full");
10941 }
10942 /* Logic:
10943 * If the current message is not the first OR
10944 * if we're listening to the first new message and there are
10945 * also urgent messages, then prompt for navigation to the
10946 * previous message
10947 */
10948 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
10949 res = ast_play_and_wait(chan, "vm-prev");
10950 }
10951 if (!res && !skipadvanced)
10952 res = ast_play_and_wait(chan, "vm-advopts");
10953 if (!res)
10954 res = ast_play_and_wait(chan, "vm-repeat");
10955 /* Logic:
10956 * If we're not listening to the last message OR
10957 * we're listening to the last urgent message and there are
10958 * also new non-urgent messages, then prompt for navigation
10959 * to the next message
10960 */
10961 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
10962 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
10963 res = ast_play_and_wait(chan, "vm-next");
10964 }
10965 if (!res) {
10966 int curmsg_deleted;
10967#ifdef IMAP_STORAGE
10968 ast_mutex_lock(&vms->lock);
10969#endif
10970 curmsg_deleted = vms->deleted[vms->curmsg];
10971#ifdef IMAP_STORAGE
10972 ast_mutex_unlock(&vms->lock);
10973#endif
10974 if (!nodelete) {
10975 if (!curmsg_deleted) {
10976 res = ast_play_and_wait(chan, "vm-delete");
10977 } else {
10978 res = ast_play_and_wait(chan, "vm-undelete");
10979 }
10980 }
10981 if (!res) {
10982 res = ast_play_and_wait(chan, "vm-toforward");
10983 }
10984 if (!res) {
10985 res = ast_play_and_wait(chan, "vm-savemessage");
10986 }
10987 }
10988 }
10989 if (!res) {
10990 res = ast_play_and_wait(chan, "vm-helpexit");
10991 }
10992 if (!res)
10993 res = ast_waitfordigit(chan, 6000);
10994 if (!res) {
10995 vms->repeats++;
10996 if (vms->repeats > 2) {
10997 res = 't';
10998 }
10999 }
11000 }
11001 return res;
11002}

References ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_test_flag, ast_waitfordigit(), vm_state::curmsg, vm_state::deleted, vm_state::lastmsg, vm_state::newmessages, vm_state::repeats, vm_state::starting, vm_state::urgentmessages, VM_MESSAGEWRAP, vm_play_folder_name(), and vm_state::vmbox.

Referenced by vm_instructions(), and vm_instructions_zh().

◆ vm_instructions_ja()

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

Definition at line 11004 of file app_voicemail.c.

11005{
11006 int res = 0;
11007 /* Play instructions and wait for new command */
11008 while (!res) {
11009 if (vms->starting) {
11010 if (vms->lastmsg > -1) {
11011 res = vm_play_folder_name(chan, vms->vmbox);
11012 if (!res)
11013 res = ast_play_and_wait(chan, "jp-wa");
11014 if (!res)
11015 res = ast_play_and_wait(chan, "digits/1");
11016 if (!res)
11017 res = ast_play_and_wait(chan, "jp-wo");
11018 if (!res)
11019 res = ast_play_and_wait(chan, "silence/1");
11020 }
11021 if (!res)
11022 res = ast_play_and_wait(chan, "vm-opts");
11023 } else {
11024 /* Added for additional help */
11025 if (skipadvanced) {
11026 res = vm_play_folder_name(chan, vms->vmbox);
11027 if (!res)
11028 res = ast_play_and_wait(chan, "jp-wa");
11029 if (!res)
11030 res = ast_play_and_wait(chan, "digits/1");
11031 if (!res)
11032 res = ast_play_and_wait(chan, "jp-wo");
11033 if (!res)
11034 res = ast_play_and_wait(chan, "silence/1");
11035 res = ast_play_and_wait(chan, "vm-opts-full");
11036 }
11037 /* Logic:
11038 * If the current message is not the first OR
11039 * if we're listening to the first new message and there are
11040 * also urgent messages, then prompt for navigation to the
11041 * previous message
11042 */
11043 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
11044 res = ast_play_and_wait(chan, "vm-prev");
11045 }
11046 if (!res && !skipadvanced)
11047 res = ast_play_and_wait(chan, "vm-advopts");
11048 if (!res)
11049 res = ast_play_and_wait(chan, "vm-repeat");
11050 /* Logic:
11051 * If we're not listening to the last message OR
11052 * we're listening to the last urgent message and there are
11053 * also new non-urgent messages, then prompt for navigation
11054 * to the next message
11055 */
11056 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
11057 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
11058 res = ast_play_and_wait(chan, "vm-next");
11059 }
11060 if (!res) {
11061 int curmsg_deleted;
11062#ifdef IMAP_STORAGE
11063 ast_mutex_lock(&vms->lock);
11064#endif
11065 curmsg_deleted = vms->deleted[vms->curmsg];
11066#ifdef IMAP_STORAGE
11067 ast_mutex_unlock(&vms->lock);
11068#endif
11069 if (!curmsg_deleted) {
11070 res = ast_play_and_wait(chan, "vm-delete");
11071 } else {
11072 res = ast_play_and_wait(chan, "vm-undelete");
11073 }
11074 if (!res) {
11075 res = ast_play_and_wait(chan, "vm-toforward");
11076 }
11077 if (!res) {
11078 res = ast_play_and_wait(chan, "vm-savemessage");
11079 }
11080 }
11081 }
11082
11083 if (!res) {
11084 res = ast_play_and_wait(chan, "vm-helpexit");
11085 }
11086 if (!res)
11087 res = ast_waitfordigit(chan, 6000);
11088 if (!res) {
11089 vms->repeats++;
11090 if (vms->repeats > 2) {
11091 res = 't';
11092 }
11093 }
11094
11095 }
11096
11097 return res;
11098}

References ast_mutex_lock, ast_mutex_unlock, ast_play_and_wait(), ast_test_flag, ast_waitfordigit(), vm_state::curmsg, vm_state::deleted, vm_state::lastmsg, vm_state::newmessages, vm_state::repeats, vm_state::starting, vm_state::urgentmessages, VM_MESSAGEWRAP, vm_play_folder_name(), and vm_state::vmbox.

Referenced by vm_instructions().

◆ vm_instructions_zh()

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

Definition at line 11100 of file app_voicemail.c.

11101{
11102 int res = 0;
11103 /* Play instructions and wait for new command */
11104 while (!res) {
11105 if (vms->lastmsg > -1) {
11106 res = ast_play_and_wait(chan, "vm-listen");
11107 if (!res)
11108 res = vm_play_folder_name(chan, vms->vmbox);
11109 if (!res)
11110 res = ast_play_and_wait(chan, "press");
11111 if (!res)
11112 res = ast_play_and_wait(chan, "digits/1");
11113 }
11114 if (!res)
11115 res = ast_play_and_wait(chan, "vm-opts");
11116 if (!res) {
11117 vms->starting = 0;
11118 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11119 }
11120 }
11121 return res;
11122}

References ast_play_and_wait(), vm_state::lastmsg, vm_state::starting, vm_instructions_en(), vm_play_folder_name(), and vm_state::vmbox.

Referenced by vm_instructions().

◆ vm_intro()

static int vm_intro ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms 
)
static

Definition at line 10852 of file app_voicemail.c.

10853{
10854 char prefile[256];
10855
10856 /* Notify the user that the temp greeting is set and give them the option to remove it */
10857 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10858 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10859 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10860 if (ast_fileexists(prefile, NULL, NULL) > 0) {
10861 ast_play_and_wait(chan, "vm-tempgreetactive");
10862 }
10863 DISPOSE(prefile, -1);
10864 }
10865
10866 /* Play voicemail intro - syntax is different for different languages */
10867 if (0) {
10868 return 0;
10869 } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) { /* CZECH syntax */
10870 return vm_intro_cs(chan, vms);
10871 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
10872 return vm_intro_de(chan, vms);
10873 } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH syntax */
10874 return vm_intro_es(chan, vms);
10875 } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) { /* FRENCH syntax */
10876 return vm_intro_fr(chan, vms);
10877 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
10878 return vm_intro_gr(chan, vms);
10879 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */
10880 return vm_intro_he(chan, vms);
10881 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
10882 return vm_intro_is(chan, vms);
10883 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
10884 return vm_intro_it(chan, vms);
10885 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */
10886 return vm_intro_ja(chan, vms);
10887 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
10888 return vm_intro_nl(chan, vms);
10889 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
10890 return vm_intro_no(chan, vms);
10891 } else if (!strncasecmp(ast_channel_language(chan), "da", 2)) { /* DANISH syntax */
10892 return vm_intro_da(chan, vms);
10893 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
10894 return vm_intro_pl(chan, vms);
10895 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* BRAZILIAN PORTUGUESE syntax */
10896 return vm_intro_pt_BR(chan, vms);
10897 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE syntax */
10898 return vm_intro_pt(chan, vms);
10899 } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) { /* RUSSIAN syntax */
10900 return vm_intro_multilang(chan, vms, "n");
10901 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
10902 return vm_intro_se(chan, vms);
10903 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* UKRAINIAN syntax */
10904 return vm_intro_multilang(chan, vms, "n");
10905 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
10906 return vm_intro_vi(chan, vms);
10907 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
10908 return vm_intro_zh(chan, vms);
10909 } else { /* Default to ENGLISH */
10910 return vm_intro_en(chan, vms);
10911 }
10912}
static int vm_intro_pl(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_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
static int vm_intro_de(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_vi(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_zh(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_en(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_fr(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_es(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_se(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_gr(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)

References ast_channel_language(), ast_fileexists(), ast_play_and_wait(), ast_test_flag, ast_vm_user::context, DISPOSE, ast_vm_user::mailbox, NULL, RETRIEVE, vm_state::username, vm_intro_cs(), vm_intro_da(), vm_intro_de(), vm_intro_en(), vm_intro_es(), vm_intro_fr(), vm_intro_gr(), vm_intro_he(), vm_intro_is(), vm_intro_it(), vm_intro_ja(), vm_intro_multilang(), vm_intro_nl(), vm_intro_no(), vm_intro_pl(), vm_intro_pt(), vm_intro_pt_BR(), vm_intro_se(), vm_intro_vi(), vm_intro_zh(), VM_SPOOL_DIR, and VM_TEMPGREETWARN.

Referenced by vm_execmain().

◆ vm_intro_cs()

static int vm_intro_cs ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10722 of file app_voicemail.c.

10723{
10724 int res;
10725 res = ast_play_and_wait(chan, "vm-youhave");
10726 if (!res) {
10727 if (vms->newmessages) {
10728 if (vms->newmessages == 1) {
10729 res = ast_play_and_wait(chan, "digits/jednu");
10730 } else {
10731 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10732 }
10733 if (!res) {
10734 if (vms->newmessages == 1)
10735 res = ast_play_and_wait(chan, "vm-novou");
10736 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10737 res = ast_play_and_wait(chan, "vm-nove");
10738 if (vms->newmessages > 4)
10739 res = ast_play_and_wait(chan, "vm-novych");
10740 }
10741 if (vms->oldmessages && !res)
10742 res = ast_play_and_wait(chan, "vm-and");
10743 else if (!res) {
10744 if (vms->newmessages == 1)
10745 res = ast_play_and_wait(chan, "vm-zpravu");
10746 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10747 res = ast_play_and_wait(chan, "vm-zpravy");
10748 if (vms->newmessages > 4)
10749 res = ast_play_and_wait(chan, "vm-zprav");
10750 }
10751 }
10752 if (!res && vms->oldmessages) {
10753 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10754 if (!res) {
10755 if (vms->oldmessages == 1)
10756 res = ast_play_and_wait(chan, "vm-starou");
10757 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10758 res = ast_play_and_wait(chan, "vm-stare");
10759 if (vms->oldmessages > 4)
10760 res = ast_play_and_wait(chan, "vm-starych");
10761 }
10762 if (!res) {
10763 if (vms->oldmessages == 1)
10764 res = ast_play_and_wait(chan, "vm-zpravu");
10765 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10766 res = ast_play_and_wait(chan, "vm-zpravy");
10767 if (vms->oldmessages > 4)
10768 res = ast_play_and_wait(chan, "vm-zprav");
10769 }
10770 }
10771 if (!res) {
10772 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10773 res = ast_play_and_wait(chan, "vm-no");
10774 if (!res)
10775 res = ast_play_and_wait(chan, "vm-zpravy");
10776 }
10777 }
10778 }
10779 return res;
10780}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_da()

static int vm_intro_da ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10373 of file app_voicemail.c.

10374{
10375 /* Introduce messages they have */
10376 int res;
10377
10378 res = ast_play_and_wait(chan, "vm-youhave");
10379 if (res)
10380 return res;
10381
10382 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10383 res = ast_play_and_wait(chan, "vm-no");
10384 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10385 return res;
10386 }
10387
10388 if (vms->newmessages) {
10389 if ((vms->newmessages == 1)) {
10390 res = ast_play_and_wait(chan, "digits/1");
10391 res = res ? res : ast_play_and_wait(chan, "vm-INBOX");
10392 res = res ? res : ast_play_and_wait(chan, "vm-message");
10393 } else {
10394 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10395 res = res ? res : ast_play_and_wait(chan, "vm-INBOXs");
10396 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10397 }
10398 if (!res && vms->oldmessages)
10399 res = ast_play_and_wait(chan, "vm-and");
10400 }
10401 if (!res && vms->oldmessages) {
10402 if (vms->oldmessages == 1) {
10403 res = ast_play_and_wait(chan, "digits/1");
10404 res = res ? res : ast_play_and_wait(chan, "vm-Old");
10405 res = res ? res : ast_play_and_wait(chan, "vm-message");
10406 } else {
10407 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10408 res = res ? res : ast_play_and_wait(chan, "vm-Olds");
10409 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10410 }
10411 }
10412
10413 return res;
10414}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_de()

static int vm_intro_de ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10418 of file app_voicemail.c.

10419{
10420 /* Introduce messages they have */
10421 int res;
10422 res = ast_play_and_wait(chan, "vm-youhave");
10423 if (!res) {
10424 if (vms->newmessages) {
10425 if (vms->newmessages == 1)
10426 res = ast_play_and_wait(chan, "digits/1F");
10427 else
10428 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10429 if (!res)
10430 res = ast_play_and_wait(chan, "vm-INBOX");
10431 if (vms->oldmessages && !res)
10432 res = ast_play_and_wait(chan, "vm-and");
10433 else if (!res) {
10434 if (vms->newmessages == 1)
10435 res = ast_play_and_wait(chan, "vm-message");
10436 else
10437 res = ast_play_and_wait(chan, "vm-messages");
10438 }
10439
10440 }
10441 if (!res && vms->oldmessages) {
10442 if (vms->oldmessages == 1)
10443 res = ast_play_and_wait(chan, "digits/1F");
10444 else
10445 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10446 if (!res)
10447 res = ast_play_and_wait(chan, "vm-Old");
10448 if (!res) {
10449 if (vms->oldmessages == 1)
10450 res = ast_play_and_wait(chan, "vm-message");
10451 else
10452 res = ast_play_and_wait(chan, "vm-messages");
10453 }
10454 }
10455 if (!res) {
10456 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10457 res = ast_play_and_wait(chan, "vm-no");
10458 if (!res)
10459 res = ast_play_and_wait(chan, "vm-messages");
10460 }
10461 }
10462 }
10463 return res;
10464}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_en()

static int vm_intro_en ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10053 of file app_voicemail.c.

10054{
10055 int res;
10056
10057 /* Introduce messages they have */
10058 res = ast_play_and_wait(chan, "vm-youhave");
10059 if (!res) {
10060 if (vms->urgentmessages) {
10061 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
10062 if (!res)
10063 res = ast_play_and_wait(chan, "vm-Urgent");
10064 if ((vms->oldmessages || vms->newmessages) && !res) {
10065 res = ast_play_and_wait(chan, "vm-and");
10066 } else if (!res) {
10067 if (vms->urgentmessages == 1)
10068 res = ast_play_and_wait(chan, "vm-message");
10069 else
10070 res = ast_play_and_wait(chan, "vm-messages");
10071 }
10072 }
10073 if (vms->newmessages) {
10074 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10075 if (!res)
10076 res = ast_play_and_wait(chan, "vm-INBOX");
10077 if (vms->oldmessages && !res)
10078 res = ast_play_and_wait(chan, "vm-and");
10079 else if (!res) {
10080 if (vms->newmessages == 1)
10081 res = ast_play_and_wait(chan, "vm-message");
10082 else
10083 res = ast_play_and_wait(chan, "vm-messages");
10084 }
10085
10086 }
10087 if (!res && vms->oldmessages) {
10088 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10089 if (!res)
10090 res = ast_play_and_wait(chan, "vm-Old");
10091 if (!res) {
10092 if (vms->oldmessages == 1)
10093 res = ast_play_and_wait(chan, "vm-message");
10094 else
10095 res = ast_play_and_wait(chan, "vm-messages");
10096 }
10097 }
10098 if (!res) {
10099 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10100 res = ast_play_and_wait(chan, "vm-no");
10101 if (!res)
10102 res = ast_play_and_wait(chan, "vm-messages");
10103 }
10104 }
10105 }
10106 return res;
10107}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_es()

static int vm_intro_es ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10467 of file app_voicemail.c.

10468{
10469 /* Introduce messages they have */
10470 int res;
10471 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10472 res = ast_play_and_wait(chan, "vm-youhaveno");
10473 if (!res)
10474 res = ast_play_and_wait(chan, "vm-messages");
10475 } else {
10476 res = ast_play_and_wait(chan, "vm-youhave");
10477 }
10478 if (!res) {
10479 if (vms->newmessages) {
10480 if (!res) {
10481 if (vms->newmessages == 1) {
10482 res = ast_play_and_wait(chan, "digits/1M");
10483 if (!res)
10484 res = ast_play_and_wait(chan, "vm-message");
10485 if (!res)
10486 res = ast_play_and_wait(chan, "vm-INBOXs");
10487 } else {
10488 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10489 if (!res)
10490 res = ast_play_and_wait(chan, "vm-messages");
10491 if (!res)
10492 res = ast_play_and_wait(chan, "vm-INBOX");
10493 }
10494 }
10495 if (vms->oldmessages && !res)
10496 res = ast_play_and_wait(chan, "vm-and");
10497 }
10498 if (vms->oldmessages) {
10499 if (!res) {
10500 if (vms->oldmessages == 1) {
10501 res = ast_play_and_wait(chan, "digits/1M");
10502 if (!res)
10503 res = ast_play_and_wait(chan, "vm-message");
10504 if (!res)
10505 res = ast_play_and_wait(chan, "vm-Olds");
10506 } else {
10507 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10508 if (!res)
10509 res = ast_play_and_wait(chan, "vm-messages");
10510 if (!res)
10511 res = ast_play_and_wait(chan, "vm-Old");
10512 }
10513 }
10514 }
10515 }
10516return res;
10517}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_fr()

static int vm_intro_fr ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10565 of file app_voicemail.c.

10566{
10567 /* Introduce messages they have */
10568 int res;
10569 res = ast_play_and_wait(chan, "vm-youhave");
10570 if (!res) {
10571 if (vms->newmessages) {
10572 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10573 if (!res)
10574 res = ast_play_and_wait(chan, "vm-INBOX");
10575 if (vms->oldmessages && !res)
10576 res = ast_play_and_wait(chan, "vm-and");
10577 else if (!res) {
10578 if (vms->newmessages == 1)
10579 res = ast_play_and_wait(chan, "vm-message");
10580 else
10581 res = ast_play_and_wait(chan, "vm-messages");
10582 }
10583
10584 }
10585 if (!res && vms->oldmessages) {
10586 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10587 if (!res)
10588 res = ast_play_and_wait(chan, "vm-Old");
10589 if (!res) {
10590 if (vms->oldmessages == 1)
10591 res = ast_play_and_wait(chan, "vm-message");
10592 else
10593 res = ast_play_and_wait(chan, "vm-messages");
10594 }
10595 }
10596 if (!res) {
10597 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10598 res = ast_play_and_wait(chan, "vm-no");
10599 if (!res)
10600 res = ast_play_and_wait(chan, "vm-messages");
10601 }
10602 }
10603 }
10604 return res;
10605}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_gr()

static int vm_intro_gr ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 9813 of file app_voicemail.c.

9814{
9815 int res = 0;
9816
9817 if (vms->newmessages) {
9818 res = ast_play_and_wait(chan, "vm-youhave");
9819 if (!res)
9821 if (!res) {
9822 if (vms->newmessages == 1) {
9823 res = ast_play_and_wait(chan, "vm-INBOX");
9824 if (!res)
9825 res = ast_play_and_wait(chan, "vm-message");
9826 } else {
9827 res = ast_play_and_wait(chan, "vm-INBOXs");
9828 if (!res)
9829 res = ast_play_and_wait(chan, "vm-messages");
9830 }
9831 }
9832 } else if (vms->oldmessages){
9833 res = ast_play_and_wait(chan, "vm-youhave");
9834 if (!res)
9836 if (vms->oldmessages == 1){
9837 res = ast_play_and_wait(chan, "vm-Old");
9838 if (!res)
9839 res = ast_play_and_wait(chan, "vm-message");
9840 } else {
9841 res = ast_play_and_wait(chan, "vm-Olds");
9842 if (!res)
9843 res = ast_play_and_wait(chan, "vm-messages");
9844 }
9845 } else if (!vms->oldmessages && !vms->newmessages)
9846 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
9847 return res;
9848}

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, NULL, and vm_state::oldmessages.

Referenced by vm_intro().

◆ vm_intro_he()

static int vm_intro_he ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 9947 of file app_voicemail.c.

9948{
9949 int res = 0;
9950
9951 /* Introduce messages they have */
9952 if (!res) {
9953 if ((vms->newmessages) || (vms->oldmessages)) {
9954 res = ast_play_and_wait(chan, "vm-youhave");
9955 }
9956 /*
9957 * The word "shtei" refers to the number 2 in hebrew when performing a count
9958 * of elements. In Hebrew, there are 6 forms of enumerating the number 2 for
9959 * an element, this is one of them.
9960 */
9961 if (vms->newmessages) {
9962 if (!res) {
9963 if (vms->newmessages == 1) {
9964 res = ast_play_and_wait(chan, "vm-INBOX1");
9965 } else {
9966 if (vms->newmessages == 2) {
9967 res = ast_play_and_wait(chan, "vm-shtei");
9968 } else {
9969 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9970 }
9971 res = ast_play_and_wait(chan, "vm-INBOX");
9972 }
9973 }
9974 if (vms->oldmessages && !res) {
9975 res = ast_play_and_wait(chan, "vm-and");
9976 if (vms->oldmessages == 1) {
9977 res = ast_play_and_wait(chan, "vm-Old1");
9978 } else {
9979 if (vms->oldmessages == 2) {
9980 res = ast_play_and_wait(chan, "vm-shtei");
9981 } else {
9982 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9983 }
9984 res = ast_play_and_wait(chan, "vm-Old");
9985 }
9986 }
9987 }
9988 if (!res && vms->oldmessages && !vms->newmessages) {
9989 if (!res) {
9990 if (vms->oldmessages == 1) {
9991 res = ast_play_and_wait(chan, "vm-Old1");
9992 } else {
9993 if (vms->oldmessages == 2) {
9994 res = ast_play_and_wait(chan, "vm-shtei");
9995 } else {
9996 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9997 }
9998 res = ast_play_and_wait(chan, "vm-Old");
9999 }
10000 }
10001 }
10002 if (!res) {
10003 if (!vms->oldmessages && !vms->newmessages) {
10004 if (!res) {
10005 res = ast_play_and_wait(chan, "vm-nomessages");
10006 }
10007 }
10008 }
10009 }
10010 return res;
10011}

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_intro().

◆ vm_intro_is()

static int vm_intro_is ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10110 of file app_voicemail.c.

10111{
10112 int res;
10113
10114 /* Introduce messages they have */
10115 res = ast_play_and_wait(chan, "vm-youhave");
10116 if (!res) {
10117 if (vms->urgentmessages) {
10118 /* Digits 1-4 are spoken in neutral and plural when talking about messages,
10119 however, feminine is used for 1 as it is the same as the neutral for plural,
10120 and singular neutral is the same after 1. */
10121 if (vms->urgentmessages < 5) {
10122 char recname[16];
10123 if (vms->urgentmessages == 1)
10124 snprintf(recname, sizeof(recname), "digits/1kvk");
10125 else
10126 snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages);
10127 res = ast_play_and_wait(chan, recname);
10128 } else if (!res)
10129 res = ast_play_and_wait(chan, "vm-Urgent");
10130 if ((vms->oldmessages || vms->newmessages) && !res) {
10131 res = ast_play_and_wait(chan, "vm-and");
10132 } else if (!res)
10133 res = ast_play_and_wait(chan, "vm-messages");
10134 }
10135 if (vms->newmessages) {
10136 if (vms->newmessages < 5) {
10137 char recname[16];
10138 if (vms->newmessages == 1)
10139 snprintf(recname, sizeof(recname), "digits/1kvk");
10140 else
10141 snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages);
10142 res = ast_play_and_wait(chan, recname);
10143 } else
10144 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10145 if (!res)
10146 res = ast_play_and_wait(chan, "vm-INBOX");
10147 if (vms->oldmessages && !res)
10148 res = ast_play_and_wait(chan, "vm-and");
10149 else if (!res)
10150 res = ast_play_and_wait(chan, "vm-messages");
10151 }
10152 if (!res && vms->oldmessages) {
10153 if (vms->oldmessages < 5) {
10154 char recname[16];
10155 if (vms->oldmessages == 1)
10156 snprintf(recname, sizeof(recname), "digits/1kvk");
10157 else
10158 snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages);
10159 res = ast_play_and_wait(chan, recname);
10160 } else
10161 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10162 if (!res)
10163 res = ast_play_and_wait(chan, "vm-Old");
10164 if (!res)
10165 res = ast_play_and_wait(chan, "vm-messages");
10166 }
10167 if (!res) {
10168 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10169 res = ast_play_and_wait(chan, "vm-no");
10170 if (!res)
10171 res = ast_play_and_wait(chan, "vm-messages");
10172 }
10173 }
10174 }
10175 return res;
10176}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_it()

static int vm_intro_it ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10179 of file app_voicemail.c.

10180{
10181 /* Introduce messages they have */
10182 int res;
10183 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
10184 res = ast_play_and_wait(chan, "vm-no") ||
10185 ast_play_and_wait(chan, "vm-message");
10186 else
10187 res = ast_play_and_wait(chan, "vm-youhave");
10188 if (!res && vms->newmessages) {
10189 res = (vms->newmessages == 1) ?
10190 ast_play_and_wait(chan, "digits/un") ||
10191 ast_play_and_wait(chan, "vm-nuovo") ||
10192 ast_play_and_wait(chan, "vm-message") :
10193 /* 2 or more new messages */
10194 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
10195 ast_play_and_wait(chan, "vm-nuovi") ||
10196 ast_play_and_wait(chan, "vm-messages");
10197 if (!res && vms->oldmessages)
10198 res = ast_play_and_wait(chan, "vm-and");
10199 }
10200 if (!res && vms->oldmessages) {
10201 res = (vms->oldmessages == 1) ?
10202 ast_play_and_wait(chan, "digits/un") ||
10203 ast_play_and_wait(chan, "vm-vecchio") ||
10204 ast_play_and_wait(chan, "vm-message") :
10205 /* 2 or more old messages */
10206 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
10207 ast_play_and_wait(chan, "vm-vecchi") ||
10208 ast_play_and_wait(chan, "vm-messages");
10209 }
10210 return res;
10211}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_ja()

static int vm_intro_ja ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10014 of file app_voicemail.c.

10015{
10016 /* Introduce messages they have */
10017 int res;
10018 if (vms->newmessages) {
10019 res = ast_play_and_wait(chan, "vm-INBOX");
10020 if (!res)
10021 res = ast_play_and_wait(chan, "vm-message");
10022 if (!res)
10023 res = ast_play_and_wait(chan, "jp-ga");
10024 if (!res)
10025 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10026 if (vms->oldmessages && !res)
10027 res = ast_play_and_wait(chan, "silence/1");
10028
10029 }
10030 if (vms->oldmessages) {
10031 res = ast_play_and_wait(chan, "vm-Old");
10032 if (!res)
10033 res = ast_play_and_wait(chan, "vm-message");
10034 if (!res)
10035 res = ast_play_and_wait(chan, "jp-ga");
10036 if (!res)
10037 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10038 }
10039 if (!vms->oldmessages && !vms->newmessages) {
10040 res = ast_play_and_wait(chan, "vm-messages");
10041 if (!res)
10042 res = ast_play_and_wait(chan, "jp-wa");
10043 if (!res)
10044 res = ast_play_and_wait(chan, "jp-arimasen");
10045 }
10046 else {
10047 res = ast_play_and_wait(chan, "jp-arimasu");
10048 }
10049 return res;
10050} /* Japanese */

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

◆ vm_intro_multilang()

static int vm_intro_multilang ( struct ast_channel chan,
struct vm_state vms,
const char  message_gender[] 
)
static

Definition at line 9907 of file app_voicemail.c.

9908{
9909 int res;
9910 int lastnum = 0;
9911
9912 res = ast_play_and_wait(chan, "vm-youhave");
9913
9914 if (!res && vms->newmessages) {
9915 lastnum = vms->newmessages;
9916
9917 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9918 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
9919 }
9920
9921 if (!res && vms->oldmessages) {
9922 res = ast_play_and_wait(chan, "vm-and");
9923 }
9924 }
9925
9926 if (!res && vms->oldmessages) {
9927 lastnum = vms->oldmessages;
9928
9929 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9930 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
9931 }
9932 }
9933
9934 if (!res) {
9935 if (lastnum == 0) {
9936 res = ast_play_and_wait(chan, "vm-no");
9937 }
9938 if (!res) {
9939 res = ast_say_counted_noun(chan, lastnum, "vm-message");
9940 }
9941 }
9942
9943 return res;
9944}
int ast_say_counted_noun(struct ast_channel *chan, int num, const char *noun)
int ast_say_counted_adjective(struct ast_channel *chan, int num, const char *adjective, const char *gender)

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_counted_adjective(), ast_say_counted_noun(), ast_say_number(), vm_state::newmessages, and vm_state::oldmessages.

Referenced by vm_intro().

◆ vm_intro_nl()

static int vm_intro_nl ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10608 of file app_voicemail.c.

10609{
10610 /* Introduce messages they have */
10611 int res;
10612 res = ast_play_and_wait(chan, "vm-youhave");
10613 if (!res) {
10614 if (vms->newmessages) {
10615 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10616 if (!res) {
10617 if (vms->newmessages == 1)
10618 res = ast_play_and_wait(chan, "vm-INBOXs");
10619 else
10620 res = ast_play_and_wait(chan, "vm-INBOX");
10621 }
10622 if (vms->oldmessages && !res)
10623 res = ast_play_and_wait(chan, "vm-and");
10624 else if (!res) {
10625 if (vms->newmessages == 1)
10626 res = ast_play_and_wait(chan, "vm-message");
10627 else
10628 res = ast_play_and_wait(chan, "vm-messages");
10629 }
10630
10631 }
10632 if (!res && vms->oldmessages) {
10633 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10634 if (!res) {
10635 if (vms->oldmessages == 1)
10636 res = ast_play_and_wait(chan, "vm-Olds");
10637 else
10638 res = ast_play_and_wait(chan, "vm-Old");
10639 }
10640 if (!res) {
10641 if (vms->oldmessages == 1)
10642 res = ast_play_and_wait(chan, "vm-message");
10643 else
10644 res = ast_play_and_wait(chan, "vm-messages");
10645 }
10646 }
10647 if (!res) {
10648 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10649 res = ast_play_and_wait(chan, "vm-no");
10650 if (!res)
10651 res = ast_play_and_wait(chan, "vm-messages");
10652 }
10653 }
10654 }
10655 return res;
10656}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_no()

static int vm_intro_no ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10329 of file app_voicemail.c.

10330{
10331 /* Introduce messages they have */
10332 int res;
10333
10334 res = ast_play_and_wait(chan, "vm-youhave");
10335 if (res)
10336 return res;
10337
10338 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10339 res = ast_play_and_wait(chan, "vm-no");
10340 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10341 return res;
10342 }
10343
10344 if (vms->newmessages) {
10345 if (vms->newmessages == 1) {
10346 res = ast_play_and_wait(chan, "digits/1");
10347 res = res ? res : ast_play_and_wait(chan, "vm-ny");
10348 res = res ? res : ast_play_and_wait(chan, "vm-message");
10349 } else {
10350 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10351 res = res ? res : ast_play_and_wait(chan, "vm-nye");
10352 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10353 }
10354 if (!res && vms->oldmessages)
10355 res = ast_play_and_wait(chan, "vm-and");
10356 }
10357 if (!res && vms->oldmessages) {
10358 if (vms->oldmessages == 1) {
10359 res = ast_play_and_wait(chan, "digits/1");
10360 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
10361 res = res ? res : ast_play_and_wait(chan, "vm-message");
10362 } else {
10363 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10364 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
10365 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10366 }
10367 }
10368
10369 return res;
10370}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_pl()

static int vm_intro_pl ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10214 of file app_voicemail.c.

10215{
10216 /* Introduce messages they have */
10217 int res;
10218 div_t num;
10219
10220 if (!vms->oldmessages && !vms->newmessages) {
10221 res = ast_play_and_wait(chan, "vm-no");
10222 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10223 return res;
10224 } else {
10225 res = ast_play_and_wait(chan, "vm-youhave");
10226 }
10227
10228 if (vms->newmessages) {
10229 num = div(vms->newmessages, 10);
10230 if (vms->newmessages == 1) {
10231 res = ast_play_and_wait(chan, "digits/1-a");
10232 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
10233 res = res ? res : ast_play_and_wait(chan, "vm-message");
10234 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10235 if (num.rem == 2) {
10236 if (!num.quot) {
10237 res = ast_play_and_wait(chan, "digits/2-ie");
10238 } else {
10239 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
10240 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
10241 }
10242 } else {
10243 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10244 }
10245 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
10246 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10247 } else {
10248 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10249 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
10250 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10251 }
10252 if (!res && vms->oldmessages)
10253 res = ast_play_and_wait(chan, "vm-and");
10254 }
10255 if (!res && vms->oldmessages) {
10256 num = div(vms->oldmessages, 10);
10257 if (vms->oldmessages == 1) {
10258 res = ast_play_and_wait(chan, "digits/1-a");
10259 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
10260 res = res ? res : ast_play_and_wait(chan, "vm-message");
10261 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10262 if (num.rem == 2) {
10263 if (!num.quot) {
10264 res = ast_play_and_wait(chan, "digits/2-ie");
10265 } else {
10266 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
10267 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
10268 }
10269 } else {
10270 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10271 }
10272 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
10273 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10274 } else {
10275 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10276 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
10277 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10278 }
10279 }
10280
10281 return res;
10282}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

◆ vm_intro_pt()

static int vm_intro_pt ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10659 of file app_voicemail.c.

10660{
10661 /* Introduce messages they have */
10662 int res;
10663 res = ast_play_and_wait(chan, "vm-youhave");
10664 if (!res) {
10665 if (vms->newmessages) {
10666 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10667 if (!res) {
10668 if (vms->newmessages == 1) {
10669 res = ast_play_and_wait(chan, "vm-message");
10670 if (!res)
10671 res = ast_play_and_wait(chan, "vm-INBOXs");
10672 } else {
10673 res = ast_play_and_wait(chan, "vm-messages");
10674 if (!res)
10675 res = ast_play_and_wait(chan, "vm-INBOX");
10676 }
10677 }
10678 if (vms->oldmessages && !res)
10679 res = ast_play_and_wait(chan, "vm-and");
10680 }
10681 if (!res && vms->oldmessages) {
10682 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10683 if (!res) {
10684 if (vms->oldmessages == 1) {
10685 res = ast_play_and_wait(chan, "vm-message");
10686 if (!res)
10687 res = ast_play_and_wait(chan, "vm-Olds");
10688 } else {
10689 res = ast_play_and_wait(chan, "vm-messages");
10690 if (!res)
10691 res = ast_play_and_wait(chan, "vm-Old");
10692 }
10693 }
10694 }
10695 if (!res) {
10696 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10697 res = ast_play_and_wait(chan, "vm-no");
10698 if (!res)
10699 res = ast_play_and_wait(chan, "vm-messages");
10700 }
10701 }
10702 }
10703 return res;
10704}

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, vm_state::oldmessages, and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_pt_BR()

static int vm_intro_pt_BR ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10520 of file app_voicemail.c.

10520 {
10521 /* Introduce messages they have */
10522 int res;
10523 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10524 res = ast_play_and_wait(chan, "vm-nomessages");
10525 return res;
10526 } else {
10527 res = ast_play_and_wait(chan, "vm-youhave");
10528 }
10529 if (vms->newmessages) {
10530 if (!res)
10531 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10532 if (vms->newmessages == 1) {
10533 if (!res)
10534 res = ast_play_and_wait(chan, "vm-message");
10535 if (!res)
10536 res = ast_play_and_wait(chan, "vm-INBOXs");
10537 } else {
10538 if (!res)
10539 res = ast_play_and_wait(chan, "vm-messages");
10540 if (!res)
10541 res = ast_play_and_wait(chan, "vm-INBOX");
10542 }
10543 if (vms->oldmessages && !res)
10544 res = ast_play_and_wait(chan, "vm-and");
10545 }
10546 if (vms->oldmessages) {
10547 if (!res)
10548 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10549 if (vms->oldmessages == 1) {
10550 if (!res)
10551 res = ast_play_and_wait(chan, "vm-message");
10552 if (!res)
10553 res = ast_play_and_wait(chan, "vm-Olds");
10554 } else {
10555 if (!res)
10556 res = ast_play_and_wait(chan, "vm-messages");
10557 if (!res)
10558 res = ast_play_and_wait(chan, "vm-Old");
10559 }
10560 }
10561 return res;
10562}

References ast_channel_language(), AST_DIGIT_ANY, ast_play_and_wait(), ast_say_number(), vm_state::newmessages, vm_state::oldmessages, and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_se()

static int vm_intro_se ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10285 of file app_voicemail.c.

10286{
10287 /* Introduce messages they have */
10288 int res;
10289
10290 res = ast_play_and_wait(chan, "vm-youhave");
10291 if (res)
10292 return res;
10293
10294 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10295 res = ast_play_and_wait(chan, "vm-no");
10296 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10297 return res;
10298 }
10299
10300 if (vms->newmessages) {
10301 if (vms->newmessages == 1) {
10302 res = ast_play_and_wait(chan, "digits/ett");
10303 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
10304 res = res ? res : ast_play_and_wait(chan, "vm-message");
10305 } else {
10306 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10307 res = res ? res : ast_play_and_wait(chan, "vm-nya");
10308 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10309 }
10310 if (!res && vms->oldmessages)
10311 res = ast_play_and_wait(chan, "vm-and");
10312 }
10313 if (!res && vms->oldmessages) {
10314 if (vms->oldmessages == 1) {
10315 res = ast_play_and_wait(chan, "digits/ett");
10316 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
10317 res = res ? res : ast_play_and_wait(chan, "vm-message");
10318 } else {
10319 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10320 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
10321 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10322 }
10323 }
10324
10325 return res;
10326}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, say_and_wait(), and vm_state::urgentmessages.

Referenced by vm_intro().

◆ vm_intro_vi()

static int vm_intro_vi ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10822 of file app_voicemail.c.

10823{
10824 int res;
10825
10826 /* Introduce messages they have */
10827 res = ast_play_and_wait(chan, "vm-youhave");
10828 if (!res) {
10829 if (vms->newmessages) {
10830 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10831 if (!res)
10832 res = ast_play_and_wait(chan, "vm-INBOX");
10833 if (vms->oldmessages && !res)
10834 res = ast_play_and_wait(chan, "vm-and");
10835 }
10836 if (!res && vms->oldmessages) {
10837 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10838 if (!res)
10839 res = ast_play_and_wait(chan, "vm-Old");
10840 }
10841 if (!res) {
10842 if (!vms->oldmessages && !vms->newmessages) {
10843 res = ast_play_and_wait(chan, "vm-no");
10844 if (!res)
10845 res = ast_play_and_wait(chan, "vm-message");
10846 }
10847 }
10848 }
10849 return res;
10850}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

◆ vm_intro_zh()

static int vm_intro_zh ( struct ast_channel chan,
struct vm_state vms 
)
static

Definition at line 10783 of file app_voicemail.c.

10784{
10785 int res;
10786 /* Introduce messages they have */
10787 res = ast_play_and_wait(chan, "vm-you");
10788
10789 if (!res && vms->newmessages) {
10790 res = ast_play_and_wait(chan, "vm-have");
10791 if (!res)
10792 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10793 if (!res)
10794 res = ast_play_and_wait(chan, "vm-tong");
10795 if (!res)
10796 res = ast_play_and_wait(chan, "vm-INBOX");
10797 if (vms->oldmessages && !res)
10798 res = ast_play_and_wait(chan, "vm-and");
10799 else if (!res)
10800 res = ast_play_and_wait(chan, "vm-messages");
10801 }
10802 if (!res && vms->oldmessages) {
10803 res = ast_play_and_wait(chan, "vm-have");
10804 if (!res)
10805 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10806 if (!res)
10807 res = ast_play_and_wait(chan, "vm-tong");
10808 if (!res)
10809 res = ast_play_and_wait(chan, "vm-Old");
10810 if (!res)
10811 res = ast_play_and_wait(chan, "vm-messages");
10812 }
10813 if (!res && !vms->oldmessages && !vms->newmessages) {
10814 res = ast_play_and_wait(chan, "vm-haveno");
10815 if (!res)
10816 res = ast_play_and_wait(chan, "vm-messages");
10817 }
10818 return res;
10819}

References ast_channel_language(), ast_play_and_wait(), vm_state::newmessages, vm_state::oldmessages, and say_and_wait().

Referenced by vm_intro().

◆ vm_lock_path()

static int vm_lock_path ( const char *  path)
static

Lock file path only return failure if ast_lock_path returns 'timeout', not if the path does not exist or any other reason.

Definition at line 4008 of file app_voicemail.c.

4009{
4010 switch (ast_lock_path(path)) {
4011 case AST_LOCK_TIMEOUT:
4012 return -1;
4013 default:
4014 return 0;
4015 }
4016}
@ AST_LOCK_TIMEOUT
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Definition main/app.c:2615

References ast_lock_path(), and AST_LOCK_TIMEOUT.

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

◆ vm_mailbox_snapshot_create()

static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_create ( const char *  mailbox,
const char *  context,
const char *  folder,
int  descending,
enum ast_vm_snapshot_sort_val  sort_val,
int  combine_INBOX_and_OLD 
)
static

Definition at line 17075 of file app_voicemail.c.

17081{
17082 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
17083 struct vm_state vms;
17084 struct ast_vm_user *vmu = NULL, vmus;
17085 int res;
17086 int i;
17087 int this_index_only = -1;
17088 int open = 0;
17089 int inbox_index = get_folder_by_name("INBOX");
17090 int old_index = get_folder_by_name("Old");
17091 int urgent_index = get_folder_by_name("Urgent");
17092
17093 if (ast_strlen_zero(mailbox)) {
17094 ast_log(LOG_WARNING, "Cannot create a mailbox snapshot since no mailbox was specified\n");
17095 return NULL;
17096 }
17097
17098 memset(&vmus, 0, sizeof(vmus));
17099
17100 if (!(ast_strlen_zero(folder))) {
17101 /* find the folder index */
17102 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
17103 if (!strcasecmp(mailbox_folders[i], folder)) {
17104 this_index_only = i;
17105 break;
17106 }
17107 }
17108 if (this_index_only == -1) {
17109 /* Folder was specified and it did not match any folder in our list */
17110 return NULL;
17111 }
17112 }
17113
17114 if (!(vmu = find_user(&vmus, context, mailbox))) {
17115 ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot for unknown voicemail user %s@%s\n", mailbox, context);
17116 return NULL;
17117 }
17118
17119 if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot)))) {
17120 ast_log(AST_LOG_ERROR, "Failed to allocate memory for mailbox snapshot\n");
17121 free_user(vmu);
17122 return NULL;
17123 }
17124
17125 if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots)))) {
17126 ast_free(mailbox_snapshot);
17127 free_user(vmu);
17128 return NULL;
17129 }
17130
17131 mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders);
17132
17133 for (i = 0; i < mailbox_snapshot->folders; i++) {
17134 int msg_folder_index = i;
17135
17136 /* We want this message in the snapshot if any of the following:
17137 * No folder was specified.
17138 * The specified folder matches the current folder.
17139 * The specified folder is INBOX AND we were asked to combine messages AND the current folder is either Old or Urgent.
17140 */
17141 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
17142 continue;
17143 }
17144
17145 /* Make sure that Old or Urgent messages are marked as being in INBOX. */
17146 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
17147 msg_folder_index = inbox_index;
17148 }
17149
17150 memset(&vms, 0, sizeof(vms));
17151 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
17152 vms.lastmsg = -1;
17153 open = 0;
17154
17155 /* open the mailbox state */
17156 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
17157 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
17158 goto snapshot_cleanup;
17159 }
17160 open = 1;
17161
17162 /* Iterate through each msg, storing off info */
17163 if (vms.lastmsg != -1) {
17164 if ((vm_msg_snapshot_create(vmu, &vms, mailbox_snapshot, msg_folder_index, i, descending, sort_val))) {
17165 ast_log(LOG_WARNING, "Failed to create msg snapshots for %s@%s\n", mailbox, context);
17166 goto snapshot_cleanup;
17167 }
17168 }
17169
17170 /* close mailbox */
17171 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17172 goto snapshot_cleanup;
17173 }
17174 open = 0;
17175 }
17176
17177snapshot_cleanup:
17178 if (vmu && open) {
17179 close_mailbox(&vms, vmu);
17180 }
17181
17182#ifdef IMAP_STORAGE
17183 if (vmu) {
17184 vmstate_delete(&vms);
17185 }
17186#endif
17187
17188 free_user(vmu);
17189 return mailbox_snapshot;
17190}
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.
struct ast_vm_mailbox_snapshot::@192 * snapshots

References ARRAY_LEN, ast_calloc, ast_copy_string(), ast_free, ast_log, AST_LOG_ERROR, AST_LOG_WARNING, ast_strlen_zero(), close_mailbox(), ast_vm_user::context, ERROR_LOCK_PATH, find_user(), ast_vm_mailbox_snapshot::folders, free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, mailbox_folders, NULL, open_mailbox(), ast_vm_mailbox_snapshot::snapshots, vm_state::username, and vm_msg_snapshot_create().

◆ vm_mailbox_snapshot_destroy()

static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_destroy ( struct ast_vm_mailbox_snapshot mailbox_snapshot)
static

Definition at line 17192 of file app_voicemail.c.

17193{
17194 int i;
17195 struct ast_vm_msg_snapshot *msg_snapshot;
17196
17197 for (i = 0; i < mailbox_snapshot->folders; i++) {
17198 while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg))) {
17199 msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
17200 }
17201 }
17202 ast_free(mailbox_snapshot->snapshots);
17203 ast_free(mailbox_snapshot);
17204 return NULL;
17205}
static struct ast_vm_msg_snapshot * vm_msg_snapshot_destroy(struct ast_vm_msg_snapshot *msg_snapshot)

References ast_free, AST_LIST_REMOVE_HEAD, ast_vm_mailbox_snapshot::folders, ast_vm_msg_snapshot::msg, NULL, ast_vm_mailbox_snapshot::snapshots, and vm_msg_snapshot_destroy().

◆ vm_msg_forward()

static int vm_msg_forward ( const char *  from_mailbox,
const char *  from_context,
const char *  from_folder,
const char *  to_mailbox,
const char *  to_context,
const char *  to_folder,
size_t  num_msgs,
const char *  msg_ids[],
int  delete_old 
)
static

Definition at line 17286 of file app_voicemail.c.

17295{
17296 struct vm_state from_vms;
17297 struct ast_vm_user *vmu = NULL, vmus;
17298 struct ast_vm_user *to_vmu = NULL, to_vmus;
17299 struct ast_config *msg_cfg;
17300 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17301 char filename[PATH_MAX];
17302 int from_folder_index;
17303 int open = 0;
17304 int res = 0;
17305 int i;
17306 int *msg_nums;
17307
17308 if (ast_strlen_zero(from_mailbox) || ast_strlen_zero(to_mailbox)) {
17309 ast_log(LOG_WARNING, "Cannot forward message because either the from or to mailbox was not specified\n");
17310 return -1;
17311 }
17312
17313 if (!num_msgs) {
17314 ast_log(LOG_WARNING, "Invalid number of messages specified to forward: %zu\n", num_msgs);
17315 return -1;
17316 }
17317
17318 if (ast_strlen_zero(from_folder) || ast_strlen_zero(to_folder)) {
17319 ast_log(LOG_WARNING, "Cannot forward message because the from_folder or to_folder was not specified\n");
17320 return -1;
17321 }
17322
17323 memset(&vmus, 0, sizeof(vmus));
17324 memset(&to_vmus, 0, sizeof(to_vmus));
17325 memset(&from_vms, 0, sizeof(from_vms));
17326
17327 from_folder_index = get_folder_by_name(from_folder);
17328 if (from_folder_index == -1) {
17329 return -1;
17330 }
17331
17332 if (get_folder_by_name(to_folder) == -1) {
17333 return -1;
17334 }
17335
17336 if (!(vmu = find_user(&vmus, from_context, from_mailbox))) {
17337 ast_log(LOG_WARNING, "Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
17338 return -1;
17339 }
17340
17341 if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) {
17342 ast_log(LOG_WARNING, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
17343 free_user(vmu);
17344 return -1;
17345 }
17346
17347 ast_copy_string(from_vms.username, from_mailbox, sizeof(from_vms.username));
17348 from_vms.lastmsg = -1;
17349 open = 0;
17350
17351 /* open the mailbox state */
17352 if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
17353 ast_log(LOG_WARNING, "Could not open mailbox %s\n", from_mailbox);
17354 res = -1;
17355 goto vm_forward_cleanup;
17356 }
17357
17358 open = 1;
17359
17360 if ((from_vms.lastmsg + 1) < num_msgs) {
17361 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", from_folder, num_msgs);
17362 res = -1;
17363 goto vm_forward_cleanup;
17364 }
17365
17366 msg_nums = ast_alloca(sizeof(int) * num_msgs);
17367
17368 if ((res = message_range_and_existence_check(&from_vms, msg_ids, num_msgs, msg_nums, vmu) < 0)) {
17369 goto vm_forward_cleanup;
17370 }
17371
17372 /* Now we actually forward the messages */
17373 for (i = 0; i < num_msgs; i++) {
17374 int cur_msg = msg_nums[i];
17375 int duration = 0;
17376 const char *value;
17377
17378 make_file(from_vms.fn, sizeof(from_vms.fn), from_vms.curdir, cur_msg);
17379 snprintf(filename, sizeof(filename), "%s.txt", from_vms.fn);
17380 RETRIEVE(from_vms.curdir, cur_msg, vmu->mailbox, vmu->context);
17381 msg_cfg = ast_config_load(filename, config_flags);
17382 /* XXX This likely will not fail since we previously ensured that the
17383 * message we are looking for exists. However, there still could be some
17384 * circumstance where this fails, so atomicity is not guaranteed.
17385 */
17386 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17387 DISPOSE(from_vms.curdir, cur_msg);
17388 continue;
17389 }
17390 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
17391 duration = atoi(value);
17392 }
17393
17394 copy_message(NULL, vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir, "", to_folder);
17395
17396 if (delete_old) {
17397 from_vms.deleted[cur_msg] = 1;
17398 }
17399 ast_config_destroy(msg_cfg);
17400 DISPOSE(from_vms.curdir, cur_msg);
17401 }
17402
17403 /* close mailbox */
17404 if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH)) {
17405 res = -1;
17406 goto vm_forward_cleanup;
17407 }
17408 open = 0;
17409
17410vm_forward_cleanup:
17411 if (vmu && open) {
17412 close_mailbox(&from_vms, vmu);
17413 }
17414#ifdef IMAP_STORAGE
17415 if (vmu) {
17416 vmstate_delete(&from_vms);
17417 }
17418#endif
17419
17420 if (!res) {
17421 notify_new_state(to_vmu);
17422 }
17423
17424 free_user(vmu);
17425 free_user(to_vmu);
17426 return res;
17427}

References ast_alloca, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log, ast_strlen_zero(), ast_variable_retrieve(), close_mailbox(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, copy_message(), vm_state::curdir, vm_state::deleted, DISPOSE, ERROR_LOCK_PATH, find_user(), vm_state::fn, free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), message_range_and_existence_check(), notify_new_state(), NULL, open_mailbox(), PATH_MAX, RETRIEVE, vm_state::username, value, and vmfmts.

Referenced by forward_message_from_mailbox(), and manager_voicemail_forward().

◆ vm_msg_move()

static int vm_msg_move ( const char *  mailbox,
const char *  context,
size_t  num_msgs,
const char *  oldfolder,
const char *  old_msg_ids[],
const char *  newfolder 
)
static

Definition at line 17429 of file app_voicemail.c.

17435{
17436 struct vm_state vms;
17437 struct ast_vm_user *vmu = NULL, vmus;
17438 int old_folder_index;
17439 int new_folder_index;
17440 int open = 0;
17441 int res = 0;
17442 int i;
17443 int *old_msg_nums;
17444
17445 if (ast_strlen_zero(mailbox)) {
17446 ast_log(LOG_WARNING, "Cannot move message because no mailbox was specified\n");
17447 return -1;
17448 }
17449
17450 if (!num_msgs) {
17451 ast_log(LOG_WARNING, "Invalid number of messages specified to move: %zu\n", num_msgs);
17452 return -1;
17453 }
17454
17455 if (ast_strlen_zero(oldfolder) || ast_strlen_zero(newfolder)) {
17456 ast_log(LOG_WARNING, "Cannot move message because either oldfolder or newfolder was not specified\n");
17457 return -1;
17458 }
17459
17460 old_folder_index = get_folder_by_name(oldfolder);
17461 new_folder_index = get_folder_by_name(newfolder);
17462
17463 memset(&vmus, 0, sizeof(vmus));
17464 memset(&vms, 0, sizeof(vms));
17465
17466 if (old_folder_index == -1 || new_folder_index == -1) {
17467 return -1;
17468 }
17469
17470 if (!(vmu = find_user(&vmus, context, mailbox))) {
17471 return -1;
17472 }
17473
17474 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
17475 vms.lastmsg = -1;
17476 open = 0;
17477
17478 /* open the mailbox state */
17479 if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
17480 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
17481 res = -1;
17482 goto vm_move_cleanup;
17483 }
17484
17485 open = 1;
17486
17487 if ((vms.lastmsg + 1) < num_msgs) {
17488 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", oldfolder, num_msgs);
17489 res = -1;
17490 goto vm_move_cleanup;
17491 }
17492
17493 old_msg_nums = ast_alloca(sizeof(int) * num_msgs);
17494
17495 if ((res = message_range_and_existence_check(&vms, old_msg_ids, num_msgs, old_msg_nums, vmu)) < 0) {
17496 goto vm_move_cleanup;
17497 }
17498
17499 /* Now actually move the message */
17500 for (i = 0; i < num_msgs; ++i) {
17501 if (save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, NULL, 0)) {
17502 res = -1;
17503 goto vm_move_cleanup;
17504 }
17505 vms.deleted[old_msg_nums[i]] = 1;
17506 }
17507
17508 /* close mailbox */
17509 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17510 res = -1;
17511 goto vm_move_cleanup;
17512 }
17513 open = 0;
17514
17515vm_move_cleanup:
17516 if (vmu && open) {
17517 close_mailbox(&vms, vmu);
17518 }
17519#ifdef IMAP_STORAGE
17520 if (vmu) {
17521 vmstate_delete(&vms);
17522 }
17523#endif
17524
17525 if (!res) {
17526 notify_new_state(vmu);
17527 }
17528
17529 free_user(vmu);
17530 return res;
17531}

References ast_alloca, ast_copy_string(), ast_log, ast_strlen_zero(), close_mailbox(), ast_vm_user::context, vm_state::deleted, ERROR_LOCK_PATH, find_user(), free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, message_range_and_existence_check(), notify_new_state(), NULL, open_mailbox(), save_to_folder(), and vm_state::username.

Referenced by manager_voicemail_move(), and move_message_from_mailbox().

◆ vm_msg_play()

static int vm_msg_play ( struct ast_channel chan,
const char *  mailbox,
const char *  context,
const char *  folder,
const char *  msg_num,
ast_vm_msg_play_cb  cb 
)
static

Definition at line 17631 of file app_voicemail.c.

17637{
17638 struct vm_state vms;
17639 struct ast_vm_user *vmu = NULL, vmus;
17640 int res = 0;
17641 int open = 0;
17642 int i;
17643 char filename[PATH_MAX];
17644 struct ast_config *msg_cfg;
17645 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17646 int duration = 0;
17647 const char *value;
17648
17649 if (ast_strlen_zero(mailbox)) {
17650 ast_log(LOG_WARNING, "Cannot play message because no mailbox was specified\n");
17651 return -1;
17652 }
17653
17654 if (ast_strlen_zero(folder)) {
17655 ast_log(LOG_WARNING, "Cannot play message because no folder was specified\n");
17656 return -1;
17657 }
17658
17659 if (ast_strlen_zero(msg_id)) {
17660 ast_log(LOG_WARNING, "Cannot play message because no message number was specified\n");
17661 return -1;
17662 }
17663
17664 memset(&vmus, 0, sizeof(vmus));
17665 memset(&vms, 0, sizeof(vms));
17666
17667 if (ast_strlen_zero(context)) {
17668 context = "default";
17669 }
17670
17671 if (!(vmu = find_user(&vmus, context, mailbox))) {
17672 return -1;
17673 }
17674
17675 i = get_folder_by_name(folder);
17676 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
17677 vms.lastmsg = -1;
17678 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
17679 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
17680 goto play2_msg_cleanup;
17681 }
17682 open = 1;
17683
17684 if (message_range_and_existence_check(&vms, &msg_id, 1, &vms.curmsg, vmu)) {
17685 res = -1;
17686 goto play2_msg_cleanup;
17687 }
17688
17689 /* Find the msg */
17690 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
17691 snprintf(filename, sizeof(filename), "%s.txt", vms.fn);
17692 RETRIEVE(vms.curdir, vms.curmsg, vmu->mailbox, vmu->context);
17693
17694 msg_cfg = ast_config_load(filename, config_flags);
17695 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17696 DISPOSE(vms.curdir, vms.curmsg);
17697 res = -1;
17698 goto play2_msg_cleanup;
17699 }
17700 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
17701 duration = atoi(value);
17702 }
17703 ast_config_destroy(msg_cfg);
17704
17705#ifdef IMAP_STORAGE
17706 /*IMAP storage stores any prepended message from a forward
17707 * as a separate file from the rest of the message
17708 */
17709 if (!ast_strlen_zero(vms.introfn) && ast_fileexists(vms.introfn, NULL, NULL) > 0) {
17710 wait_file(chan, &vms, vms.introfn);
17711 }
17712#endif
17713 if (cb) {
17714 cb(chan, vms.fn, duration);
17715 } else if ((wait_file(chan, &vms, vms.fn)) < 0) {
17716 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms.fn);
17717 } else {
17718 res = 0;
17719 }
17720
17721 vms.heard[vms.curmsg] = 1;
17722
17723 /* cleanup configs and msg */
17724 DISPOSE(vms.curdir, vms.curmsg);
17725
17726play2_msg_cleanup:
17727 if (vmu && open) {
17728 close_mailbox(&vms, vmu);
17729 }
17730
17731#ifdef IMAP_STORAGE
17732 if (vmu) {
17733 vmstate_delete(&vms);
17734 }
17735#endif
17736
17737 if (!res) {
17738 notify_new_state(vmu);
17739 }
17740
17741 free_user(vmu);
17742 return res;
17743}

References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_fileexists(), ast_log, AST_LOG_WARNING, ast_strlen_zero(), ast_variable_retrieve(), close_mailbox(), CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, find_user(), vm_state::fn, free_user(), get_folder_by_name(), vm_state::heard, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, make_file(), message_range_and_existence_check(), notify_new_state(), NULL, open_mailbox(), PATH_MAX, RETRIEVE, vm_state::username, value, and wait_file().

◆ vm_msg_remove()

static int vm_msg_remove ( const char *  mailbox,
const char *  context,
size_t  num_msgs,
const char *  folder,
const char *  msgs[] 
)
static

Definition at line 17533 of file app_voicemail.c.

17538{
17539 struct vm_state vms;
17540 struct ast_vm_user *vmu = NULL, vmus;
17541 int folder_index;
17542 int open = 0;
17543 int res = 0;
17544 int i;
17545 int *msg_nums;
17546
17547 if (ast_strlen_zero(mailbox)) {
17548 ast_log(LOG_WARNING, "Cannot remove message because no mailbox was specified\n");
17549 return -1;
17550 }
17551
17552 if (!num_msgs) {
17553 ast_log(LOG_WARNING, "Invalid number of messages specified to remove: %zu\n", num_msgs);
17554 return -1;
17555 }
17556
17557 if (ast_strlen_zero(folder)) {
17558 ast_log(LOG_WARNING, "Cannot remove message because no folder was specified\n");
17559 return -1;
17560 }
17561
17562 memset(&vmus, 0, sizeof(vmus));
17563 memset(&vms, 0, sizeof(vms));
17564
17565 folder_index = get_folder_by_name(folder);
17566 if (folder_index == -1) {
17567 ast_log(LOG_WARNING, "Could not remove msgs from unknown folder %s\n", folder);
17568 return -1;
17569 }
17570
17571 if (!(vmu = find_user(&vmus, context, mailbox))) {
17572 ast_log(LOG_WARNING, "Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
17573 return -1;
17574 }
17575
17576 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
17577 vms.lastmsg = -1;
17578 open = 0;
17579
17580 /* open the mailbox state */
17581 if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
17582 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
17583 res = -1;
17584 goto vm_remove_cleanup;
17585 }
17586
17587 open = 1;
17588
17589 if ((vms.lastmsg + 1) < num_msgs) {
17590 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", folder, num_msgs);
17591 res = -1;
17592 goto vm_remove_cleanup;
17593 }
17594
17595 msg_nums = ast_alloca(sizeof(int) * num_msgs);
17596
17597 if ((res = message_range_and_existence_check(&vms, msgs, num_msgs, msg_nums, vmu)) < 0) {
17598 goto vm_remove_cleanup;
17599 }
17600
17601 for (i = 0; i < num_msgs; i++) {
17602 vms.deleted[msg_nums[i]] = 1;
17603 }
17604
17605 /* close mailbox */
17606 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17607 res = -1;
17608 ast_log(AST_LOG_ERROR, "Failed to close mailbox folder %s while removing msgs\n", folder);
17609 goto vm_remove_cleanup;
17610 }
17611 open = 0;
17612
17613vm_remove_cleanup:
17614 if (vmu && open) {
17615 close_mailbox(&vms, vmu);
17616 }
17617#ifdef IMAP_STORAGE
17618 if (vmu) {
17619 vmstate_delete(&vms);
17620 }
17621#endif
17622
17623 if (!res) {
17624 notify_new_state(vmu);
17625 }
17626
17627 free_user(vmu);
17628 return res;
17629}

References ast_alloca, ast_copy_string(), ast_log, AST_LOG_ERROR, ast_strlen_zero(), close_mailbox(), ast_vm_user::context, vm_state::deleted, ERROR_LOCK_PATH, find_user(), free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, message_range_and_existence_check(), notify_new_state(), NULL, open_mailbox(), and vm_state::username.

Referenced by manager_voicemail_remove(), and remove_message_from_mailbox().

◆ vm_msg_snapshot_alloc()

static struct ast_vm_msg_snapshot * vm_msg_snapshot_alloc ( void  )
static

Definition at line 16892 of file app_voicemail.c.

16893{
16894 struct ast_vm_msg_snapshot *msg_snapshot;
16895
16896 if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot)))) {
16897 return NULL;
16898 }
16899
16900 if (ast_string_field_init(msg_snapshot, 512)) {
16901 ast_free(msg_snapshot);
16902 return NULL;
16903 }
16904
16905 return msg_snapshot;
16906}
#define ast_string_field_init(x, size)
Initialize a field pool and fields.

References ast_calloc, ast_free, ast_string_field_init, and NULL.

Referenced by vm_msg_snapshot_create().

◆ vm_msg_snapshot_create()

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

16967{
16968 struct ast_vm_msg_snapshot *msg_snapshot;
16969 struct ast_vm_msg_snapshot *msg_snapshot_tmp;
16970 struct ast_config *msg_cfg;
16971 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
16972 char filename[PATH_MAX];
16973 const char *value;
16974
16975 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
16976 int inserted = 0;
16977 /* Find the msg */
16978 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
16979 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
16980 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
16981 msg_cfg = ast_config_load(filename, config_flags);
16982 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
16983 DISPOSE(vms->curdir, vms->curmsg);
16984 continue;
16985 }
16986
16987 /* Create the snapshot object */
16988 if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
16989 ast_config_destroy(msg_cfg);
16990 return -1;
16991 }
16992
16993 /* Fill in the snapshot object */
16994 if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
16995 ast_string_field_set(msg_snapshot, msg_id, value);
16996 } else {
16997 /* Message snapshots *really* should have a
16998 * message ID. Add one to the message config
16999 * if it does not already exist
17000 */
17001 char id[MSG_ID_LEN];
17002 if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
17003 filename, id, sizeof(id), vmu, mailbox_index))) {
17004 ast_string_field_set(msg_snapshot, msg_id, id);
17005 } else {
17006 ast_log(LOG_WARNING, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
17007 }
17008 }
17009 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
17010 ast_string_field_set(msg_snapshot, callerid, value);
17011 }
17012 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
17013 ast_string_field_set(msg_snapshot, callerchan, value);
17014 }
17015 if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
17016 ast_string_field_set(msg_snapshot, exten, value);
17017 }
17018 if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
17019 ast_string_field_set(msg_snapshot, origdate, value);
17020 }
17021 if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
17022 ast_string_field_set(msg_snapshot, origtime, value);
17023 }
17024 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
17025 ast_string_field_set(msg_snapshot, duration, value);
17026 }
17027 if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
17028 ast_string_field_set(msg_snapshot, flag, value);
17029 }
17030 msg_snapshot->msg_number = vms->curmsg;
17031 ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);
17032
17033 /* store msg snapshot in mailbox snapshot */
17034 switch (sort_val) {
17035 default:
17037 if (descending) {
17038 AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17039 } else {
17040 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17041 }
17042 inserted = 1;
17043 break;
17045 AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
17046 int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
17047 if (descending && val >= 0) {
17048 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17049 inserted = 1;
17050 break;
17051 } else if (!descending && val <= 0) {
17052 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17053 inserted = 1;
17054 break;
17055 }
17056 }
17058 break;
17059 }
17060
17061 if (!inserted) {
17062 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17063 }
17064
17065 mailbox_snapshot->total_msg_num++;
17066
17067 /* cleanup configs and msg */
17068 ast_config_destroy(msg_cfg);
17069 DISPOSE(vms->curdir, vms->curmsg);
17070 }
17071
17072 return 0;
17073}
static struct ast_vm_msg_snapshot * vm_msg_snapshot_alloc(void)
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)
@ AST_VM_SNAPSHOT_SORT_BY_TIME
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
const ast_string_field origtime

References add_message_id(), ast_config_destroy(), ast_config_load, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, ast_string_field_set, ast_variable_retrieve(), AST_VM_SNAPSHOT_SORT_BY_ID, AST_VM_SNAPSHOT_SORT_BY_TIME, CONFIG_FLAG_NOCACHE, CONFIG_STATUS_FILEINVALID, ast_vm_user::context, vm_state::curdir, vm_state::curmsg, DISPOSE, vm_state::fn, vm_state::lastmsg, LOG_WARNING, ast_vm_user::mailbox, mailbox_folders, make_file(), MSG_ID_LEN, ast_vm_msg_snapshot::msg_number, ast_vm_msg_snapshot::origtime, PATH_MAX, RETRIEVE, ast_vm_mailbox_snapshot::snapshots, ast_vm_mailbox_snapshot::total_msg_num, value, and vm_msg_snapshot_alloc().

Referenced by vm_mailbox_snapshot_create().

◆ vm_msg_snapshot_destroy()

static struct ast_vm_msg_snapshot * vm_msg_snapshot_destroy ( struct ast_vm_msg_snapshot msg_snapshot)
static

Definition at line 16908 of file app_voicemail.c.

16909{
16910 ast_string_field_free_memory(msg_snapshot);
16911 ast_free(msg_snapshot);
16912
16913 return NULL;
16914}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object

References ast_free, ast_string_field_free_memory, and NULL.

Referenced by vm_mailbox_snapshot_destroy().

◆ vm_newuser_setup()

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

Definition at line 11135 of file app_voicemail.c.

11136{
11137 int cmd = 0;
11138 int duration = 0;
11139 int tries = 0;
11140 char newpassword[80] = "";
11141 char newpassword2[80] = "";
11142 char prefile[PATH_MAX] = "";
11143 unsigned char buf[256];
11144 int bytes = 0;
11145
11146 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
11147 if (ast_adsi_available(chan)) {
11148 bytes += adsi_logo(buf + bytes);
11149 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
11150 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
11151 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
11152 bytes += ast_adsi_voice_mode(buf + bytes, 0);
11154 }
11155
11156 /* If forcename is set, have the user record their name */
11157 if (ast_test_flag(vmu, VM_FORCENAME)) {
11158 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
11159 if (ast_fileexists(prefile, NULL, NULL) < 1) {
11160 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11161 if (cmd < 0 || cmd == 't' || cmd == '#')
11162 return cmd;
11163 }
11164 }
11165
11166 /* If forcegreetings is set, have the user record their greetings */
11167 if (ast_test_flag(vmu, VM_FORCEGREET)) {
11168 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
11169 if (ast_fileexists(prefile, NULL, NULL) < 1) {
11170 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11171 if (cmd < 0 || cmd == 't' || cmd == '#')
11172 return cmd;
11173 }
11174
11175 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
11176 if (ast_fileexists(prefile, NULL, NULL) < 1) {
11177 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11178 if (cmd < 0 || cmd == 't' || cmd == '#')
11179 return cmd;
11180 }
11181 }
11182
11183 /*
11184 * Change the password last since new users will be able to skip over any steps this one comes before
11185 * by hanging up and calling back to voicemail main since the password is used to verify new user status.
11186 */
11187 for (;;) {
11188 newpassword[1] = '\0';
11189 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
11190 if (cmd == '#')
11191 newpassword[0] = '\0';
11192 if (cmd < 0 || cmd == 't' || cmd == '#')
11193 return cmd;
11194 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
11195 if (cmd < 0 || cmd == 't' || cmd == '#')
11196 return cmd;
11197 cmd = check_password(vmu, newpassword); /* perform password validation */
11198 if (cmd != 0) {
11199 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
11201 } else {
11202 newpassword2[1] = '\0';
11203 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
11204 if (cmd == '#')
11205 newpassword2[0] = '\0';
11206 if (cmd < 0 || cmd == 't' || cmd == '#')
11207 return cmd;
11208 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
11209 if (cmd < 0 || cmd == 't' || cmd == '#')
11210 return cmd;
11211 if (!strcmp(newpassword, newpassword2))
11212 break;
11213 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
11214 cmd = ast_play_and_wait(chan, vm_mismatch);
11215 }
11216 if (++tries == 3)
11217 return -1;
11218 if (cmd != 0) {
11220 }
11221 }
11223 vm_change_password(vmu, newpassword);
11225 vm_change_password_shell(vmu, newpassword);
11226
11227 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
11228 cmd = ast_play_and_wait(chan, vm_passchanged);
11229
11230 return cmd;
11231}
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
The handler for the change password option.
static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
static void check_password(void)
Definition pbx_dundi.c:2192

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_debug, ast_fileexists(), ast_log, AST_LOG_NOTICE, ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, buf, check_password(), ast_vm_user::context, ext_pass_cmd, maxgreet, NULL, PATH_MAX, play_record_review(), pwdchange, PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, vm_state::username, vm_change_password(), vm_change_password_shell(), VM_FORCEGREET, VM_FORCENAME, vm_invalid_password, vm_mismatch, vm_newpassword, vm_passchanged, vm_pls_try_again, vm_reenterpassword, and VM_SPOOL_DIR.

Referenced by vm_execmain().

◆ vm_options()

static int vm_options ( struct ast_channel chan,
struct ast_vm_user vmu,
struct vm_state vms,
char *  fmtc,
signed char  record_gain 
)
static

Definition at line 11233 of file app_voicemail.c.

11234{
11235 int cmd = 0;
11236 int retries = 0;
11237 int duration = 0;
11238 char newpassword[80] = "";
11239 char newpassword2[80] = "";
11240 char prefile[PATH_MAX] = "";
11241 unsigned char buf[256];
11242 int bytes = 0;
11243 SCOPE_ENTER(3, "%s: %s entering mailbox options", ast_channel_name(chan), vms->username);
11244
11245 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
11246 if (ast_adsi_available(chan)) {
11247 bytes += adsi_logo(buf + bytes);
11248 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
11249 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
11250 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
11251 bytes += ast_adsi_voice_mode(buf + bytes, 0);
11253 }
11254 while ((cmd >= 0) && (cmd != 't')) {
11255 if (cmd)
11256 retries = 0;
11257 switch (cmd) {
11258 case '1': /* Record your unavailable message */
11259 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
11260 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_record_review, chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11261 break;
11262 case '2': /* Record your busy message */
11263 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
11264 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_record_review, chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11265 break;
11266 case '3': /* Record greeting */
11267 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
11268 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_record_review, chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11269 break;
11270 case '4': /* manage the temporary greeting */
11271 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
11272 break;
11273 case '5': /* change password */
11274 if (vmu->password[0] == '-') {
11275 cmd = ast_play_and_wait(chan, "vm-no");
11276 break;
11277 }
11278 newpassword[1] = '\0';
11279 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
11280 if (cmd == '#')
11281 newpassword[0] = '\0';
11282 else {
11283 if (cmd < 0)
11284 break;
11285 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
11286 break;
11287 }
11288 }
11289 cmd = check_password(vmu, newpassword); /* perform password validation */
11290 if (cmd != 0) {
11291 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
11293 if (!cmd) {
11295 }
11296 break;
11297 }
11298 newpassword2[1] = '\0';
11299 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
11300 if (cmd == '#')
11301 newpassword2[0] = '\0';
11302 else {
11303 if (cmd < 0)
11304 break;
11305
11306 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
11307 break;
11308 }
11309 }
11310 if (strcmp(newpassword, newpassword2)) {
11311 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
11312 cmd = ast_play_and_wait(chan, vm_mismatch);
11313 if (!cmd) {
11315 }
11316 break;
11317 }
11318
11320 vm_change_password(vmu, newpassword);
11321 }
11323 vm_change_password_shell(vmu, newpassword);
11324 }
11325
11326 ast_debug(1, "User %s set password to %s of length %d\n",
11327 vms->username, newpassword, (int) strlen(newpassword));
11328 cmd = ast_play_and_wait(chan, vm_passchanged);
11329 break;
11330 case '*':
11331 cmd = 't';
11332 break;
11333 default:
11334 cmd = 0;
11335 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
11336 SCOPE_CALL(-1, RETRIEVE, prefile, -1, vmu->mailbox, vmu->context);
11337 if (ast_fileexists(prefile, NULL, NULL)) {
11338 cmd = ast_play_and_wait(chan, "vm-tmpexists");
11339 }
11340 SCOPE_CALL(-1, DISPOSE, prefile, -1);
11341 if (!cmd) {
11342 cmd = ast_play_and_wait(chan, "vm-options");
11343 }
11344 if (!cmd) {
11345 cmd = ast_waitfordigit(chan, 6000);
11346 }
11347 if (!cmd) {
11348 retries++;
11349 }
11350 if (retries > 3) {
11351 cmd = 't';
11352 }
11353 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
11354 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
11355 }
11356 }
11357 if (cmd == 't')
11358 cmd = 0;
11359 SCOPE_EXIT_RTN_VALUE(cmd, "Done\n");
11360}
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'.

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_channel_name(), ast_debug, ast_fileexists(), ast_log, AST_LOG_NOTICE, ast_play_and_wait(), ast_readstring(), ast_strlen_zero(), ast_test_suite_event_notify, ast_waitfordigit(), buf, check_password(), ast_vm_user::context, DISPOSE, ext_pass_cmd, ast_vm_user::mailbox, maxgreet, NULL, ast_vm_user::password, PATH_MAX, play_record_review(), pwdchange, PWDCHANGE_EXTERNAL, PWDCHANGE_INTERNAL, RETRIEVE, SCOPE_CALL, SCOPE_CALL_WITH_INT_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, vm_state::username, vm_change_password(), vm_change_password_shell(), vm_invalid_password, vm_mismatch, vm_newpassword, vm_passchanged, vm_pls_try_again, vm_reenterpassword, VM_SPOOL_DIR, and vm_tempgreeting().

Referenced by vm_execmain().

◆ vm_play_folder_name()

static int vm_play_folder_name ( struct ast_channel chan,
char *  mbox 
)
static

Definition at line 9774 of file app_voicemail.c.

9775{
9776 int cmd;
9777
9778 if ( !strncasecmp(ast_channel_language(chan), "it", 2) ||
9779 !strncasecmp(ast_channel_language(chan), "es", 2) ||
9780 !strncasecmp(ast_channel_language(chan), "pt", 2)) { /* Italian, Spanish, or Portuguese syntax */
9781 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
9782 return cmd ? cmd : ast_play_and_wait(chan, box);
9783 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
9784 return vm_play_folder_name_gr(chan, box);
9785 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* Hebrew syntax */
9786 return ast_play_and_wait(chan, box);
9787 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
9788 return vm_play_folder_name_ja(chan, box);
9789 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9790 return vm_play_folder_name_pl(chan, box);
9791 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* Ukrainian syntax */
9792 return vm_play_folder_name_ua(chan, box);
9793 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
9794 return ast_play_and_wait(chan, box);
9795 } else { /* Default English */
9796 cmd = ast_play_and_wait(chan, box);
9797 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages */
9798 }
9799}
static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
static int vm_play_folder_name_ja(struct ast_channel *chan, char *box)

References ast_channel_language(), ast_play_and_wait(), vm_play_folder_name_gr(), vm_play_folder_name_ja(), vm_play_folder_name_pl(), and vm_play_folder_name_ua().

Referenced by get_folder(), get_folder_ja(), vm_execmain(), vm_instructions_en(), vm_instructions_ja(), and vm_instructions_zh().

◆ vm_play_folder_name_gr()

static int vm_play_folder_name_gr ( struct ast_channel chan,
char *  box 
)
static

Definition at line 9714 of file app_voicemail.c.

9715{
9716 int cmd;
9717 char *buf;
9718
9719 buf = ast_alloca(strlen(box) + 2);
9720 strcpy(buf, box);
9721 strcat(buf, "s");
9722
9723 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
9724 cmd = ast_play_and_wait(chan, buf); /* "NEA / PALIA" */
9725 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9726 } else {
9727 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9728 return cmd ? cmd : ast_play_and_wait(chan, box); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
9729 }
9730}

References ast_alloca, ast_play_and_wait(), and buf.

Referenced by vm_play_folder_name().

◆ vm_play_folder_name_ja()

static int vm_play_folder_name_ja ( struct ast_channel chan,
char *  box 
)
static

Definition at line 9732 of file app_voicemail.c.

9733{
9734 int cmd;
9735
9736 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9737 cmd = ast_play_and_wait(chan, box);
9738 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9739 } else {
9740 cmd = ast_play_and_wait(chan, box);
9741 return cmd;
9742 }
9743}

References ast_play_and_wait().

Referenced by vm_play_folder_name().

◆ vm_play_folder_name_pl()

static int vm_play_folder_name_pl ( struct ast_channel chan,
char *  box 
)
static

Definition at line 9745 of file app_voicemail.c.

9746{
9747 int cmd;
9748
9749 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9750 if (!strcasecmp(box, "vm-INBOX"))
9751 cmd = ast_play_and_wait(chan, "vm-new-e");
9752 else
9753 cmd = ast_play_and_wait(chan, "vm-old-e");
9754 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9755 } else {
9756 cmd = ast_play_and_wait(chan, "vm-messages");
9757 return cmd ? cmd : ast_play_and_wait(chan, box);
9758 }
9759}

References ast_play_and_wait().

Referenced by vm_play_folder_name().

◆ vm_play_folder_name_ua()

static int vm_play_folder_name_ua ( struct ast_channel chan,
char *  box 
)
static

Definition at line 9761 of file app_voicemail.c.

9762{
9763 int cmd;
9764
9765 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
9766 cmd = ast_play_and_wait(chan, "vm-messages");
9767 return cmd ? cmd : ast_play_and_wait(chan, box);
9768 } else {
9769 cmd = ast_play_and_wait(chan, box);
9770 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9771 }
9772}

References ast_play_and_wait().

Referenced by vm_play_folder_name().

◆ vm_playmsgexec()

static int vm_playmsgexec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 11956 of file app_voicemail.c.

11957{
11958 char *parse;
11959 char *mailbox = NULL;
11960 char *context = NULL;
11961 int res;
11962
11964 AST_APP_ARG(mailbox);
11965 AST_APP_ARG(msg_id);
11966 );
11967
11968 if (ast_channel_state(chan) != AST_STATE_UP) {
11969 ast_debug(1, "Before ast_answer\n");
11970 ast_answer(chan);
11971 }
11972
11973 if (ast_strlen_zero(data)) {
11974 return -1;
11975 }
11976
11977 parse = ast_strdupa(data);
11979
11980 if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
11981 return -1;
11982 }
11983
11984 if ((context = strchr(args.mailbox, '@'))) {
11985 *context++ = '\0';
11986 }
11987 mailbox = args.mailbox;
11988
11989 res = play_message_by_id(chan, mailbox, context, args.msg_id);
11990 pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
11991
11992 return 0;
11993}
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.

References args, ast_answer(), AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_vm_user::context, ast_vm_user::mailbox, NULL, pbx_builtin_setvar_helper(), and play_message_by_id().

Referenced by load_module().

◆ vm_sayname()

static int vm_sayname ( struct ast_channel chan,
const char *  mailbox_id 
)
static

Definition at line 15500 of file app_voicemail.c.

15501{
15502 char *context;
15503 char *mailbox;
15504
15505 if (ast_strlen_zero(mailbox_id)
15506 || separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
15507 return -1;
15508 }
15509 return sayname(chan, mailbox, context);
15510}
static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)

References ast_strdupa, ast_strlen_zero(), sayname(), and separate_mailbox().

◆ vm_tempgreeting()

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_gain

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

11379{
11380 int cmd = 0;
11381 int retries = 0;
11382 int duration = 0;
11383 char prefile[PATH_MAX] = "";
11384 unsigned char buf[256];
11385 int bytes = 0;
11386
11387 if (ast_adsi_available(chan)) {
11388 bytes += adsi_logo(buf + bytes);
11389 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
11390 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
11391 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
11392 bytes += ast_adsi_voice_mode(buf + bytes, 0);
11394 }
11395
11396 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
11397 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
11398 while ((cmd >= 0) && (cmd != 't')) {
11399 if (cmd)
11400 retries = 0;
11401 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
11402 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
11403 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11404 if (cmd == -1) {
11405 break;
11406 }
11407 cmd = 't';
11408 } else {
11409 switch (cmd) {
11410 case '1':
11411 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11412 break;
11413 case '2':
11414 DELETE(prefile, -1, prefile, vmu);
11415 ast_play_and_wait(chan, "vm-tempremoved");
11416 cmd = 't';
11417 break;
11418 case '*':
11419 cmd = 't';
11420 break;
11421 default:
11422 cmd = ast_play_and_wait(chan,
11423 ast_fileexists(prefile, NULL, NULL) > 0 ? /* XXX always true ? */
11424 "vm-tempgreeting2" : "vm-tempgreeting");
11425 if (!cmd) {
11426 cmd = ast_waitfordigit(chan, 6000);
11427 }
11428 if (!cmd) {
11429 retries++;
11430 }
11431 if (retries > 3) {
11432 cmd = 't';
11433 }
11434 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
11435 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
11436 }
11437 }
11438 DISPOSE(prefile, -1);
11439 }
11440 if (cmd == 't')
11441 cmd = 0;
11442 return cmd;
11443}

References ADSI_COMM_PAGE, ADSI_JUST_CENT, adsi_logo(), ADSI_MSG_DISPLAY, ast_adsi_available(), ast_adsi_display(), ast_adsi_set_line(), ast_adsi_transmit_message(), ast_adsi_voice_mode(), ast_fileexists(), ast_play_and_wait(), ast_test_suite_event_notify, ast_waitfordigit(), buf, ast_vm_user::context, DELETE, DISPOSE, ast_vm_user::mailbox, maxgreet, NULL, PATH_MAX, play_record_review(), RETRIEVE, vm_state::username, and VM_SPOOL_DIR.

Referenced by vm_options().

◆ vmauthenticate()

static int vmauthenticate ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 13700 of file app_voicemail.c.

13701{
13702 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
13703 struct ast_vm_user vmus = {{0}};
13704 char *options = NULL;
13705 int silent = 0, skipuser = 0;
13706 int res = -1;
13707
13708 if (data) {
13709 s = ast_strdupa(data);
13710 user = strsep(&s, ",");
13711 options = strsep(&s, ",");
13712 if (user) {
13713 s = user;
13714 user = strsep(&s, "@");
13715 context = strsep(&s, "");
13716 if (!ast_strlen_zero(user))
13717 skipuser++;
13719 }
13720 }
13721
13722 if (options) {
13723 silent = (strchr(options, 's')) != NULL;
13724 }
13725
13726 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
13727 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
13728 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
13729 ast_play_and_wait(chan, "auth-thankyou");
13730 res = 0;
13731 } else if (mailbox[0] == '*') {
13732 /* user entered '*' */
13733 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
13734 res = 0; /* prevent hangup */
13735 }
13736 }
13737
13738 return res;
13739}
structure to hold users read from phoneprov_users.conf

References ast_channel_context(), ast_copy_string(), ast_goto_if_exists(), AST_MAX_EXTENSION, ast_play_and_wait(), ast_strdupa, ast_strlen_zero(), ast_vm_user::context, ast_vm_user::mailbox, NULL, options, pbx_builtin_setvar_helper(), strsep(), and vm_authenticate().

Referenced by load_module().

◆ vmsayname_exec()

static int vmsayname_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 15562 of file app_voicemail.c.

15563{
15564 char *context;
15565 char *mailbox;
15566 int res;
15567
15568 if (ast_strlen_zero(data)
15569 || separate_mailbox(ast_strdupa(data), &mailbox, &context)) {
15570 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
15571 return -1;
15572 }
15573
15574 if ((res = sayname(chan, mailbox, context)) < 0) {
15575 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", mailbox, context);
15576 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
15577 if (!res) {
15579 }
15580 }
15581
15582 return res;
15583}
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
Definition channel.c:8377
@ AST_SAY_CASE_NONE
Definition say.h:182

References ast_channel_language(), ast_debug, AST_DIGIT_ANY, ast_log, AST_SAY_CASE_NONE, ast_say_character_str(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), LOG_WARNING, sayname(), and separate_mailbox().

Referenced by load_module().

◆ vmu_tm()

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

5330{
5331 const struct vm_zone *z = NULL;
5332 struct timeval t = ast_tvnow();
5333
5334 /* Does this user have a timezone specified? */
5335 if (!ast_strlen_zero(vmu->zonetag)) {
5336 /* Find the zone in the list */
5338 AST_LIST_TRAVERSE(&zones, z, list) {
5339 if (!strcmp(z->name, vmu->zonetag))
5340 break;
5341 }
5343 }
5344 ast_localtime(&t, tm, z ? z->timezone : NULL);
5345 return tm;
5346}

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_localtime(), ast_strlen_zero(), ast_tvnow(), vm_zone::name, NULL, vm_zone::timezone, and ast_vm_user::zonetag.

Referenced by make_email_file(), and sendpage().

◆ wait_file()

static int wait_file ( struct ast_channel chan,
struct vm_state vms,
char *  file 
)
static

Definition at line 9058 of file app_voicemail.c.

9059{
9060 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
9062}
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
Definition main/app.c:1466

References ast_control_streamfile(), ast_test_suite_event_notify, listen_control_forward_key, listen_control_pause_key, listen_control_restart_key, listen_control_reverse_key, listen_control_stop_key, NULL, and skipms.

Referenced by advanced_options(), play_message(), play_message_by_id_helper(), and vm_msg_play().

◆ wait_file2()

static int wait_file2 ( struct ast_channel chan,
struct vm_state vms,
char *  file 
)
static

Definition at line 9050 of file app_voicemail.c.

9051{
9052 int res;
9053 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
9054 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
9055 return res;
9056}

References AST_DIGIT_ANY, ast_log, AST_LOG_WARNING, and ast_stream_and_wait().

Referenced by play_message(), play_message_callerid(), and play_message_duration().

◆ write_password_to_file()

static int write_password_to_file ( const char *  secretfn,
const char *  password 
)
static

Definition at line 15529 of file app_voicemail.c.

15529 {
15530 struct ast_config *conf;
15531 struct ast_category *cat;
15532 struct ast_variable *var;
15533 int res = -1;
15534
15535 if (!(conf = ast_config_new())) {
15536 ast_log(LOG_ERROR, "Error creating new config structure\n");
15537 return res;
15538 }
15539 if (!(cat = ast_category_new("general", "", 1))) {
15540 ast_log(LOG_ERROR, "Error creating new category structure\n");
15542 return res;
15543 }
15544 if (!(var = ast_variable_new("password", password, ""))) {
15545 ast_log(LOG_ERROR, "Error creating new variable structure\n");
15548 return res;
15549 }
15552 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
15553 res = 0;
15554 } else {
15555 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
15556 }
15557
15559 return res;
15560}
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition extconf.c:3272
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition extconf.c:2831
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition extconf.c:2786
void ast_category_destroy(struct ast_category *cat)
Definition extconf.c:2843
All configuration options for http media cache.

References ast_category_append(), ast_category_destroy(), ast_category_new(), ast_config_destroy(), ast_config_new(), ast_config_text_file_save(), ast_log, ast_variable_append(), ast_variable_new, LOG_ERROR, and var.

Referenced by vm_change_password().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = tdesc , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .optional_modules = "res_adsi,res_smdi", }
static

Definition at line 17755 of file app_voicemail.c.

◆ addesc

char* addesc = "Comedian Mail"
static

Definition at line 1088 of file app_voicemail.c.

Referenced by adsi_load_vmail().

◆ adsifdn

unsigned char adsifdn[4] = "\x00\x00\x00\x0F"
static

Definition at line 1211 of file app_voicemail.c.

Referenced by actual_load_config(), adsi_begin(), and adsi_load_vmail().

◆ adsisec

unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC"
static

Definition at line 1212 of file app_voicemail.c.

Referenced by actual_load_config(), and adsi_load_vmail().

◆ adsiver

int adsiver = 1
static

Definition at line 1213 of file app_voicemail.c.

Referenced by actual_load_config(), adsi_begin(), and adsi_load_vmail().

◆ alias_mailbox_mappings

struct ao2_container* alias_mailbox_mappings
static

◆ aliasescontext

char aliasescontext[MAX_VM_CONTEXT_LEN]
static

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 17755 of file app_voicemail.c.

◆ callcontext

char callcontext[AST_MAX_CONTEXT] = ""
static

Definition at line 1197 of file app_voicemail.c.

Referenced by actual_load_config(), and populate_defaults().

◆ charset

char charset[32] = "ISO-8859-1"
static

Definition at line 1209 of file app_voicemail.c.

◆ cidinternalcontexts

char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]
static

Definition at line 1200 of file app_voicemail.c.

Referenced by actual_load_config(), and play_message_callerid().

◆ cli_voicemail

struct ast_cli_entry cli_voicemail[]
static

Definition at line 13983 of file app_voicemail.c.

13983 {
13984 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
13985 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
13986 AST_CLI_DEFINE(handle_voicemail_show_aliases, "List mailbox aliases"),
13987 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
13988 AST_CLI_DEFINE(handle_voicemail_show_mailbox, "Display a mailbox's content details"),
13989 AST_CLI_DEFINE(handle_voicemail_forward_message, "Forward message to another folder"),
13990 AST_CLI_DEFINE(handle_voicemail_move_message, "Move message to another folder"),
13992};
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_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_voicemail_forward_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_zones(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_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)
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ dialcontext

char dialcontext[AST_MAX_CONTEXT] = ""
static

◆ emailbody

char* emailbody
static

◆ emaildateformat

char emaildateformat[32] = "%A, %B %d, %Y at %r"
static

Definition at line 1214 of file app_voicemail.c.

Referenced by actual_load_config(), make_email_file(), and prep_email_sub_vars().

◆ emailsubject

char* emailsubject
static

Definition at line 1204 of file app_voicemail.c.

Referenced by actual_load_config(), and make_email_file().

◆ exitcontext

char exitcontext[AST_MAX_CONTEXT] = ""
static

◆ ext_pass_check_cmd

char ext_pass_check_cmd[128]
static

Definition at line 1070 of file app_voicemail.c.

Referenced by actual_load_config(), and check_password().

◆ ext_pass_cmd

char ext_pass_cmd[128]
static

◆ externnotify

char externnotify[160]
static

Definition at line 1112 of file app_voicemail.c.

Referenced by actual_load_config(), and run_externnotify().

◆ fromstring

char fromstring[100]
static

Definition at line 1207 of file app_voicemail.c.

Referenced by actual_load_config(), append_vmu_info_astman(), and make_email_file().

◆ globalflags

struct ast_flags globalflags = {0}
static

◆ inprocess_container

struct ao2_container* inprocess_container

Definition at line 1298 of file app_voicemail.c.

Referenced by inprocess_count(), load_module(), and unload_module().

◆ listen_control_forward_key

char listen_control_forward_key[12]
static

Definition at line 1163 of file app_voicemail.c.

Referenced by actual_load_config(), and wait_file().

◆ listen_control_pause_key

char listen_control_pause_key[12]
static

Definition at line 1165 of file app_voicemail.c.

Referenced by actual_load_config(), and wait_file().

◆ listen_control_restart_key

char listen_control_restart_key[12]
static

Definition at line 1166 of file app_voicemail.c.

Referenced by actual_load_config(), and wait_file().

◆ listen_control_reverse_key

char listen_control_reverse_key[12]
static

Definition at line 1164 of file app_voicemail.c.

Referenced by actual_load_config(), and wait_file().

◆ listen_control_stop_key

char listen_control_stop_key[12]
static

Definition at line 1167 of file app_voicemail.c.

Referenced by actual_load_config(), and wait_file().

◆ locale

char locale[20]
static

◆ mailbox_alias_mappings

struct ao2_container* mailbox_alias_mappings
static

◆ mailbox_folders

const char* const mailbox_folders[]
static

Definition at line 803 of file app_voicemail.c.

803 {
804#ifdef IMAP_STORAGE
805 imapfolder,
806#else
807 "INBOX",
808#endif
809 "Old",
810 "Work",
811 "Family",
812 "Friends",
813 "Cust1",
814 "Cust2",
815 "Cust3",
816 "Cust4",
817 "Cust5",
818 "Deleted",
819 "Urgent",
820};

Referenced by complete_voicemail_move_message(), get_folder_by_name(), mbox(), play_message_by_id(), vm_mailbox_snapshot_create(), and vm_msg_snapshot_create().

◆ mailcmd

char mailcmd[160] = SENDMAIL
static

Definition at line 1111 of file app_voicemail.c.

Referenced by actual_load_config(), append_vmu_info_astman(), sendmail(), and sendpage().

◆ maxdeletedmsg

int maxdeletedmsg
static

Definition at line 1108 of file app_voicemail.c.

Referenced by actual_load_config(), and populate_defaults().

◆ maxgreet

int maxgreet
static

◆ maxlogins

int maxlogins = 3
static

Definition at line 1120 of file app_voicemail.c.

Referenced by actual_load_config(), and vm_execmain().

◆ maxmsg

int maxmsg = MAXMSG
static

Definition at line 1107 of file app_voicemail.c.

Referenced by actual_load_config(), copy_message(), and populate_defaults().

◆ maxsilence

int maxsilence
static

◆ minpassword

int minpassword = MINPASSWORD
static

Definition at line 1121 of file app_voicemail.c.

Referenced by actual_load_config(), and check_password().

◆ msg_id_incrementor

int msg_id_incrementor
static

Definition at line 4021 of file app_voicemail.c.

Referenced by generate_msg_id().

◆ mwi_observer

struct ast_mwi_observer mwi_observer
Initial value:
= {
.on_subscribe = mwi_handle_subscribe,
.on_unsubscribe = mwi_handle_unsubscribe,
}
static void mwi_handle_unsubscribe(const char *id, struct ast_mwi_subscriber *sub)
static void mwi_handle_subscribe(const char *id, struct ast_mwi_subscriber *sub)

Definition at line 14137 of file app_voicemail.c.

14137 {
14138 .on_subscribe = mwi_handle_subscribe,
14139 .on_unsubscribe = mwi_handle_unsubscribe,
14140};

Referenced by start_poll_thread(), and stop_poll_thread().

◆ mwi_subscription_tps

struct ast_taskprocessor* mwi_subscription_tps
static

◆ my_umask

int my_umask
static

◆ pagerbody

char* pagerbody
static

Definition at line 1205 of file app_voicemail.c.

Referenced by actual_load_config(), and sendpage().

◆ pagerdateformat

char pagerdateformat[32] = "%A, %B %d, %Y at %r"
static

Definition at line 1215 of file app_voicemail.c.

Referenced by actual_load_config(), and sendpage().

◆ pagerfromstring

char pagerfromstring[100]
static

Definition at line 1208 of file app_voicemail.c.

Referenced by actual_load_config(), and sendpage().

◆ pagersubject

char* pagersubject
static

Definition at line 1206 of file app_voicemail.c.

Referenced by actual_load_config(), and sendpage().

◆ passwordlocation

int passwordlocation
static

Definition at line 1122 of file app_voicemail.c.

Referenced by actual_load_config(), and populate_defaults().

◆ playmsg_app

char* playmsg_app = "VoiceMailPlayMsg"
static

Definition at line 1098 of file app_voicemail.c.

Referenced by load_module(), and unload_module().

◆ poll_cond

ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER
static

Definition at line 1135 of file app_voicemail.c.

Referenced by mb_poll_thread(), and stop_poll_thread().

◆ poll_freq

unsigned int poll_freq = DEFAULT_POLL_FREQ
static

Polling frequency

Definition at line 1132 of file app_voicemail.c.

Referenced by actual_load_config(), and mb_poll_thread().

◆ poll_lock

ast_mutex_t poll_lock = AST_MUTEX_INIT_VALUE
static

Definition at line 1134 of file app_voicemail.c.

Referenced by mb_poll_thread(), and stop_poll_thread().

◆ poll_mailboxes

unsigned int poll_mailboxes
static

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

Definition at line 1127 of file app_voicemail.c.

Referenced by actual_load_config().

◆ poll_thread

pthread_t poll_thread = AST_PTHREADT_NULL
static

◆ poll_thread_run

unsigned char poll_thread_run
static

Definition at line 1137 of file app_voicemail.c.

Referenced by mb_poll_thread(), start_poll_thread(), and stop_poll_thread().

◆ pwdchange

int pwdchange = PWDCHANGE_INTERNAL
static

Definition at line 1076 of file app_voicemail.c.

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

◆ saydurationminfo

int saydurationminfo = 2
static

Definition at line 1194 of file app_voicemail.c.

Referenced by actual_load_config(), and populate_defaults().

◆ sayname_app

char* sayname_app = "VMSayName"
static

Definition at line 1100 of file app_voicemail.c.

Referenced by load_module(), and unload_module().

◆ serveremail

char serveremail[80] = ASTERISK_USERNAME
static

◆ silencethreshold

int silencethreshold = 128
static

◆ skipms

int skipms = 3000
static

◆ smdi_iface

struct ast_smdi_interface* smdi_iface = NULL
static

Definition at line 1113 of file app_voicemail.c.

Referenced by actual_load_config(), and run_externnotify().

◆ users

◆ vm_app_options

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

Definition at line 801 of file app_voicemail.c.

Referenced by vm_exec(), and vm_execmain().

◆ vm_greeter_table

const struct ast_vm_greeter_functions vm_greeter_table
static

Definition at line 16159 of file app_voicemail.c.

16159 {
16160 .module_version = VM_GREETER_MODULE_VERSION,
16161 .module_name = AST_MODULE,
16162
16163 .sayname = vm_sayname,
16164};
#define AST_MODULE
static int vm_sayname(struct ast_channel *chan, const char *mailbox_id)
#define VM_GREETER_MODULE_VERSION

Referenced by load_module(), and unload_module().

◆ vm_info_acf

struct ast_custom_function vm_info_acf
static
Initial value:
= {
.name = "VM_INFO",
.read = acf_vm_info,
}
static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)

Definition at line 13695 of file app_voicemail.c.

13695 {
13696 .name = "VM_INFO",
13697 .read = acf_vm_info,
13698};

Referenced by load_module(), and unload_module().

◆ vm_invalid_password

char vm_invalid_password[80] = "vm-invalid-password"
static

Definition at line 1177 of file app_voicemail.c.

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

◆ vm_login

char vm_login[80] = "vm-login"
static

Definition at line 1170 of file app_voicemail.c.

Referenced by actual_load_config(), and vm_authenticate().

◆ vm_mismatch

char vm_mismatch[80] = "vm-mismatch"
static

Definition at line 1176 of file app_voicemail.c.

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

◆ vm_newpassword

char vm_newpassword[80] = "vm-newpassword"
static

Definition at line 1173 of file app_voicemail.c.

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

◆ vm_newuser

char vm_newuser[80] = "vm-newuser"
static

Definition at line 1171 of file app_voicemail.c.

Referenced by actual_load_config(), and vm_execmain().

◆ vm_passchanged

char vm_passchanged[80] = "vm-passchanged"
static

Definition at line 1174 of file app_voicemail.c.

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

◆ vm_password

char vm_password[80] = "vm-password"
static

Definition at line 1172 of file app_voicemail.c.

Referenced by actual_load_config(), and vm_authenticate().

◆ vm_pls_try_again

char vm_pls_try_again[80] = "vm-pls-try-again"
static

◆ vm_prepend_timeout

char vm_prepend_timeout[80] = "vm-then-pound"
static

Definition at line 1190 of file app_voicemail.c.

Referenced by actual_load_config(), and vm_forwardoptions().

◆ vm_reenterpassword

char vm_reenterpassword[80] = "vm-reenterpassword"
static

Definition at line 1175 of file app_voicemail.c.

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

◆ VM_SPOOL_DIR

char VM_SPOOL_DIR[PATH_MAX]
static

◆ vm_table

const struct ast_vm_functions vm_table
static

Definition at line 16141 of file app_voicemail.c.

16141 {
16142 .module_version = VM_MODULE_VERSION,
16143 .module_name = AST_MODULE,
16144
16145 .has_voicemail = has_voicemail,
16146 .inboxcount = inboxcount,
16147 .inboxcount2 = inboxcount2,
16148 .messagecount = messagecount,
16149 .copy_recording_to_vm = msg_create_from_file,
16150 .index_to_foldername = vm_index_to_foldername,
16151 .mailbox_snapshot_create = vm_mailbox_snapshot_create,
16152 .mailbox_snapshot_destroy = vm_mailbox_snapshot_destroy,
16153 .msg_move = vm_msg_move,
16154 .msg_remove = vm_msg_remove,
16155 .msg_forward = vm_msg_forward,
16156 .msg_play = vm_msg_play,
16157};
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 const char * vm_index_to_foldername(int id)
static int msg_create_from_file(struct ast_vm_recording_data *recdata)
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
static int has_voicemail(const char *mailbox, const char *folder)
Determines if the given folder has messages.
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
#define VM_MODULE_VERSION

Referenced by __ast_vm_greeter_register(), __ast_vm_register(), load_module(), and unload_module().

◆ vmauthenticate_app

char* vmauthenticate_app = "VMAuthenticate"
static

Definition at line 1096 of file app_voicemail.c.

Referenced by load_module(), and unload_module().

◆ vmfmts

char vmfmts[80] = "wav"
static

◆ vmmaxsecs

int vmmaxsecs
static

Definition at line 1117 of file app_voicemail.c.

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

◆ vmminsecs

int vmminsecs
static

Definition at line 1116 of file app_voicemail.c.

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

◆ voicemail_app

char* voicemail_app = "VoiceMail"
static

Definition at line 1091 of file app_voicemail.c.

Referenced by load_module(), and unload_module().

◆ voicemailmain_app

char* voicemailmain_app = "VoiceMailMain"
static

Definition at line 1094 of file app_voicemail.c.

Referenced by load_module(), and unload_module().

◆ volgain

double volgain
static

Definition at line 1115 of file app_voicemail.c.

Referenced by actual_load_config(), and populate_defaults().

◆ zones

◆ zonetag

char zonetag[80]
static

Definition at line 1104 of file app_voicemail.c.

Referenced by actual_load_config(), build_peer(), and populate_defaults().