Asterisk - The Open Source Telephony Project GIT-master-43bf8a4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Enumerations | Functions | Variables
app_voicemail_odbc.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_odbc.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. More...
 
#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 , NEW_FOLDER = 0 , OLD_FOLDER = 1 ,
  WORK_FOLDER = 2 , FAMILY_FOLDER = 3 , FRIENDS_FOLDER = 4 , GREETINGS_FOLDER = -1 ,
  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 , OPT_ARG_RECORDGAIN = 0 , OPT_ARG_PLAYFOLDER = 1 , OPT_ARG_DTMFEXIT = 2 ,
  OPT_ARG_BEEP_TONE = 3 , OPT_ARG_ARRAY_SIZE = 4 , 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) , 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) , OPT_SILENT = (1 << 0) , OPT_BUSY_GREETING = (1 << 1) ,
  OPT_UNAVAIL_GREETING = (1 << 2) , OPT_RECORDGAIN = (1 << 3) , OPT_PREPEND_MAILBOX = (1 << 4) , OPT_AUTOPLAY = (1 << 6) ,
  OPT_DTMFEXIT = (1 << 7) , OPT_MESSAGE_Urgent = (1 << 8) , OPT_MESSAGE_PRIORITY = (1 << 9) , OPT_EARLYM_GREETING = (1 << 10) ,
  OPT_BEEP = (1 << 11) , OPT_SILENT_IF_GREET = (1 << 12) , OPT_READONLY = (1 << 13)
}
 
enum  vm_passwordlocation {
  OPT_PWLOC_VOICEMAILCONF = 0 , OPT_PWLOC_SPOOLDIR = 1 , OPT_PWLOC_VOICEMAILCONF = 0 , OPT_PWLOC_SPOOLDIR = 1 ,
  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. More...
 
static struct alias_mailbox_mappingalias_mailbox_mapping_create (const char *alias, const char *mailbox)
 
 AO2_STRING_FIELD_CMP_FN (alias_mailbox_mapping, alias)
 
 AO2_STRING_FIELD_CMP_FN (mailbox_alias_mapping, mailbox)
 
 AO2_STRING_FIELD_HASH_FN (alias_mailbox_mapping, alias)
 
 AO2_STRING_FIELD_HASH_FN (mailbox_alias_mapping, mailbox)
 
static int append_mailbox (const char *context, const char *box, const char *data)
 
static int append_vmbox_info_astman (struct mansession *s, const struct message *m, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
 Append vmbox info string into given astman with event_name. More...
 
static int append_vmu_info_astman (struct mansession *s, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
 Append vmu info string into given astman with event_name. More...
 
static void apply_option (struct ast_vm_user *vmu, const char *var, const char *value)
 Sets a specific property value. More...
 
static void apply_options (struct ast_vm_user *vmu, const char *options)
 Destructively Parse options and apply. More...
 
static void apply_options_full (struct ast_vm_user *retval, struct ast_variable *var)
 Loads the options specific to a voicemail user. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static const char * ast_str_encode_mime (struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
 Encode a string according to the MIME rules for encoding strings that are not 7-bit clean or contain control characters. More...
 
static const char * ast_str_quote (struct ast_str **buf, ssize_t maxlen, const char *from)
 Wraps a character sequence in double quotes, escaping occurrences of quotes within the string. More...
 
static int change_password_realtime (struct ast_vm_user *vmu, const char *password)
 Performs a change of the voicemail password in the realtime engine. More...
 
static int check_mime (const char *str)
 Check if the string would need encoding within the MIME standard, to avoid confusing certain mail software that expects messages to be 7-bit clean. More...
 
static int check_password (struct ast_vm_user *vmu, char *password)
 Check that password meets minimum required length. More...
 
static int close_mailbox (struct vm_state *vms, struct ast_vm_user *vmu)
 
static char * complete_voicemail_move_message (struct ast_cli_args *a, int maxpos)
 
static char * complete_voicemail_show_mailbox (struct ast_cli_args *a)
 
static char * complete_voicemail_show_users (const char *line, const char *word, int pos, int state)
 
static int copy (char *infile, char *outfile)
 Utility function to copy a file. More...
 
static int copy_message (struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag, const char *dest_folder)
 Copies a message from one mailbox to another. More...
 
static void copy_plain_file (char *frompath, char *topath)
 Copies a voicemail information (envelope) file. More...
 
static int count_messages (struct ast_vm_user *vmu, char *dir)
 Find all .txt files - even if they are not in sequence from 0000. More...
 
static int create_dirpath (char *dest, int len, const char *context, const char *ext, const char *folder)
 basically mkdir -p $dest/$context/$ext/$folder More...
 
static int dialout (struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
 
static struct ast_vm_userfind_or_create (const char *context, const char *box)
 
static struct ast_vm_userfind_user (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the users file or the realtime engine. More...
 
static struct ast_vm_userfind_user_realtime (struct ast_vm_user *ivm, const char *context, const char *mailbox)
 Finds a voicemail user from the realtime engine. More...
 
static int forward_message (struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
 Sends a voicemail message to a mailbox recipient. More...
 
static int forward_message_from_mailbox (struct ast_cli_args *a)
 
static void free_user (struct ast_vm_user *vmu)
 
static void free_user_final (struct ast_vm_user *vmu)
 
static void free_vm_users (void)
 Free the users structure. More...
 
static void free_vm_zones (void)
 Free the zones structure. More...
 
static void free_zone (struct vm_zone *z)
 
static void generate_msg_id (char *dst)
 Sets the destination string to a uniquely identifying msg_id string. More...
 
static int get_date (char *s, int len)
 Gets the current date and time, as formatted string. More...
 
static int get_folder (struct ast_channel *chan, int start)
 get_folder: Folder menu Plays "press 1 for INBOX messages" etc. Should possibly be internationalized More...
 
static int get_folder2 (struct ast_channel *chan, char *fn, int start)
 plays a prompt and waits for a keypress. More...
 
static int get_folder_by_name (const char *name)
 
static int get_folder_ja (struct ast_channel *chan, int start)
 
static char * handle_voicemail_forward_message (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_voicemail_move_message (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_voicemail_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Reload voicemail configuration from the CLI. More...
 
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. More...
 
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. More...
 
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. More...
 
static int has_voicemail (const char *mailbox, const char *folder)
 Determines if the given folder has messages. More...
 
static int inboxcount (const char *mailbox, int *newmsgs, int *oldmsgs)
 
static int inboxcount2 (const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
 Check the given mailbox's message count. More...
 
static int inprocess_cmp_fn (void *obj, void *arg, int flags)
 
static int inprocess_count (const char *context, const char *mailbox, int delta)
 
static int inprocess_hash_fn (const void *obj, const int flags)
 
static int invent_message (struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
 
static int is_valid_dtmf (const char *key)
 Determines if a DTMF key entered is valid. More...
 
static int last_message_index (char *dir)
 Determines the highest message number in use for a given user and mailbox folder. More...
 
static int leave_voicemail (struct ast_channel *chan, char *ext, struct leave_vm_options *options)
 Prompts the user and records a voicemail to a mailbox. More...
 
static void load_aliases (struct ast_config *cfg)
 
static int load_config (int reload)
 
static int load_config_force (int reload, int force)
 Reload voicemail.conf. More...
 
static int load_module (void)
 Load the module. More...
 
static void load_users (struct ast_config *cfg)
 
static void load_zonemessages (struct ast_config *cfg)
 
static int make_dir (char *dest, int len, const char *context, const char *ext, const char *folder)
 Creates a file system path expression for a folder within the voicemail data folder and the appropriate context. More...
 
static void make_email_file (FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag, const char *msg_id)
 Creates the email file to be sent to indicate a new voicemail exists for a user. More...
 
static int make_file (char *dest, const int len, const char *dir, const int num)
 Creates a file system path expression for a folder within the voicemail data folder and the appropriate context. More...
 
static int manager_get_mailbox_summary (struct mansession *s, const struct message *m)
 
static int manager_list_voicemail_users (struct mansession *s, const struct message *m)
 Manager list voicemail users command. More...
 
static int manager_match_mailbox (struct ast_mwi_state *mwi_state, void *data)
 
static int manager_status_voicemail_user (struct mansession *s, const struct message *m)
 
static int manager_voicemail_forward (struct mansession *s, const struct message *m)
 
static int manager_voicemail_move (struct mansession *s, const struct message *m)
 
static int manager_voicemail_refresh (struct mansession *s, const struct message *m)
 
static int manager_voicemail_remove (struct mansession *s, const struct message *m)
 
static void * mb_poll_thread (void *data)
 
static const char * mbox (struct ast_vm_user *vmu, int id)
 
static int message_range_and_existence_check (struct vm_state *vms, const char *msg_ids[], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu)
 common bounds checking and existence check for Voicemail API functions. More...
 
static int messagecount (const char *mailbox_id, const char *folder)
 
static int move_message_from_mailbox (struct ast_cli_args *a)
 
static int msg_create_from_file (struct ast_vm_recording_data *recdata)
 
static void mwi_handle_subscribe (const char *id, struct ast_mwi_subscriber *sub)
 
static int mwi_handle_subscribe2 (void *data)
 
static void mwi_handle_unsubscribe (const char *id, struct ast_mwi_subscriber *sub)
 
static int mwi_handle_unsubscribe2 (void *data)
 
static int notify_new_message (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
 Sends email notification that a user has a new voicemail waiting for them. More...
 
static void notify_new_state (struct ast_vm_user *vmu)
 
static int open_mailbox (struct vm_state *vms, struct ast_vm_user *vmu, int box)
 
static int play_message (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
 
static int play_message_by_id (struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
 Finds a message in a specific mailbox by msg_id and plays it to the channel. More...
 
static int play_message_by_id_helper (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, const char *msg_id)
 
static int play_message_callerid (struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
 
static int play_message_category (struct ast_channel *chan, const char *category)
 
static int play_message_datetime (struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
 
static int play_message_duration (struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
 
static int play_record_review (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir, signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id, int forwardintro)
 
static int poll_subscribed_mailbox (struct ast_mwi_state *mwi_state, void *data)
 
static void populate_defaults (struct ast_vm_user *vmu)
 Sets default voicemail system options to a voicemail user. More...
 
static void prep_email_sub_vars (struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
 
static void print_mappings (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void queue_mwi_event (const char *channel_id, const char *box, int urgent, int new, int old)
 
static void read_password_from_file (const char *secretfn, char *password, int passwordlen)
 
static int reload (void)
 
static int remove_message_from_mailbox (struct ast_cli_args *a)
 
static void rename_file (char *sfn, char *dfn)
 Renames a message in a mailbox folder. More...
 
static int resequence_mailbox (struct ast_vm_user *vmu, char *dir, int stopcount)
 
static int reset_user_pw (const char *context, const char *mailbox, const char *newpass)
 Resets a user password to a specified password. More...
 
static void run_externnotify (const char *context, const char *extension, const char *flag)
 
static int save_to_folder (struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
 
static int say_and_wait (struct ast_channel *chan, int num, const char *language)
 
static int sayname (struct ast_channel *chan, const char *mailbox, const char *context)
 
static int sendmail (char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag, const char *msg_id)
 
static int sendpage (char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
 
static int separate_mailbox (char *mailbox_id, char **mailbox, char **context)
 
static int show_mailbox_details (struct ast_cli_args *a)
 
static int show_mailbox_snapshot (struct ast_cli_args *a)
 
static int show_messages_for_mailbox (struct ast_cli_args *a)
 
static char * show_users_realtime (int fd, const char *context)
 
static void start_poll_thread (void)
 
static void stop_poll_thread (void)
 
static char * strip_control_and_high (const char *input, char *buf, size_t buflen)
 Strips control and non 7-bit clean characters from input string. More...
 
static const char * substitute_escapes (const char *value)
 
static int unload_module (void)
 
static int valid_config (const struct ast_config *cfg)
 Check if configuration file is valid. More...
 
static int vm_allocate_dh (struct vm_state *vms, struct ast_vm_user *vmu, int count_msg)
 
static int vm_authenticate (struct ast_channel *chan, char *mailbox, int mailbox_size, struct ast_vm_user *res_vmu, const char *context, const char *prefix, int skipuser, int max_logins, int silent)
 
static int vm_browse_messages (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Top level method to invoke the language variant vm_browse_messages_XX function. More...
 
static int vm_browse_messages_en (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Default English syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_es (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Spanish syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_gr (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Greek syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_he (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 
static int vm_browse_messages_it (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Italian syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_ja (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Japanese syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_pt (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Portuguese syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_vi (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Vietnamese syntax for 'You have N messages' greeting. More...
 
static int vm_browse_messages_zh (struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 Chinese (Taiwan)syntax for 'You have N messages' greeting. More...
 
static void vm_change_password (struct ast_vm_user *vmu, const char *newpassword)
 The handler for the change password option. More...
 
static void vm_change_password_shell (struct ast_vm_user *vmu, char *newpassword)
 
static char * vm_check_password_shell (char *command, char *buf, size_t len)
 
static int vm_delete (char *file)
 Removes the voicemail sound and information file. More...
 
static int vm_exec (struct ast_channel *chan, const char *data)
 
static int vm_execmain (struct ast_channel *chan, const char *data)
 
static int vm_forwardoptions (struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts, char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
 presents the option to prepend to an existing message when forwarding it. More...
 
static const char * vm_index_to_foldername (int id)
 
static int vm_instructions (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_instructions_en (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_instructions_ja (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_instructions_zh (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
 
static int vm_intro (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
 
static int vm_intro_cs (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_da (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_de (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_en (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_es (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_fr (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_gr (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_he (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_is (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_it (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_ja (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_multilang (struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
 
static int vm_intro_nl (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_no (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_pl (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_pt (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_pt_BR (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_se (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_vi (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_intro_zh (struct ast_channel *chan, struct vm_state *vms)
 
static int vm_lock_path (const char *path)
 Lock file path only return failure if ast_lock_path returns 'timeout', not if the path does not exist or any other reason. More...
 
static struct ast_vm_mailbox_snapshotvm_mailbox_snapshot_create (const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
 
static struct ast_vm_mailbox_snapshotvm_mailbox_snapshot_destroy (struct ast_vm_mailbox_snapshot *mailbox_snapshot)
 
static int vm_msg_forward (const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old)
 
static int vm_msg_move (const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder)
 
static int vm_msg_play (struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb)
 
static int vm_msg_remove (const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[])
 
static struct ast_vm_msg_snapshotvm_msg_snapshot_alloc (void)
 
static int vm_msg_snapshot_create (struct ast_vm_user *vmu, struct vm_state *vms, struct ast_vm_mailbox_snapshot *mailbox_snapshot, int snapshot_index, int mailbox_index, int descending, enum ast_vm_snapshot_sort_val sort_val)
 Create and store off all the msgs in an open mailbox. More...
 
static struct ast_vm_msg_snapshotvm_msg_snapshot_destroy (struct ast_vm_msg_snapshot *msg_snapshot)
 
static int vm_newuser_setup (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 
static int vm_options (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 
static int vm_play_folder_name (struct ast_channel *chan, char *mbox)
 
static int vm_play_folder_name_gr (struct ast_channel *chan, char *box)
 
static int vm_play_folder_name_ja (struct ast_channel *chan, char *box)
 
static int vm_play_folder_name_pl (struct ast_channel *chan, char *box)
 
static int vm_play_folder_name_ua (struct ast_channel *chan, char *box)
 
static int vm_playmsgexec (struct ast_channel *chan, const char *data)
 
static int vm_sayname (struct ast_channel *chan, const char *mailbox_id)
 
static int vm_tempgreeting (struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 The handler for 'record a temporary greeting'. More...
 
static int vmauthenticate (struct ast_channel *chan, const char *data)
 
static int vmsayname_exec (struct ast_channel *chan, const char *data)
 
static const struct ast_tmvmu_tm (const struct ast_vm_user *vmu, struct ast_tm *tm)
 fill in *tm for current time according to the proper timezone, if any. More...
 
static int wait_file (struct ast_channel *chan, struct vm_state *vms, char *file)
 
static int wait_file2 (struct ast_channel *chan, struct vm_state *vms, char *file)
 
static int write_password_to_file (const char *secretfn, const char *password)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Comedian Mail (Voicemail System)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = 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 = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static unsigned int poll_mailboxes
 
static pthread_t poll_thread = AST_PTHREADT_NULL
 
static unsigned char poll_thread_run
 
static int pwdchange = PWDCHANGE_INTERNAL
 
static int saydurationminfo = 2
 
static char * sayname_app = "VMSayName"
 
static char serveremail [80] = ASTERISK_USERNAME
 
static int silencethreshold = 128
 
static int skipms = 3000
 
static struct ast_smdi_interfacesmdi_iface = NULL
 
static struct users users = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static const struct ast_app_option vm_app_options [128] = { [ 's' ] = { .flag = OPT_SILENT }, [ 'S' ] = { .flag = OPT_SILENT_IF_GREET }, [ 'b' ] = { .flag = OPT_BUSY_GREETING }, [ 'u' ] = { .flag = OPT_UNAVAIL_GREETING }, [ 'g' ] = { .flag = OPT_RECORDGAIN , .arg_index = OPT_ARG_RECORDGAIN + 1 }, [ 'd' ] = { .flag = OPT_DTMFEXIT , .arg_index = OPT_ARG_DTMFEXIT + 1 }, [ 'p' ] = { .flag = OPT_PREPEND_MAILBOX }, [ 'a' ] = { .flag = OPT_AUTOPLAY , .arg_index = OPT_ARG_PLAYFOLDER + 1 }, [ 'U' ] = { .flag = OPT_MESSAGE_Urgent }, [ 'P' ] = { .flag = OPT_MESSAGE_PRIORITY }, [ 'e' ] = { .flag = OPT_EARLYM_GREETING }, [ 't' ] = { .flag = OPT_BEEP , .arg_index = OPT_ARG_BEEP_TONE + 1 }, [ 'r' ] = { .flag = OPT_READONLY }, }
 
static const struct ast_vm_greeter_functions vm_greeter_table
 
static struct ast_custom_function vm_info_acf
 
static char vm_invalid_password [80] = "vm-invalid-password"
 
static char vm_login [80] = "vm-login"
 
static char vm_mismatch [80] = "vm-mismatch"
 
static char vm_newpassword [80] = "vm-newpassword"
 
static char vm_newuser [80] = "vm-newuser"
 
static char vm_passchanged [80] = "vm-passchanged"
 
static char vm_password [80] = "vm-password"
 
static char vm_pls_try_again [80] = "vm-pls-try-again"
 
static char vm_prepend_timeout [80] = "vm-then-pound"
 
static char vm_reenterpassword [80] = "vm-reenterpassword"
 
static char VM_SPOOL_DIR [PATH_MAX]
 
static const struct ast_vm_functions vm_table
 
static char * vmauthenticate_app = "VMAuthenticate"
 
static char vmfmts [80] = "wav"
 
static int vmmaxsecs
 
static int vmminsecs
 
static char * voicemail_app = "VoiceMail"
 
static char * voicemailmain_app = "VoiceMailMain"
 
static double volgain
 
static struct zones zones = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static char zonetag [80]
 

Detailed Description

Comedian Mail - Voicemail System.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

unixODBC (http://www.unixodbc.org/) A source distribution of University of Washington's IMAP c-client (http://www.washington.edu/imap/)

See also
Note
For information about voicemail IMAP storage, https://docs.asterisk.org/Configuration/Applications/Voicemail/IMAP-Voicemail-Storage/
Todo:
This module requires res_adsi to load. This needs to be optional during compilation.
Todo:
This file is now almost impossible to work with, due to all #ifdefs. Feels like the database code before realtime. Someone - please come up with a plan to clean this up.

Definition in file app_voicemail_odbc.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_odbc.c.

◆ CHUNKSIZE

#define CHUNKSIZE   65536

Definition at line 683 of file app_voicemail_odbc.c.

◆ COMMAND_TIMEOUT

#define COMMAND_TIMEOUT   5000

Definition at line 679 of file app_voicemail_odbc.c.

◆ COPY

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

Definition at line 1061 of file app_voicemail_odbc.c.

◆ COUNT

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

Definition at line 1054 of file app_voicemail_odbc.c.

◆ DEFAULT_LISTEN_CONTROL_FORWARD_KEY

#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY   "#"

Definition at line 691 of file app_voicemail_odbc.c.

◆ DEFAULT_LISTEN_CONTROL_PAUSE_KEY

#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY   "0"

Definition at line 693 of file app_voicemail_odbc.c.

◆ DEFAULT_LISTEN_CONTROL_RESTART_KEY

#define DEFAULT_LISTEN_CONTROL_RESTART_KEY   "2"

Definition at line 694 of file app_voicemail_odbc.c.

◆ DEFAULT_LISTEN_CONTROL_REVERSE_KEY

#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY   "*"

Definition at line 692 of file app_voicemail_odbc.c.

◆ DEFAULT_LISTEN_CONTROL_STOP_KEY

#define DEFAULT_LISTEN_CONTROL_STOP_KEY   "13456789"

Definition at line 695 of file app_voicemail_odbc.c.

◆ DEFAULT_POLL_FREQ

#define DEFAULT_POLL_FREQ   30

By default, poll every 30 seconds

Definition at line 1130 of file app_voicemail_odbc.c.

◆ DELETE

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

Definition at line 1062 of file app_voicemail_odbc.c.

◆ DISPOSE

#define DISPOSE (   a,
  b 
)

Definition at line 1057 of file app_voicemail_odbc.c.

◆ ENDL

#define ENDL   "\n"

Definition at line 713 of file app_voicemail_odbc.c.

◆ ERROR_LOCK_PATH

#define ERROR_LOCK_PATH   -100

Definition at line 742 of file app_voicemail_odbc.c.

◆ ERROR_MAX_MSGS

#define ERROR_MAX_MSGS   -101

Definition at line 743 of file app_voicemail_odbc.c.

◆ EXISTS

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

Definition at line 1059 of file app_voicemail_odbc.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_odbc.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_odbc.c.

◆ LAST_MSG_INDEX

#define LAST_MSG_INDEX (   a)    last_message_index(a)

Definition at line 1055 of file app_voicemail_odbc.c.

◆ MAPPING_BUCKETS

#define MAPPING_BUCKETS   511

Definition at line 1153 of file app_voicemail_odbc.c.

◆ MAX_DATETIME_FORMAT

#define MAX_DATETIME_FORMAT   512

Definition at line 716 of file app_voicemail_odbc.c.

◆ MAX_MAIL_BODY_CONTENT_SIZE

#define MAX_MAIL_BODY_CONTENT_SIZE   134217728L

Definition at line 703 of file app_voicemail_odbc.c.

◆ MAX_NUM_CID_CONTEXTS

#define MAX_NUM_CID_CONTEXTS   10

Definition at line 717 of file app_voicemail_odbc.c.

◆ MAX_VM_CONTEXT_LEN

#define MAX_VM_CONTEXT_LEN   (AST_MAX_CONTEXT)

Definition at line 933 of file app_voicemail_odbc.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_odbc.c.

◆ MAX_VM_MBOX_ID_LEN

#define MAX_VM_MBOX_ID_LEN   (AST_MAX_EXTENSION)

Definition at line 932 of file app_voicemail_odbc.c.

◆ MAXMSG

#define MAXMSG   100

Definition at line 705 of file app_voicemail_odbc.c.

◆ MAXMSGLIMIT

#define MAXMSGLIMIT   9999

Definition at line 706 of file app_voicemail_odbc.c.

◆ MINPASSWORD

#define MINPASSWORD   0

Default minimum mailbox password length

Definition at line 708 of file app_voicemail_odbc.c.

◆ MSG_ID_LEN

#define MSG_ID_LEN   256

Definition at line 4018 of file app_voicemail_odbc.c.

◆ MSGFILE_LEN

#define MSGFILE_LEN   (7)

Length of the message file name: msgXXXX

Definition at line 746 of file app_voicemail_odbc.c.

◆ OPERATOR_EXIT

#define OPERATOR_EXIT   300

Definition at line 744 of file app_voicemail_odbc.c.

◆ PWDCHANGE_EXTERNAL

#define PWDCHANGE_EXTERNAL   (1 << 2)

Definition at line 1075 of file app_voicemail_odbc.c.

◆ PWDCHANGE_INTERNAL

#define PWDCHANGE_INTERNAL   (1 << 1)

Definition at line 1074 of file app_voicemail_odbc.c.

◆ RENAME

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

Definition at line 1060 of file app_voicemail_odbc.c.

◆ RETRIEVE

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

Definition at line 1056 of file app_voicemail_odbc.c.

◆ SENDMAIL

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

Definition at line 700 of file app_voicemail_odbc.c.

◆ SMDI_MWI_WAIT_TIMEOUT

#define SMDI_MWI_WAIT_TIMEOUT   1000 /* 1 second */

Definition at line 677 of file app_voicemail_odbc.c.

◆ STORE

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

Definition at line 1058 of file app_voicemail_odbc.c.

◆ tdesc

#define tdesc   "Comedian Mail (Voicemail System)"

Definition at line 1084 of file app_voicemail_odbc.c.

◆ UPDATE_MSG_ID

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

Definition at line 1063 of file app_voicemail_odbc.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_odbc.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_odbc.c.

◆ VM_ATTACH

#define VM_ATTACH   (1 << 11)

Attach message to voicemail notifications?

Definition at line 730 of file app_voicemail_odbc.c.

◆ VM_DELETE

#define VM_DELETE   (1 << 12)

Delete message after sending notification

Definition at line 731 of file app_voicemail_odbc.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_odbc.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_odbc.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_odbc.c.

◆ VM_FORCEGREET

#define VM_FORCEGREET   (1 << 8)

Have new users record their greetings

Definition at line 727 of file app_voicemail_odbc.c.

◆ VM_FORCENAME

#define VM_FORCENAME   (1 << 7)

Have new users record their name

Definition at line 726 of file app_voicemail_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.c.

◆ VM_SAYCID

#define VM_SAYCID   (1 << 2)

Repeat the CallerID info during envelope playback

Definition at line 721 of file app_voicemail_odbc.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_odbc.c.

◆ VM_SEARCH

#define VM_SEARCH   (1 << 14)

Search all contexts for a matching mailbox

Definition at line 733 of file app_voicemail_odbc.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_odbc.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_odbc.c.

◆ VM_TEMPGREETWARN

#define VM_TEMPGREETWARN   (1 << 15)

Remind user tempgreeting is set

Definition at line 734 of file app_voicemail_odbc.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_odbc.c.

◆ VOICEMAIL_CONFIG

#define VOICEMAIL_CONFIG   "voicemail.conf"

Definition at line 685 of file app_voicemail_odbc.c.

◆ VOICEMAIL_DIR_MODE

#define VOICEMAIL_DIR_MODE   0777

Definition at line 681 of file app_voicemail_odbc.c.

◆ VOICEMAIL_FILE_MODE

#define VOICEMAIL_FILE_MODE   0666

Definition at line 682 of file app_voicemail_odbc.c.

Enumeration Type Documentation

◆ vm_box

enum vm_box
Enumerator
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 
NEW_FOLDER 
OLD_FOLDER 
WORK_FOLDER 
FAMILY_FOLDER 
FRIENDS_FOLDER 
GREETINGS_FOLDER 

Definition at line 748 of file app_voicemail_odbc.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 
OPT_ARG_RECORDGAIN 
OPT_ARG_PLAYFOLDER 
OPT_ARG_DTMFEXIT 
OPT_ARG_BEEP_TONE 
OPT_ARG_ARRAY_SIZE 
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_odbc.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 
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 
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_odbc.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 
OPT_PWLOC_VOICEMAILCONF 
OPT_PWLOC_SPOOLDIR 
OPT_PWLOC_VOICEMAILCONF 
OPT_PWLOC_SPOOLDIR 

Definition at line 782 of file app_voicemail_odbc.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_odbc.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";
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, voicemailpwcheck::context, alias_mailbox_mapping::mailbox, voicemailpwcheck::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 17737 of file app_voicemail_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 17737 of file app_voicemail_odbc.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 13596 of file app_voicemail_odbc.c.

13597{
13598 struct ast_vm_user svm;
13599 struct ast_vm_user *vmu = NULL;
13600 char *parse;
13601 char *mailbox;
13602 char *context;
13603 int res = 0;
13604
13606 AST_APP_ARG(mailbox_context);
13607 AST_APP_ARG(attribute);
13608 AST_APP_ARG(folder);
13609 );
13610
13611 buf[0] = '\0';
13612
13613 if (ast_strlen_zero(args)) {
13614 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13615 return -1;
13616 }
13617
13618 parse = ast_strdupa(args);
13619 AST_STANDARD_APP_ARGS(arg, parse);
13620
13621 if (ast_strlen_zero(arg.mailbox_context)
13622 || ast_strlen_zero(arg.attribute)
13623 || separate_mailbox(ast_strdupa(arg.mailbox_context), &mailbox, &context)) {
13624 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13625 return -1;
13626 }
13627
13628 memset(&svm, 0, sizeof(svm));
13629 vmu = find_user(&svm, context, mailbox);
13630
13631 if (!strncasecmp(arg.attribute, "exists", 5)) {
13632 ast_copy_string(buf, vmu ? "1" : "0", len);
13633 free_user(vmu);
13634 return 0;
13635 }
13636
13637 if (vmu) {
13638 if (!strncasecmp(arg.attribute, "password", 8)) {
13640 } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
13642 } else if (!strncasecmp(arg.attribute, "email", 5)) {
13643 ast_copy_string(buf, vmu->email, len);
13644 } else if (!strncasecmp(arg.attribute, "pager", 5)) {
13645 ast_copy_string(buf, vmu->pager, len);
13646 } else if (!strncasecmp(arg.attribute, "language", 8)) {
13648 } else if (!strncasecmp(arg.attribute, "locale", 6)) {
13649 ast_copy_string(buf, vmu->locale, len);
13650 } else if (!strncasecmp(arg.attribute, "tz", 2)) {
13652 } else if (!strncasecmp(arg.attribute, "count", 5)) {
13653 char *mailbox_id;
13654
13655 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
13656 sprintf(mailbox_id, "%s@%s", mailbox, context);/* Safe */
13657
13658 /* If mbxfolder is empty messagecount will default to INBOX */
13659 res = messagecount(mailbox_id, arg.folder);
13660 if (res < 0) {
13661 ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
13662 free_user(vmu);
13663 return -1;
13664 }
13665 snprintf(buf, len, "%d", res);
13666 } else {
13667 ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
13668 free_user(vmu);
13669 return -1;
13670 }
13671 free_user(vmu);
13672 }
13673
13674 return 0;
13675}
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
#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 pager[80]
char password[80]
char zonetag[80]
char locale[20]
char language[MAX_LANGUAGE]
char fullname[80]
const char * args

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, voicemailpwcheck::context, ast_vm_user::email, find_user(), free_user(), ast_vm_user::fullname, ast_vm_user::language, len(), ast_vm_user::locale, LOG_ERROR, voicemailpwcheck::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 14819 of file app_voicemail_odbc.c.

14820{
14821 const char *val;
14822 char *q, *stringp, *tmp;
14823 int x;
14824 unsigned int tmpadsi[4];
14825 long tps_queue_low;
14826 long tps_queue_high;
14827
14828#ifdef IMAP_STORAGE
14829 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
14830#endif
14831 /* set audio control prompts */
14838
14839#ifdef IMAP_STORAGE
14840 ast_mwi_state_callback_all(imap_close_subscribed_mailbox, NULL);
14841#endif
14842
14843 /* Free all the users structure */
14844 free_vm_users();
14845
14846 /* Free all the zones structure */
14847 free_vm_zones();
14848
14849 /* Remove all aliases */
14852
14854
14855 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
14856 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
14857
14858 if (cfg) {
14859 /* General settings */
14860 aliasescontext[0] = '\0';
14861 val = ast_variable_retrieve(cfg, "general", "aliasescontext");
14863
14864 /* Attach voice message to mail message ? */
14865 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
14866 val = "yes";
14868
14869 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
14870 val = "no";
14872
14873 volgain = 0.0;
14874 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
14875 sscanf(val, "%30lf", &volgain);
14876
14877#ifdef ODBC_STORAGE
14878 strcpy(odbc_database, "asterisk");
14879 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
14880 ast_copy_string(odbc_database, val, sizeof(odbc_database));
14881 }
14882
14883 strcpy(odbc_table, "voicemessages");
14884 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
14885 ast_copy_string(odbc_table, val, sizeof(odbc_table));
14886 }
14887 odbc_table_len = strlen(odbc_table);
14888
14890 if (!(val = ast_variable_retrieve(cfg, "general", "odbc_audio_on_disk")))
14891 val = "no";
14893
14894#endif
14895 /* Mail command */
14896 strcpy(mailcmd, SENDMAIL);
14897 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
14898 ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */
14899
14900 maxsilence = 0;
14901 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
14902 maxsilence = atoi(val);
14903 if (maxsilence > 0)
14904 maxsilence *= 1000;
14905 }
14906
14907 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
14908 maxmsg = MAXMSG;
14909 } else {
14910 maxmsg = atoi(val);
14911 if (maxmsg < 0) {
14912 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
14913 maxmsg = MAXMSG;
14914 } else if (maxmsg > MAXMSGLIMIT) {
14915 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14917 }
14918 }
14919
14920 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
14921 maxdeletedmsg = 0;
14922 } else {
14923 if (sscanf(val, "%30d", &x) == 1)
14924 maxdeletedmsg = x;
14925 else if (ast_true(val))
14927 else
14928 maxdeletedmsg = 0;
14929
14930 if (maxdeletedmsg < 0) {
14931 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
14933 } else if (maxdeletedmsg > MAXMSGLIMIT) {
14934 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14936 }
14937 }
14938
14939 /* Load date format config for voicemail mail */
14940 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
14942 }
14943
14944 /* Load date format config for voicemail pager mail */
14945 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
14947 }
14948
14949 /* External password changing command */
14950 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
14953 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
14956 }
14957
14958 /* External password validation command */
14959 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
14961 ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd);
14962 }
14963
14964#ifdef IMAP_STORAGE
14965 /* IMAP server address */
14966 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
14967 ast_copy_string(imapserver, val, sizeof(imapserver));
14968 } else {
14969 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
14970 }
14971 /* IMAP server port */
14972 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
14973 ast_copy_string(imapport, val, sizeof(imapport));
14974 } else {
14975 ast_copy_string(imapport, "143", sizeof(imapport));
14976 }
14977 /* IMAP server flags */
14978 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
14979 ast_copy_string(imapflags, val, sizeof(imapflags));
14980 }
14981 /* IMAP server master username */
14982 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
14983 ast_copy_string(authuser, val, sizeof(authuser));
14984 }
14985 /* IMAP server master password */
14986 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
14987 ast_copy_string(authpassword, val, sizeof(authpassword));
14988 }
14989 /* Expunge on exit */
14990 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
14991 if (ast_false(val))
14992 expungeonhangup = 0;
14993 else
14994 expungeonhangup = 1;
14995 } else {
14996 expungeonhangup = 1;
14997 }
14998 /* IMAP voicemail folder */
14999 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
15000 ast_copy_string(imapfolder, val, sizeof(imapfolder));
15001 } else {
15002 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
15003 }
15004 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
15005 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
15006 }
15007 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
15008 imapgreetings = ast_true(val);
15009 } else {
15010 imapgreetings = 0;
15011 }
15012 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
15013 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
15014 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
15015 /* Also support greetingsfolder as documented in voicemail.conf.sample */
15016 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
15017 } else {
15018 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
15019 }
15020 if ((val = ast_variable_retrieve(cfg, "general", "imap_poll_logout"))) {
15021 imap_poll_logout = ast_true(val);
15022 } else {
15023 imap_poll_logout = 0;
15024 }
15025
15026 /* There is some very unorthodox casting done here. This is due
15027 * to the way c-client handles the argument passed in. It expects a
15028 * void pointer and casts the pointer directly to a long without
15029 * first dereferencing it. */
15030 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
15031 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
15032 } else {
15033 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
15034 }
15035
15036 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
15037 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
15038 } else {
15039 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
15040 }
15041
15042 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
15043 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
15044 } else {
15045 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
15046 }
15047
15048 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
15049 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
15050 } else {
15051 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
15052 }
15053
15054 /* Increment configuration version */
15055 imapversion++;
15056#endif
15057 /* External voicemail notify application */
15058 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
15060 ast_debug(1, "found externnotify: %s\n", externnotify);
15061 } else {
15062 externnotify[0] = '\0';
15063 }
15064
15065 /* SMDI voicemail notification */
15066 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
15067 ast_debug(1, "Enabled SMDI voicemail notification\n");
15068 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
15070 } else {
15071 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
15072 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
15073 }
15074 if (!smdi_iface) {
15075 ast_log(AST_LOG_ERROR, "No valid SMDI interface specified, disabling SMDI voicemail notification\n");
15076 }
15077 }
15078
15079 /* Silence treshold */
15081 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
15082 silencethreshold = atoi(val);
15083
15084 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
15087
15088 vmmaxsecs = 0;
15089 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
15090 if (sscanf(val, "%30d", &x) == 1) {
15091 vmmaxsecs = x;
15092 } else {
15093 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
15094 }
15095 }
15096
15097 vmminsecs = 0;
15098 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
15099 if (sscanf(val, "%30d", &x) == 1) {
15100 vmminsecs = x;
15101 if (maxsilence / 1000 >= vmminsecs) {
15102 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
15103 }
15104 } else {
15105 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
15106 }
15107 }
15108
15109 val = ast_variable_retrieve(cfg, "general", "format");
15110 if (!val) {
15111 val = "wav";
15112 } else {
15113 tmp = ast_strdupa(val);
15115 if (!val) {
15116 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
15117 val = "wav";
15118 }
15119 }
15120 ast_copy_string(vmfmts, val, sizeof(vmfmts));
15121
15122 skipms = 3000;
15123 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
15124 if (sscanf(val, "%30d", &x) == 1) {
15125 maxgreet = x;
15126 } else {
15127 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
15128 }
15129 }
15130
15131 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
15132 if (sscanf(val, "%30d", &x) == 1) {
15133 skipms = x;
15134 } else {
15135 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
15136 }
15137 }
15138
15139 maxlogins = 3;
15140 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
15141 if (sscanf(val, "%30d", &x) == 1) {
15142 maxlogins = x;
15143 } else {
15144 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
15145 }
15146 }
15147
15149 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
15150 if (sscanf(val, "%30d", &x) == 1) {
15151 minpassword = x;
15152 } else {
15153 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
15154 }
15155 }
15156
15157 /* Force new user to record name ? */
15158 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
15159 val = "no";
15161
15162 /* Force new user to record greetings ? */
15163 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
15164 val = "no";
15166
15167 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
15168 ast_debug(1, "VM_CID Internal context string: %s\n", val);
15169 stringp = ast_strdupa(val);
15170 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
15171 if (!ast_strlen_zero(stringp)) {
15172 q = strsep(&stringp, ",");
15173 while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
15174 q++;
15176 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
15177 } else {
15178 cidinternalcontexts[x][0] = '\0';
15179 }
15180 }
15181 }
15182 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
15183 ast_debug(1, "VM Review Option disabled globally\n");
15184 val = "no";
15185 }
15187
15188 if (!(val = ast_variable_retrieve(cfg, "general", "leaveurgent"))){
15189 val = "yes";
15190 } else if (ast_false(val)) {
15191 ast_debug(1, "VM leave urgent messages disabled globally\n");
15192 val = "no";
15193 }
15195
15196 /* Temporary greeting reminder */
15197 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
15198 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
15199 val = "no";
15200 } else {
15201 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
15202 }
15204 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
15205 ast_debug(1, "VM next message wrap disabled globally\n");
15206 val = "no";
15207 }
15209
15210 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
15211 ast_debug(1, "VM Operator break disabled globally\n");
15212 val = "no";
15213 }
15215
15216 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
15217 ast_debug(1, "VM CID Info before msg disabled globally\n");
15218 val = "no";
15219 }
15221
15222 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
15223 ast_debug(1, "Send Voicemail msg disabled globally\n");
15224 val = "no";
15225 }
15227
15228 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
15229 ast_debug(1, "ENVELOPE before msg enabled globally\n");
15230 val = "yes";
15231 }
15233
15234 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
15235 ast_debug(1, "Move Heard enabled globally\n");
15236 val = "yes";
15237 }
15239
15240 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
15241 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
15242 val = "no";
15243 }
15245
15246 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
15247 ast_debug(1, "Duration info before msg enabled globally\n");
15248 val = "yes";
15249 }
15251
15252 saydurationminfo = 2;
15253 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
15254 if (sscanf(val, "%30d", &x) == 1) {
15255 saydurationminfo = x;
15256 } else {
15257 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
15258 }
15259 }
15260
15261 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
15262 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
15263 val = "no";
15264 }
15266
15267 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
15269 ast_debug(1, "found dialout context: %s\n", dialcontext);
15270 } else {
15271 dialcontext[0] = '\0';
15272 }
15273
15274 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
15276 ast_debug(1, "found callback context: %s\n", callcontext);
15277 } else {
15278 callcontext[0] = '\0';
15279 }
15280
15281 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
15283 ast_debug(1, "found operator context: %s\n", exitcontext);
15284 } else {
15285 exitcontext[0] = '\0';
15286 }
15287
15288 /* load password sounds configuration */
15289 if ((val = ast_variable_retrieve(cfg, "general", "vm-login")))
15291 if ((val = ast_variable_retrieve(cfg, "general", "vm-newuser")))
15293 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
15295 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
15297 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
15299 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
15301 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
15303 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
15305 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
15307 }
15308 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
15310 }
15311 /* load configurable audio prompts */
15312 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
15314 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
15316 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
15318 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
15320 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
15322
15323 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
15324 val = "no";
15326
15327 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
15328 val = "voicemail.conf";
15329 }
15330 if (!(strcmp(val, "spooldir"))) {
15332 } else {
15334 }
15335
15337 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
15338 if (sscanf(val, "%30u", &poll_freq) != 1) {
15340 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
15341 }
15342 }
15343
15344 poll_mailboxes = 0;
15345 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
15347
15348 memset(fromstring, 0, sizeof(fromstring));
15349 memset(pagerfromstring, 0, sizeof(pagerfromstring));
15350 strcpy(charset, "ISO-8859-1");
15351 if (emailbody) {
15353 emailbody = NULL;
15354 }
15355 if (emailsubject) {
15358 }
15359 if (pagerbody) {
15361 pagerbody = NULL;
15362 }
15363 if (pagersubject) {
15366 }
15367 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
15369 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
15371 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
15373 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
15375 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
15376 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15377 for (x = 0; x < 4; x++) {
15378 memcpy(&adsifdn[x], &tmpadsi[x], 1);
15379 }
15380 }
15381 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
15382 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15383 for (x = 0; x < 4; x++) {
15384 memcpy(&adsisec[x], &tmpadsi[x], 1);
15385 }
15386 }
15387 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
15388 if (atoi(val)) {
15389 adsiver = atoi(val);
15390 }
15391 }
15392 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
15394 }
15395 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
15396 ast_copy_string(locale, val, sizeof(locale));
15397 }
15398 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
15400 }
15401 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
15403 }
15404 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
15406 }
15407 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
15409 }
15410
15411 tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;
15412 if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_high"))) {
15413 if (sscanf(val, "%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {
15414 ast_log(AST_LOG_WARNING, "Invalid the taskprocessor high water alert trigger level '%s'\n", val);
15415 tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;
15416 }
15417 }
15418 tps_queue_low = -1;
15419 if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_low"))) {
15420 if (sscanf(val, "%30ld", &tps_queue_low) != 1 ||
15421 tps_queue_low < -1 || tps_queue_high < tps_queue_low) {
15422 ast_log(AST_LOG_WARNING, "Invalid the taskprocessor low water clear alert level '%s'\n", val);
15423 tps_queue_low = -1;
15424 }
15425 }
15426 if (ast_taskprocessor_alert_set_levels(mwi_subscription_tps, tps_queue_low, tps_queue_high)) {
15427 ast_log(AST_LOG_WARNING, "Failed to set alert levels for voicemail taskprocessor.\n");
15428 }
15429
15430 /* load mailboxes from voicemail.conf */
15431
15432 /*
15433 * Aliases must be loaded before users or the aliases won't be notified
15434 * if there's existing voicemail in the user mailbox.
15435 */
15436 load_aliases(cfg);
15437
15438 load_zonemessages(cfg);
15439
15440 load_users(cfg);
15441
15443
15448
15449 return 0;
15450 } else {
15452 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
15453 return 0;
15454 }
15455}
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 void load_users(struct ast_config *cfg)
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
Definition: chan_unistim.c:336
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
char * ast_format_str_reduce(char *fmts)
Definition: file.c:1902
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
#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.
Definition: linkedlists.h:140
#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
struct ast_smdi_interface * 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:2199
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:2216
list of users found in the config file
Definition: ast_expr2.c:325
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
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:94

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_odbc.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:829
#define LOG_WARNING
int errno
char mailbox[MAX_VM_MBOX_ID_LEN]
double volgain
char context[MAX_VM_CONTEXT_LEN]
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition: utils.c:3107
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:702

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, voicemailpwcheck::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 13268 of file app_voicemail_odbc.c.

13269{
13270 struct ast_variable *var;
13271 struct ast_category *cat;
13272 generate_msg_id(id);
13273
13274 var = ast_variable_new("msg_id", id, "");
13275 if (!var) {
13276 return -1;
13277 }
13278
13279 cat = ast_category_get(msg_cfg, "message", NULL);
13280 if (!cat) {
13281 ast_log(LOG_ERROR, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
13283 return -1;
13284 }
13285
13287
13288 if (ast_config_text_file_save(filename, msg_cfg, "app_voicemail")) {
13289 ast_log(LOG_WARNING, "Unable to update %s to have a message ID\n", filename);
13290 return -1;
13291 }
13292
13293 UPDATE_MSG_ID(dir, msg, id, vmu, msg_cfg, folder);
13294 return 0;
13295}
#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.
Definition: main/config.c:2868
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: extconf.c:1177
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1205
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 7852 of file app_voicemail_odbc.c.

7853{
7854 int x;
7855 if (!ast_adsi_available(chan))
7856 return;
7857 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
7858 if (x < 0) {
7859 *useadsi = 0;
7861 return;
7862 }
7863 if (!x) {
7864 if (adsi_load_vmail(chan, useadsi)) {
7865 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
7866 return;
7867 }
7868 } else
7869 *useadsi = 1;
7870}
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 8051 of file app_voicemail_odbc.c.

8052{
8053 int bytes = 0;
8054 unsigned char buf[256];
8055 unsigned char keys[8];
8056
8057 int x;
8058
8059 if (!ast_adsi_available(chan))
8060 return;
8061
8062 /* New meaning for keys */
8063 for (x = 0; x < 5; x++)
8064 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
8065
8066 keys[6] = 0x0;
8067 keys[7] = 0x0;
8068
8069 if (!vms->curmsg) {
8070 /* No prev key, provide "Folder" instead */
8071 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8072 }
8073 if (vms->curmsg >= vms->lastmsg) {
8074 /* If last message ... */
8075 if (vms->curmsg) {
8076 /* but not only message, provide "Folder" instead */
8077 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8078 } else {
8079 /* Otherwise if only message, leave blank */
8080 keys[3] = 1;
8081 }
8082 }
8083
8084 /* If deleted, show "undeleted" */
8085#ifdef IMAP_STORAGE
8086 ast_mutex_lock(&vms->lock);
8087#endif
8088 if (vms->deleted[vms->curmsg]) {
8089 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8090 }
8091#ifdef IMAP_STORAGE
8092 ast_mutex_unlock(&vms->lock);
8093#endif
8094
8095 /* Except "Exit" */
8096 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8097 bytes += ast_adsi_set_keys(buf + bytes, keys);
8098 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8099
8101}
#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 7920 of file app_voicemail_odbc.c.

7921{
7922 unsigned char buf[256];
7923 int bytes = 0;
7924 unsigned char keys[8];
7925 int x, y;
7926
7927 if (!ast_adsi_available(chan))
7928 return;
7929
7930 for (x = 0; x < 5; x++) {
7931 y = ADSI_KEY_APPS + 12 + start + x;
7932 if (y > ADSI_KEY_APPS + 12 + 4)
7933 y = 0;
7934 keys[x] = ADSI_KEY_SKT | y;
7935 }
7936 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
7937 keys[6] = 0;
7938 keys[7] = 0;
7939
7940 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
7941 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
7942 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7943 bytes += ast_adsi_set_keys(buf + bytes, keys);
7944 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7945
7947}
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 8206 of file app_voicemail_odbc.c.

8207{
8208 unsigned char buf[256];
8209 int bytes = 0;
8210
8211 if (!ast_adsi_available(chan))
8212 return;
8213 bytes += adsi_logo(buf + bytes);
8214 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
8215 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
8216 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8217 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8218
8220}
#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 7723 of file app_voicemail_odbc.c.

7724{
7725 unsigned char buf[256];
7726 int bytes = 0;
7727 int x;
7728 char num[5];
7729
7730 *useadsi = 0;
7731 bytes += ast_adsi_data_mode(buf + bytes);
7733
7734 bytes = 0;
7735 bytes += adsi_logo(buf);
7736 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
7737#ifdef DISPLAY
7738 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
7739#endif
7740 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7741 bytes += ast_adsi_data_mode(buf + bytes);
7743
7745 bytes = 0;
7746 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
7747 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
7748 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7749 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7751 return 0;
7752 }
7753
7754#ifdef DISPLAY
7755 /* Add a dot */
7756 bytes = 0;
7757 bytes += ast_adsi_logo(buf);
7758 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
7759 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
7760 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7762#endif
7763 bytes = 0;
7764 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
7765 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
7766 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advanced", "3", 1);
7767 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
7768 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
7769 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
7771
7772#ifdef DISPLAY
7773 /* Add another dot */
7774 bytes = 0;
7775 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
7776 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7777
7778 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7780#endif
7781
7782 bytes = 0;
7783 /* These buttons we load but don't use yet */
7784 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
7785 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
7786 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
7787 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
7788 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
7789 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
7791
7792#ifdef DISPLAY
7793 /* Add another dot */
7794 bytes = 0;
7795 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
7796 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7798#endif
7799
7800 bytes = 0;
7801 for (x = 0; x < 5; x++) {
7802 snprintf(num, sizeof(num), "%d", x);
7803 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
7804 }
7805 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
7807
7808#ifdef DISPLAY
7809 /* Add another dot */
7810 bytes = 0;
7811 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
7812 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7814#endif
7815
7816 if (ast_adsi_end_download(chan)) {
7817 bytes = 0;
7818 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
7819 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
7820 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7821 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7823 return 0;
7824 }
7825 bytes = 0;
7826 bytes += ast_adsi_download_disconnect(buf + bytes);
7827 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7829
7830 ast_debug(1, "Done downloading scripts...\n");
7831
7832#ifdef DISPLAY
7833 /* Add last dot */
7834 bytes = 0;
7835 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
7836 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7837#endif
7838 ast_debug(1, "Restarting session...\n");
7839
7840 bytes = 0;
7841 /* Load the session now */
7842 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
7843 *useadsi = 1;
7844 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
7845 } else
7846 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
7847
7849 return 0;
7850}
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 7872 of file app_voicemail_odbc.c.

7873{
7874 unsigned char buf[256];
7875 int bytes = 0;
7876 unsigned char keys[8];
7877 int x;
7878 if (!ast_adsi_available(chan))
7879 return;
7880
7881 for (x = 0; x < 8; x++)
7882 keys[x] = 0;
7883 /* Set one key for next */
7884 keys[3] = ADSI_KEY_APPS + 3;
7885
7886 bytes += adsi_logo(buf + bytes);
7887 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
7888 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
7889 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7890 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
7891 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
7892 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
7893 bytes += ast_adsi_set_keys(buf + bytes, keys);
7894 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7896}
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 7715 of file app_voicemail_odbc.c.

7716{
7717 int bytes = 0;
7718 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
7719 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
7720 return bytes;
7721}

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 7949 of file app_voicemail_odbc.c.

7950{
7951 int bytes = 0;
7952 unsigned char buf[256];
7953 char buf1[256], buf2[256];
7954 char fn2[PATH_MAX];
7955
7956 char cid[256] = "";
7957 char *val;
7958 char *name, *num;
7959 char datetime[21] = "";
7960 FILE *f;
7961
7962 unsigned char keys[8];
7963
7964 int x;
7965
7966 if (!ast_adsi_available(chan))
7967 return;
7968
7969 /* Retrieve important info */
7970 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
7971 f = fopen(fn2, "r");
7972 if (f) {
7973 while (!feof(f)) {
7974 if (!fgets((char *) buf, sizeof(buf), f)) {
7975 continue;
7976 }
7977 if (!feof(f)) {
7978 char *stringp = NULL;
7979 stringp = (char *) buf;
7980 strsep(&stringp, "=");
7981 val = strsep(&stringp, "=");
7982 if (!ast_strlen_zero(val)) {
7983 if (!strcmp((char *) buf, "callerid"))
7984 ast_copy_string(cid, val, sizeof(cid));
7985 if (!strcmp((char *) buf, "origdate"))
7986 ast_copy_string(datetime, val, sizeof(datetime));
7987 }
7988 }
7989 }
7990 fclose(f);
7991 }
7992 /* New meaning for keys */
7993 for (x = 0; x < 5; x++)
7994 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
7995 keys[6] = 0x0;
7996 keys[7] = 0x0;
7997
7998 if (!vms->curmsg) {
7999 /* No prev key, provide "Folder" instead */
8000 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8001 }
8002 if (vms->curmsg >= vms->lastmsg) {
8003 /* If last message ... */
8004 if (vms->curmsg) {
8005 /* but not only message, provide "Folder" instead */
8006 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8007 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8008
8009 } else {
8010 /* Otherwise if only message, leave blank */
8011 keys[3] = 1;
8012 }
8013 }
8014
8015 if (!ast_strlen_zero(cid)) {
8016 ast_callerid_parse(cid, &name, &num);
8017 if (!name)
8018 name = num;
8019 } else {
8020 name = "Unknown Caller";
8021 }
8022
8023 /* If deleted, show "undeleted" */
8024#ifdef IMAP_STORAGE
8025 ast_mutex_lock(&vms->lock);
8026#endif
8027 if (vms->deleted[vms->curmsg]) {
8028 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8029 }
8030#ifdef IMAP_STORAGE
8031 ast_mutex_unlock(&vms->lock);
8032#endif
8033
8034 /* Except "Exit" */
8035 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8036 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
8037 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
8038 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
8039
8040 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8041 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8042 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
8043 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
8044 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8045 bytes += ast_adsi_set_keys(buf + bytes, keys);
8046 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8047
8049}
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
static struct ast_threadstorage buf2
static struct ast_threadstorage buf1
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, buf1, buf2, 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 7898 of file app_voicemail_odbc.c.

7899{
7900 unsigned char buf[256];
7901 int bytes = 0;
7902 unsigned char keys[8];
7903 int x;
7904 if (!ast_adsi_available(chan))
7905 return;
7906
7907 for (x = 0; x < 8; x++)
7908 keys[x] = 0;
7909 /* Set one key for next */
7910 keys[3] = ADSI_KEY_APPS + 3;
7911
7912 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7913 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
7914 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
7915 bytes += ast_adsi_set_keys(buf + bytes, keys);
7916 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7918}

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 8103 of file app_voicemail_odbc.c.

8104{
8105 unsigned char buf[256] = "";
8106 char buf1[256] = "", buf2[256] = "";
8107 int bytes = 0;
8108 unsigned char keys[8];
8109 int x;
8110
8111 char *newm = (vms->newmessages == 1) ? "message" : "messages";
8112 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
8113 if (!ast_adsi_available(chan))
8114 return;
8115 if (vms->newmessages) {
8116 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
8117 if (vms->oldmessages) {
8118 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
8119 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
8120 } else {
8121 snprintf(buf2, sizeof(buf2), "%s.", newm);
8122 }
8123 } else if (vms->oldmessages) {
8124 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
8125 snprintf(buf2, sizeof(buf2), "%s.", oldm);
8126 } else {
8127 strcpy(buf1, "You have no messages.");
8128 buf2[0] = ' ';
8129 buf2[1] = '\0';
8130 }
8131 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8132 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8133 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8134
8135 for (x = 0; x < 6; x++)
8136 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8137 keys[6] = 0;
8138 keys[7] = 0;
8139
8140 /* Don't let them listen if there are none */
8141 if (vms->lastmsg < 0)
8142 keys[0] = 1;
8143 bytes += ast_adsi_set_keys(buf + bytes, keys);
8144
8145 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8146
8148}

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, buf1, buf2, 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 8150 of file app_voicemail_odbc.c.

8151{
8152 unsigned char buf[256] = "";
8153 char buf1[256] = "", buf2[256] = "";
8154 int bytes = 0;
8155 unsigned char keys[8];
8156 int x;
8157
8158 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
8159
8160 if (!ast_adsi_available(chan))
8161 return;
8162
8163 /* Original command keys */
8164 for (x = 0; x < 6; x++)
8165 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8166
8167 keys[6] = 0;
8168 keys[7] = 0;
8169
8170 if ((vms->lastmsg + 1) < 1)
8171 keys[0] = 0;
8172
8173 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
8174 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
8175
8176 if (vms->lastmsg + 1)
8177 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
8178 else
8179 strcpy(buf2, "no messages.");
8180 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
8181 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
8182 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
8183 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
8184 bytes += ast_adsi_set_keys(buf + bytes, keys);
8185
8186 bytes += ast_adsi_voice_mode(buf + bytes, 0);
8187
8189
8190}

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, buf1, buf2, 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 16416 of file app_voicemail_odbc.c.

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

14728{
14729 struct alias_mailbox_mapping *mapping;
14730 size_t from_len = strlen(alias) + 1;
14731 size_t to_len = strlen(mailbox) + 1;
14732
14733 mapping = ao2_alloc(sizeof(*mapping) + from_len + to_len, NULL);
14734 if (!mapping) {
14735 return NULL;
14736 }
14737 mapping->alias = mapping->buf;
14738 mapping->mailbox = mapping->buf + from_len;
14739 ast_copy_string(mapping->alias, alias, from_len); /* Safe */
14740 ast_copy_string(mapping->mailbox, mailbox, to_len); /* Safe */
14741
14742 return mapping;
14743}
#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, voicemailpwcheck::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 13337 of file app_voicemail_odbc.c.

13338{
13339 /* Assumes lock is already held */
13340 char *tmp;
13341 char *stringp;
13342 char *s;
13343 struct ast_vm_user *vmu;
13344 char mailbox_full[MAX_VM_MAILBOX_LEN];
13345 int new = 0, old = 0, urgent = 0;
13346 char secretfn[PATH_MAX] = "";
13347
13348 tmp = ast_strdupa(data);
13349
13350 if (!(vmu = find_or_create(context, box)))
13351 return -1;
13352
13353 populate_defaults(vmu);
13354
13355 stringp = tmp;
13356 if ((s = strsep(&stringp, ","))) {
13357 if (!ast_strlen_zero(s) && s[0] == '*') {
13358 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
13359 "\n\tmust be reset in voicemail.conf.\n", box);
13360 }
13361 /* assign password regardless of validity to prevent NULL password from being assigned */
13362 ast_copy_string(vmu->password, s, sizeof(vmu->password));
13363 }
13364 if (stringp && (s = strsep(&stringp, ","))) {
13365 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
13366 }
13367 if (stringp && (s = strsep(&stringp, ","))) {
13368 vmu->email = ast_strdup(s);
13369 }
13370 if (stringp && (s = strsep(&stringp, ","))) {
13371 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
13372 }
13373 if (stringp) {
13374 apply_options(vmu, stringp);
13375 }
13376
13377 switch (vmu->passwordlocation) {
13378 case OPT_PWLOC_SPOOLDIR:
13379 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
13380 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
13381 }
13382
13383 snprintf(mailbox_full, MAX_VM_MAILBOX_LEN, "%s%s%s",
13384 box,
13385 ast_strlen_zero(context) ? "" : "@",
13386 context);
13387
13388 inboxcount2(mailbox_full, &urgent, &new, &old);
13389#ifdef IMAP_STORAGE
13390 imap_logout(mailbox_full);
13391#endif
13392 queue_mwi_event(NULL, mailbox_full, urgent, new, old);
13393
13394 return 0;
13395}
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.
int passwordlocation

References apply_options(), ast_copy_string(), ast_log, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_vm_user::context, voicemailpwcheck::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 14278 of file app_voicemail_odbc.c.

14284{
14285 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
14286 struct ast_vm_msg_snapshot *msg;
14287 int nummessages = 0;
14288 int i;
14289
14290 /* Take a snapshot of the mailbox */
14291 mailbox_snapshot = ast_vm_mailbox_snapshot_create(vmu->mailbox, vmu->context, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
14292 if (!mailbox_snapshot) {
14293 ast_log(LOG_ERROR, "Could not append voicemail box info for box %s@%s.",
14294 vmu->mailbox, vmu->context);
14295 return 0;
14296 }
14297
14298 astman_send_listack(s, m, "Voicemail box detail will follow", "start");
14299 /* walk through each folder's contents and append info for each message */
14300 for (i = 0; i < mailbox_snapshot->folders; i++) {
14301 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
14302 astman_append(s,
14303 "Event: %s\r\n"
14304 "%s"
14305 "Folder: %s\r\n"
14306 "CallerID: %s\r\n"
14307 "Date: %s\r\n"
14308 "Duration: %s\r\n"
14309 "Flag: %s\r\n"
14310 "ID: %s\r\n"
14311 "\r\n",
14312 event_name,
14313 actionid,
14314 msg->folder_name,
14315 msg->callerid,
14316 msg->origdate,
14317 msg->duration,
14318 msg->flag,
14319 msg->msg_id
14320 );
14321 nummessages++;
14322 }
14323 }
14324
14325 /* done, destroy. */
14326 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
14327 astman_send_list_complete_start(s, m, "VoicemailBoxDetailComplete", nummessages);
14329
14330 return 1;
14331}
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:2024
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:2060
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1903
@ 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.
Definition: linkedlists.h:491
struct ast_vm_msg_snapshot::@187 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 14154 of file app_voicemail_odbc.c.

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

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, voicemailpwcheck::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_odbc.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 * emailbody
char * emailsubject
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, ast_vm_user::maxmsg, 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_odbc.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_odbc.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}

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 17737 of file app_voicemail_odbc.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_odbc.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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
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_odbc.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_odbc.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.
Definition: main/config.c:3927
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3781

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

Referenced by vm_newuser_setup(), and vm_options().

◆ close_mailbox()

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

Definition at line 9574 of file app_voicemail_odbc.c.

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

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 12186 of file app_voicemail_odbc.c.

12187{
12188 const char *word = a->word;
12189 int pos = a->pos;
12190 int state = a->n;
12191 int which = 0;
12192 int wordlen;
12193 struct ast_vm_user *vmu;
12194 const char *context = "", *mailbox = "", *folder = "", *id = "";
12195 char *ret = NULL;
12196
12197 if (pos > maxpos) {
12198 /* If the passed in pos is above the max, return NULL to avoid 'over-filling' the cli */
12199 return NULL;
12200 }
12201
12202 /* if we are in pos 2 or pos 6 in 'forward' mode */
12203 if (pos == 2 || (pos == 6 && maxpos == 8)) {
12204 /* find users */
12205 wordlen = strlen(word);
12207 AST_LIST_TRAVERSE(&users, vmu, list) {
12208 if (!strncasecmp(word, vmu->mailbox , wordlen)) {
12209 if (mailbox && strcmp(mailbox, vmu->mailbox) && ++which > state) {
12210 ret = ast_strdup(vmu->mailbox);
12212 return ret;
12213 }
12214 mailbox = vmu->mailbox;
12215 }
12216 }
12218 } else if (pos == 3 || pos == 7) {
12219 /* find contexts that match the user */
12220 mailbox = (pos == 3) ? a->argv[2] : a->argv[6];
12221 wordlen = strlen(word);
12223 AST_LIST_TRAVERSE(&users, vmu, list) {
12224 if (!strncasecmp(word, vmu->context, wordlen) && !strcasecmp(mailbox, vmu->mailbox)) {
12225 if (context && strcmp(context, vmu->context) && ++which > state) {
12226 ret = ast_strdup(vmu->context);
12228 return ret;
12229 }
12230 context = vmu->context;
12231 }
12232 }
12234 } else if (pos == 4 || pos == 8 || (pos == 6 && maxpos == 6) ) {
12235 int i;
12236 /* Walk through the standard folders */
12237 wordlen = strlen(word);
12238 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12239 if (folder && !strncasecmp(word, mailbox_folders[i], wordlen) && ++which > state) {
12240 return ast_strdup(mailbox_folders[i]);
12241 }
12242 folder = mailbox_folders[i];
12243 }
12244 } else if (pos == 5) {
12245 /* find messages in the folder */
12246 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
12247 struct ast_vm_msg_snapshot *msg;
12248 mailbox = a->argv[2];
12249 context = a->argv[3];
12250 folder = a->argv[4];
12251 wordlen = strlen(word);
12252
12253 /* Take a snapshot of the mailbox and snag the individual info */
12254 if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create(mailbox, context, folder, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
12255 int i;
12256 /* we are only requesting the one folder, but we still need to know it's index */
12257 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12258 if (!strcasecmp(mailbox_folders[i], folder)) {
12259 break;
12260 }
12261 }
12262 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
12263 if (id && !strncasecmp(word, msg->msg_id, wordlen) && ++which > state) {
12264 ret = ast_strdup(msg->msg_id);
12265 break;
12266 }
12267 id = msg->msg_id;
12268 }
12269 /* done, destroy. */
12270 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
12271 }
12272 }
12273
12274 return ret;
12275}
static const char *const mailbox_folders[]
enum cc_state state
Definition: ccss.c:399
short word
struct ast_vm_user::@82 list
static struct test_val a
#define ARRAY_LEN(a)
Definition: utils.h:690

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, voicemailpwcheck::context, ast_vm_user::list, ast_vm_user::mailbox, voicemailpwcheck::mailbox, mailbox_folders, ast_vm_msg_snapshot::msg, NULL, and state.

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 12096 of file app_voicemail_odbc.c.

12097{
12098 const char *word = a->word;
12099 int pos = a->pos;
12100 int state = a->n;
12101 int which = 0;
12102 int wordlen;
12103 struct ast_vm_user *vmu;
12104 const char *context = "", *mailbox = "";
12105 char *ret = NULL;
12106
12107 /* 0 - voicemail; 1 - show; 2 - mailbox; 3 - <mailbox>; 4 - <context> */
12108 if (pos == 3) {
12109 wordlen = strlen(word);
12111 AST_LIST_TRAVERSE(&users, vmu, list) {
12112 if (!strncasecmp(word, vmu->mailbox , wordlen)) {
12113 if (mailbox && strcmp(mailbox, vmu->mailbox) && ++which > state) {
12114 ret = ast_strdup(vmu->mailbox);
12116 return ret;
12117 }
12118 mailbox = vmu->mailbox;
12119 }
12120 }
12122 } else if (pos == 4) {
12123 /* Only display contexts that match the user in pos 3 */
12124 const char *box = a->argv[3];
12125 wordlen = strlen(word);
12127 AST_LIST_TRAVERSE(&users, vmu, list) {
12128 if (!strncasecmp(word, vmu->context, wordlen) && !strcasecmp(box, vmu->mailbox)) {
12129 if (context && strcmp(context, vmu->context) && ++which > state) {
12130 ret = ast_strdup(vmu->context);
12132 return ret;
12133 }
12134 context = vmu->context;
12135 }
12136 }
12138 }
12139
12140 return ret;
12141}

References a, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_vm_user::context, voicemailpwcheck::context, ast_vm_user::list, ast_vm_user::mailbox, voicemailpwcheck::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 13762 of file app_voicemail_odbc.c.

13763{
13764 int which = 0;
13765 int wordlen;
13766 struct ast_vm_user *vmu;
13767 const char *context = "";
13768 char *ret;
13769
13770 /* 0 - voicemail; 1 - show; 2 - users; 3 - for; 4 - <context> */
13771 if (pos > 4)
13772 return NULL;
13773 wordlen = strlen(word);
13775 AST_LIST_TRAVERSE(&users, vmu, list) {
13776 if (!strncasecmp(word, vmu->context, wordlen)) {
13777 if (context && strcmp(context, vmu->context) && ++which > state) {
13778 ret = ast_strdup(vmu->context);
13780 return ret;
13781 }
13782 /* ignore repeated contexts ? */
13783 context = vmu->context;
13784 }
13785 }
13787 return NULL;
13788}

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_vm_user::context, voicemailpwcheck::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_odbc.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 copy_plain_file(), 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_odbc.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_odbc.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:1159
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
Definition: main/config.c:3972
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3738
struct ast_variable * next

References ast_check_realtime(), ast_filecopy(), ast_load_realtime(), ast_store_realtime(), ast_variables_destroy(), voicemailpwcheck::context, 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_odbc.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_odbc.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:150
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479

References ast_log, AST_LOG_WARNING, ast_mkdir(), voicemailpwcheck::context, 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 16344 of file app_voicemail_odbc.c.

16345{
16346 int cmd = 0;
16347 char destination[80] = "";
16348 int retries = 0;
16349
16350 if (!num) {
16351 ast_verb(3, "Destination number will be entered manually\n");
16352 while (retries < 3 && cmd != 't') {
16353 destination[1] = '\0';
16354 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
16355 if (!cmd)
16356 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
16357 if (!cmd)
16358 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
16359 if (!cmd) {
16360 cmd = ast_waitfordigit(chan, 6000);
16361 if (cmd)
16362 destination[0] = cmd;
16363 }
16364 if (!cmd) {
16365 retries++;
16366 } else {
16367
16368 if (cmd < 0)
16369 return 0;
16370 if (cmd == '*') {
16371 ast_verb(3, "User hit '*' to cancel outgoing call\n");
16372 return 0;
16373 }
16374 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
16375 retries++;
16376 else
16377 cmd = 't';
16378 }
16379 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
16380 isprint(cmd) ? cmd : '?', isprint(cmd) ? cmd : '?');
16381 }
16382 if (retries >= 3) {
16383 return 0;
16384 }
16385
16386 } else {
16387 ast_verb(3, "Destination number is CID number '%s'\n", num);
16388 ast_copy_string(destination, num, sizeof(destination));
16389 }
16390
16391 if (!ast_strlen_zero(destination)) {
16392 if (destination[strlen(destination) -1 ] == '*')
16393 return 0;
16394 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan));
16395 ast_channel_exten_set(chan, destination);
16396 ast_channel_context_set(chan, outgoing_context);
16397 ast_channel_priority_set(chan, 0);
16398 return 9;
16399 }
16400 return 0;
16401}
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:6513

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 13297 of file app_voicemail_odbc.c.

13298{
13299 struct ast_vm_user *vmu;
13300
13301 if (!ast_strlen_zero(box) && box[0] == '*') {
13302 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
13303 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
13304 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
13305 "\n\tand will be ignored.\n", box, context);
13306 return NULL;
13307 }
13308
13309 AST_LIST_TRAVERSE(&users, vmu, list) {
13310 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
13311 if (strcasecmp(vmu->context, context)) {
13312 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
13313 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
13314 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
13315 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
13316 }
13317 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
13318 return NULL;
13319 }
13320 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
13321 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
13322 return NULL;
13323 }
13324 }
13325
13326 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
13327 return NULL;
13328
13329 ast_copy_string(vmu->context, context, sizeof(vmu->context));
13330 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
13331
13333
13334 return vmu;
13335}
#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.
Definition: linkedlists.h:731

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, voicemailpwcheck::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_odbc.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.
Definition: linkedlists.h:439

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, voicemailpwcheck::context, ast_vm_user::email, ast_vm_user::emailbody, ast_vm_user::emailsubject, find_user(), find_user_realtime(), globalflags, ast_vm_user::list, alias_mailbox_mapping::mailbox, voicemailpwcheck::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_odbc.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:70

References apply_options_full(), ast_calloc, ast_copy_string(), ast_free, ast_load_realtime(), ast_set_flag, ast_test_flag, ast_variables_destroy(), voicemailpwcheck::context, globalflags, ast_vm_user::mailbox, voicemailpwcheck::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 8687 of file app_voicemail_odbc.c.

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

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, voicemailpwcheck::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(), LOG_ERROR, LOG_NOTICE, ast_vm_user::mailbox, voicemailpwcheck::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 12041 of file app_voicemail_odbc.c.

12042{
12043 const char *from_mailbox = a->argv[2];
12044 const char *from_context = a->argv[3];
12045 const char *from_folder = a->argv[4];
12046 const char *id[] = { a->argv[5] };
12047 const char *to_mailbox = a->argv[6];
12048 const char *to_context = a->argv[7];
12049 const char *to_folder = a->argv[8];
12050 int ret = vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1, id, 0);
12051 if (ret) {
12052 ast_cli(a->fd, "Error forwarding message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12053 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12054 } else {
12055 ast_cli(a->fd, "Forwarded message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12056 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12057 }
12058 return ret;
12059}
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
def from_mailbox(key, val, section, pjsip, nmapped)

References a, ast_cli(), sip_to_pjsip::from_mailbox(), 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_odbc.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 14616 of file app_voicemail_odbc.c.

14617{
14618 struct ast_vm_user *current;
14620 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
14623 }
14625}
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 14628 of file app_voicemail_odbc.c.

14629{
14630 struct vm_zone *zcur;
14632 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
14633 free_zone(zcur);
14635}
static void free_zone(struct vm_zone *z)
struct vm_zone::@83 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_odbc.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_odbc.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_odbc.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 8226 of file app_voicemail_odbc.c.

8227{
8228 int x;
8229 int d;
8230 char fn[PATH_MAX];
8231 d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
8232 if (d)
8233 return d;
8234 for (x = start; x < 5; x++) { /* For all folders */
8235 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
8236 return d;
8237 d = ast_play_and_wait(chan, "vm-for"); /* "for" */
8238 if (d)
8239 return d;
8240 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
8241
8242 /* The inbox folder can have its name changed under certain conditions
8243 * so this checks if the sound file exists for the inbox folder name and
8244 * if it doesn't, plays the default name instead. */
8245 if (x == 0) {
8246 if (ast_fileexists(fn, NULL, NULL)) {
8247 d = vm_play_folder_name(chan, fn);
8248 } else {
8249 ast_verb(4, "Failed to find file %s; falling back to INBOX\n", fn);
8250 d = vm_play_folder_name(chan, "vm-INBOX");
8251 }
8252 } else {
8253 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
8254 d = vm_play_folder_name(chan, fn);
8255 }
8256
8257 if (d)
8258 return d;
8259 d = ast_waitfordigit(chan, 500);
8260 if (d)
8261 return d;
8262 }
8263
8264 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
8265 if (d)
8266 return d;
8267 d = ast_waitfordigit(chan, 4000);
8268 return d;
8269}
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:8236
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 8311 of file app_voicemail_odbc.c.

8312{
8313 int res = 0;
8314 int loops = 0;
8315
8316 res = ast_play_and_wait(chan, fn); /* Folder name */
8317 while (((res < '0') || (res > '9')) &&
8318 (res != '#') && (res >= 0) &&
8319 loops < 4) {
8320 /* res = get_folder(chan, 0); */
8321 if (!strcasecmp(ast_channel_language(chan), "ja")) { /* Japanese syntax */
8322 res = get_folder_ja(chan, 0);
8323 } else { /* Default syntax */
8324 res = get_folder(chan, 0);
8325 }
8326 loops++;
8327 }
8328 if (loops == 4) { /* give up */
8329 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
8330 return '#';
8331 }
8332 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c",
8333 isprint(res) ? res : '?', isprint(res) ? res : '?');
8334 return res;
8335}
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_odbc.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 8272 of file app_voicemail_odbc.c.

8273{
8274 int x;
8275 int d;
8276 char fn[256];
8277 for (x = start; x < 5; x++) { /* For all folders */
8278 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL))) {
8279 return d;
8280 }
8281 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
8282 d = vm_play_folder_name(chan, fn);
8283 if (d) {
8284 return d;
8285 }
8286 d = ast_waitfordigit(chan, 500);
8287 if (d) {
8288 return d;
8289 }
8290 }
8291 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
8292 if (d) {
8293 return d;
8294 }
8295 d = ast_waitfordigit(chan, 4000);
8296 return d;
8297}

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 12277 of file app_voicemail_odbc.c.

12278{
12279 switch (cmd) {
12280 case CLI_INIT:
12281 e->command = "voicemail forward";
12282 e->usage =
12283 "Usage: voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>\n"
12284 " Forward message <messageid> in mailbox <mailbox>@<context> <from_folder>\n"
12285 " to mailbox <mailbox>@<context> <to_folder>\n";
12286 return NULL;
12287 case CLI_GENERATE:
12289 case CLI_HANDLER:
12290 break;
12291 }
12292
12293 if (a->argc != 9) {
12294 return CLI_SHOWUSAGE;
12295 }
12296
12298 return CLI_FAILURE;
12299 }
12300
12301 return CLI_SUCCESS;
12302}
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 12304 of file app_voicemail_odbc.c.

12305{
12306 switch (cmd) {
12307 case CLI_INIT:
12308 e->command = "voicemail move";
12309 e->usage =
12310 "Usage: voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>\n"
12311 " Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>\n";
12312 return NULL;
12313 case CLI_GENERATE:
12315 case CLI_HANDLER:
12316 break;
12317 }
12318
12319 if (a->argc != 7) {
12320 return CLI_SHOWUSAGE;
12321 }
12322
12324 return CLI_FAILURE;
12325 }
12326
12327 return CLI_SUCCESS;
12328}
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 13943 of file app_voicemail_odbc.c.

13944{
13945 switch (cmd) {
13946 case CLI_INIT:
13947 e->command = "voicemail reload";
13948 e->usage =
13949 "Usage: voicemail reload\n"
13950 " Reload voicemail configuration\n";
13951 return NULL;
13952 case CLI_GENERATE:
13953 return NULL;
13954 }
13955
13956 if (a->argc != 2)
13957 return CLI_SHOWUSAGE;
13958
13959 ast_cli(a->fd, "Reloading voicemail configuration...\n");
13960 load_config(1);
13961
13962 return CLI_SUCCESS;
13963}
static int load_config(int reload)

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 12330 of file app_voicemail_odbc.c.

12331{
12332 switch (cmd) {
12333 case CLI_INIT:
12334 e->command = "voicemail remove";
12335 e->usage =
12336 "Usage: voicemail remove <mailbox> <context> <from_folder> <messageid>\n"
12337 " Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>\n";
12338 return NULL;
12339 case CLI_GENERATE:
12341 case CLI_HANDLER:
12342 break;
12343 }
12344
12345 if (a->argc != 6) {
12346 return CLI_SHOWUSAGE;
12347 }
12348
12350 return CLI_FAILURE;
12351 }
12352
12353 return CLI_SUCCESS;
12354}
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 13903 of file app_voicemail_odbc.c.

13904{
13905 struct ao2_iterator aliases;
13906 struct alias_mailbox_mapping *mapping;
13907#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
13908 char *res = CLI_SUCCESS;
13909
13910 switch (cmd) {
13911 case CLI_INIT:
13912 e->command = "voicemail show aliases";
13913 e->usage =
13914 "Usage: voicemail show aliases\n"
13915 " Lists mailbox aliases\n";
13916 return NULL;
13917 case CLI_GENERATE:
13918 return NULL;
13919 }
13920
13921 if (a->argc != 3)
13922 return CLI_SHOWUSAGE;
13923
13925 ast_cli(a->fd, "Aliases are not enabled\n");
13926 return res;
13927 }
13928
13929 ast_cli(a->fd, "Aliases context: %s\n", aliasescontext);
13930 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, "Alias", "Mailbox");
13931
13933 while ((mapping = ao2_iterator_next(&aliases))) {
13934 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);
13935 ao2_ref(mapping, -1);
13936 }
13938
13939 return res;
13940}
#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 12143 of file app_voicemail_odbc.c.

12144{
12145 switch (cmd) {
12146 case CLI_INIT:
12147 e->command = "voicemail show mailbox";
12148 e->usage =
12149 "Usage: voicemail show mailbox <mailbox> <context>\n"
12150 " Show contents of mailbox <mailbox>@<context>\n";
12151 return NULL;
12152 case CLI_GENERATE:
12154 case CLI_HANDLER:
12155 break;
12156 }
12157
12158 if (a->argc != 5) {
12159 return CLI_SHOWUSAGE;
12160 }
12161
12163 return CLI_FAILURE;
12164 }
12165
12166 return CLI_SUCCESS;
12167}
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 13791 of file app_voicemail_odbc.c.

13792{
13793 struct ast_vm_user *vmu;
13794#define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
13795 const char *context = NULL;
13796 int users_counter = 0;
13797
13798 switch (cmd) {
13799 case CLI_INIT:
13800 e->command = "voicemail show users [for]";
13801 e->usage =
13802 "Usage: voicemail show users [for <context>]\n"
13803 " Lists all mailboxes currently set up\n";
13804 return NULL;
13805 case CLI_GENERATE:
13806 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
13807 }
13808
13809 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
13810 return CLI_SHOWUSAGE;
13811 if (a->argc == 5) {
13812 if (strcmp(a->argv[3],"for"))
13813 return CLI_SHOWUSAGE;
13814 context = a->argv[4];
13815 }
13816
13817 if (ast_check_realtime("voicemail")) {
13818 if (!context) {
13819 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
13820 return CLI_SHOWUSAGE;
13821 }
13822 return show_users_realtime(a->fd, context);
13823 }
13824
13826 if (AST_LIST_EMPTY(&users)) {
13827 ast_cli(a->fd, "There are no voicemail users currently defined\n");
13829 return CLI_FAILURE;
13830 }
13831 if (!context) {
13832 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
13833 } else {
13834 int count = 0;
13835 AST_LIST_TRAVERSE(&users, vmu, list) {
13836 if (!strcmp(context, vmu->context)) {
13837 count++;
13838 break;
13839 }
13840 }
13841 if (count) {
13842 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
13843 } else {
13844 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
13846 return CLI_FAILURE;
13847 }
13848 }
13849 AST_LIST_TRAVERSE(&users, vmu, list) {
13850 int newmsgs = 0, oldmsgs = 0;
13851 char count[12], tmp[256] = "";
13852
13853 if (!context || !strcmp(context, vmu->context)) {
13854 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
13855 inboxcount(tmp, &newmsgs, &oldmsgs);
13856 snprintf(count, sizeof(count), "%d", newmsgs);
13857 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
13858 users_counter++;
13859 }
13860 }
13862 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
13863 return CLI_SUCCESS;
13864}
#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, voicemailpwcheck::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 13867 of file app_voicemail_odbc.c.

13868{
13869 struct vm_zone *zone;
13870#define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
13871 char *res = CLI_SUCCESS;
13872
13873 switch (cmd) {
13874 case CLI_INIT:
13875 e->command = "voicemail show zones";
13876 e->usage =
13877 "Usage: voicemail show zones\n"
13878 " Lists zone message formats\n";
13879 return NULL;
13880 case CLI_GENERATE:
13881 return NULL;
13882 }
13883
13884 if (a->argc != 3)
13885 return CLI_SHOWUSAGE;
13886
13888 if (!AST_LIST_EMPTY(&zones)) {
13889 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
13890 AST_LIST_TRAVERSE(&zones, zone, list) {
13891 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
13892 }
13893 } else {
13894 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
13895 res = CLI_FAILURE;
13896 }
13898
13899 return res;
13900}
#define HVSZ_OUTPUT_FORMAT
char name[80]
char timezone[80]
char msg_format[512]

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_odbc.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(), voicemailpwcheck::context, voicemailpwcheck::mailbox, and strsep().

◆ inboxcount()

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

Definition at line 6598 of file app_voicemail_odbc.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 voicemailpwcheck::mailbox.

Referenced by append_vmu_info_astman(), 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_odbc.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(), voicemailpwcheck::context, inboxcount2(), voicemailpwcheck::mailbox, NULL, and strsep().

Referenced by append_mailbox(), 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_odbc.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]
char * context

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_odbc.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, voicemailpwcheck::context, inprocess::count, inprocess_container, LOG_WARNING, inprocess::mailbox, voicemailpwcheck::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_odbc.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_odbc.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(), voicemailpwcheck::context, 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_odbc.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_odbc.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_odbc.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 ast_unlock_path(dir);
7487 if (ast_check_realtime("voicemail_data")) {
7488 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
7489 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
7490 }
7491 /* We must store the file first, before copying the message, because
7492 * ODBC storage does the entire copy with SQL.
7493 */
7494 if (ast_fileexists(fn, NULL, NULL) > 0) {
7495 SCOPE_CALL(-1, STORE, dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
7496 }
7497
7498 /* Are there to be more recipients of this message? */
7499 while (tmpptr) {
7500 struct ast_vm_user recipu, *recip;
7501 char *exten, *cntx;
7502
7503 exten = strsep(&tmpptr, "&");
7504 cntx = strchr(exten, '@');
7505 if (cntx) {
7506 *cntx = '\0';
7507 cntx++;
7508 }
7509 memset(&recipu, 0, sizeof(recipu));
7510 if ((recip = find_user(&recipu, cntx, exten))) {
7511 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
7512 free_user(recip);
7513 }
7514 }
7515
7516 /* Notification needs to happen after the copy, though. */
7517 if (ast_fileexists(fn, NULL, NULL)) {
7518#ifdef IMAP_STORAGE
7519 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
7520 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7521 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7522 flag);
7523#else
7524 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
7525 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
7526 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
7527 flag);
7528#endif
7529 }
7530
7531 /* Disposal needs to happen after the optional move and copy */
7532 if (ast_fileexists(fn, NULL, NULL)) {
7533 SCOPE_CALL(-1, DISPOSE, dir, msgnum);
7534 }
7535 }
7536 }
7537 } else {
7538 inprocess_count(vmu->mailbox, vmu->context, -1);
7539 }
7540 if (res == '0') {
7541 goto transfer;
7542 } else if (res > 0 && res != 't')
7543 res = 0;
7544
7545 if (sound_duration < vmu->minsecs)
7546 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
7547 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7548 else
7549 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
7550 } else
7551 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
7552leave_vm_out:
7553 free_user(vmu);
7554
7555#ifdef IMAP_STORAGE
7556 /* expunge message - use UID Expunge if supported on IMAP server*/
7557 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
7558 if (expungeonhangup == 1 && vms->mailstream != NULL) {
7559 ast_mutex_lock(&vms->lock);
7560#ifdef HAVE_IMAP_TK2006
7561 if (LEVELUIDPLUS (vms->mailstream)) {
7562 mail_expunge_full(vms->mailstream, NIL, EX_UID);
7563 } else
7564#endif
7565 mail_expunge(vms->mailstream);
7566 ast_mutex_unlock(&vms->lock);
7567 }
7568#endif
7569
7570 ast_free(tmp);
7571 SCOPE_EXIT_RTN_VALUE(res, "Done: '%d'\n", res);
7572}
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)
Definition: chan_pjsip.c:2141
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2774
#define ast_channel_unlock(chan)
Definition: channel.h:2973
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1149
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
#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.
Definition: main/config.c:4008
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3891
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:4196
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:4211
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659

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(), ast_vm_user::context, voicemailpwcheck::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(), inboxcount(), inprocess_count(), INTRO, invent_message(), LAST_MSG_INDEX, 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, 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, strsep(), transfer(), 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 14745 of file app_voicemail_odbc.c.

14746{
14747 struct ast_variable *var;
14748
14750 return;
14751 }
14753 while (var) {
14754 struct alias_mailbox_mapping *mapping = alias_mailbox_mapping_create(var->name, var->value);
14755 if (mapping) {
14758 ao2_ref(mapping, -1);
14759 }
14760 var = var->next;
14761 }
14762}
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:1215

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 14713 of file app_voicemail_odbc.c.

14714{
14715 return load_config_force(reload, 0);
14716}
static int load_config_force(int reload, int force)
Reload voicemail.conf.
static int reload(void)

References load_config_force(), and reload().

Referenced by handle_voicemail_reload(), load_module(), 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 14684 of file app_voicemail_odbc.c.

14685{
14686 struct ast_config *cfg;
14687 struct ast_flags config_flags = { reload && !force ? CONFIG_FLAG_FILEUNCHANGED : 0 };
14688 int res;
14689
14690 ast_unload_realtime("voicemail");
14691 ast_unload_realtime("voicemail_data");
14692
14693 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14695 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
14696 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14697 return 0;
14698 }
14699 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
14700 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
14701 return 0;
14702 } else {
14704 }
14705
14706 res = actual_load_config(reload, cfg);
14707
14708 ast_config_destroy(cfg);
14709
14710 return res;
14711}
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.
Definition: main/config.c:3808
#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 16230 of file app_voicemail_odbc.c.

16231{
16232 int res;
16233 my_umask = umask(0);
16234 umask(my_umask);
16235
16238 if (!inprocess_container) {
16240 }
16241
16243 alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
16245 ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");
16248 }
16249 res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
16250 if (res) {
16251 ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");
16255 }
16256
16258 mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
16260 ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");
16262 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16265 }
16266 res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
16267 if (res) {
16268 ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");
16270 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16274 }
16275
16276 /* compute the location of the voicemail spool directory */
16277 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
16278
16279 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
16280 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
16281 }
16282
16283 if ((res = load_config(0))) {
16284 unload_module();
16286 }
16287
16301#ifdef TEST_FRAMEWORK
16302 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
16303 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
16304 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
16305 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
16306 res |= AST_TEST_REGISTER(test_voicemail_load_config);
16307 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
16308#endif
16309
16310 if (res) {
16311 ast_log(LOG_ERROR, "Failure registering applications, functions or tests\n");
16312 unload_module();
16314 }
16315
16316 /* ast_vm_register may return DECLINE if another module registered for vm */
16317 res = ast_vm_register(&vm_table);
16318 if (res) {
16319 ast_log(LOG_ERROR, "Failure registering as a voicemail provider\n");
16320 unload_module();
16322 }
16323
16324 /* ast_vm_greeter_register may return DECLINE if another module registered as a greeter */
16326 if (res) {
16327 ast_log(LOG_ERROR, "Failure registering as a greeter provider\n");
16328 unload_module();
16330 }
16331
16333
16334#ifdef TEST_FRAMEWORK
16335 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16336#endif
16337
16338 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
16339 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
16340
16342}
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:192
#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:1562
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 14799 of file app_voicemail_odbc.c.

14800{
14801 struct ast_variable *var;
14802 char *cat = NULL;
14803
14804 while ((cat = ast_category_browse(cfg, cat))) {
14805 if (strcasecmp(cat, "general") == 0
14806 || strcasecmp(cat, aliasescontext) == 0
14807 || strcasecmp(cat, "zonemessages") == 0) {
14808 continue;
14809 }
14810
14811 var = ast_variable_browse(cfg, cat);
14812 while (var) {
14813 append_mailbox(cat, var->name, var->value);
14814 var = var->next;
14815 }
14816 }
14817}
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:3326

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

Referenced by actual_load_config().

◆ load_zonemessages()

static void load_zonemessages ( struct ast_config cfg)
static

Definition at line 14764 of file app_voicemail_odbc.c.

14765{
14766 struct ast_variable *var;
14767
14768 var = ast_variable_browse(cfg, "zonemessages");
14769 while (var) {
14770 if (var->value) {
14771 struct vm_zone *z;
14772 char *msg_format, *tzone;
14773 char storage[strlen(var->value) + 1];
14774
14775 z = ast_malloc(sizeof(*z));
14776 if (!z) {
14777 return;
14778 }
14779
14780 strcpy(storage, var->value); /* safe */
14781 msg_format = storage;
14782 tzone = strsep(&msg_format, "|,");
14783 if (msg_format) {
14784 ast_copy_string(z->name, var->name, sizeof(z->name));
14785 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
14790 } else {
14791 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
14792 ast_free(z);
14793 }
14794 }
14795 var = var->next;
14796 }
14797}
#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_odbc.c.

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

References voicemailpwcheck::context, 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_odbc.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:3008
#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.
long int ast_random(void)
Definition: utils.c:2312

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_vm_user::context, voicemailpwcheck::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, voicemailpwcheck::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_odbc.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 14458 of file app_voicemail_odbc.c.

14459{
14460 struct ast_vm_user *vmu = NULL;
14461 const char *id = astman_get_header(m, "ActionID");
14462 char actionid[128];
14463 struct ast_vm_user svm;
14464
14465 const char *context = astman_get_header(m, "Context");
14466 const char *mailbox = astman_get_header(m, "Mailbox");
14467
14469 astman_send_error(s, m, "Need 'Context' and 'Mailbox' parameters.");
14470 return 0;
14471 }
14472
14473 actionid[0] = '\0';
14474 if (!ast_strlen_zero(id)) {
14475 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14476 }
14477
14478 /* find user */
14479 memset(&svm, 0, sizeof(svm));
14480 vmu = find_user(&svm, context, mailbox);
14481 if (!vmu) {
14482 /* could not find it */
14483 astman_send_ack(s, m, "There is no voicemail user matching the given user.");
14484 return 0;
14485 }
14486
14487 /* Append the mailbox details */
14488 if (!append_vmbox_info_astman(s, m, vmu, "VoicemailBoxDetail", actionid)) {
14489 astman_send_error(s, m, "Unable to get mailbox info for the given user.");
14490 }
14491
14492 free_user(vmu);
14493 return 0;
14494}
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:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643

References append_vmbox_info_astman(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), voicemailpwcheck::context, find_user(), free_user(), voicemailpwcheck::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 14417 of file app_voicemail_odbc.c.

14418{
14419 struct ast_vm_user *vmu = NULL;
14420 const char *id = astman_get_header(m, "ActionID");
14421 char actionid[128];
14422 int num_users = 0;
14423 int ret;
14424
14425 actionid[0] = '\0';
14426 if (!ast_strlen_zero(id)) {
14427 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14428 }
14429
14431
14432 if (AST_LIST_EMPTY(&users)) {
14433 astman_send_ack(s, m, "There are no voicemail users currently defined.");
14435 return RESULT_SUCCESS;
14436 }
14437
14438 astman_send_listack(s, m, "Voicemail user list will follow", "start");
14439
14440 AST_LIST_TRAVERSE(&users, vmu, list) {
14441 /* append vmu info event */
14442 ret = append_vmu_info_astman(s, vmu, "VoicemailUserEntry", actionid);
14443 if(ret == 0) {
14444 ast_log(LOG_ERROR, "Could not append voicemail user info.");
14445 continue;
14446 }
14447 ++num_users;
14448 }
14449
14450 astman_send_list_complete_start(s, m, "VoicemailUserEntryComplete", num_users);
14452
14454
14455 return RESULT_SUCCESS;
14456}
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 14333 of file app_voicemail_odbc.c.

14334{
14335 const char *context = astman_get_header(data, "Context");
14336 const char *mailbox = astman_get_header(data, "Mailbox");
14337 const char *at;
14338
14339 if (!ast_strlen_zero(mwi_state->uniqueid)) {
14340 if (
14341 /* First case: everything matches */
14343 /* Second case: match the mailbox only */
14345 (at = strchr(mwi_state->uniqueid, '@')) &&
14346 strncmp(mailbox, mwi_state->uniqueid, at - mwi_state->uniqueid) == 0) ||
14347 /* Third case: match the context only */
14349 (at = strchr(mwi_state->uniqueid, '@')) &&
14350 strcmp(context, at + 1) == 0) ||
14351 /* Final case: match an exact specified mailbox */
14353 (at = strchr(mwi_state->uniqueid, '@')) &&
14354 strncmp(mailbox, mwi_state->uniqueid, at - mwi_state->uniqueid) == 0 &&
14355 strcmp(context, at + 1) == 0)
14356 ) {
14357 poll_subscribed_mailbox(mwi_state, NULL);
14358 }
14359 }
14360
14361 return 0;
14362}
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(), voicemailpwcheck::context, voicemailpwcheck::mailbox, 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 14371 of file app_voicemail_odbc.c.

14372{
14373 struct ast_vm_user *vmu = NULL;
14374 const char *id = astman_get_header(m, "ActionID");
14375 char actionid[128];
14376 struct ast_vm_user svm;
14377 int ret;
14378
14379 const char *context = astman_get_header(m, "Context");
14380 const char *mailbox = astman_get_header(m, "Mailbox");
14381
14383 astman_send_error(s, m, "Need 'Context' and 'Mailbox' parameters.");
14384 return RESULT_SUCCESS;
14385 }
14386
14387 actionid[0] = '\0';
14388 if (!ast_strlen_zero(id)) {
14389 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
14390 }
14391
14392 /* find user */
14393 memset(&svm, 0, sizeof(svm));
14394 vmu = find_user(&svm, context, mailbox);
14395 if (!vmu) {
14396 /* could not find it */
14397 astman_send_ack(s, m, "There is no voicemail user of the given info.");
14398 return RESULT_SUCCESS;
14399 }
14400
14401 astman_send_listack(s, m, "Voicemail user detail will follow", "start");
14402
14403 /* append vmu info event */
14404 ret = append_vmu_info_astman(s, vmu, "VoicemailUserDetail", actionid);
14405 free_user(vmu);
14406 if(ret == 0) {
14407 ast_log(LOG_ERROR, "Could not append voicemail user info.");
14408 }
14409
14410 astman_send_list_complete_start(s, m, "VoicemailUserDetailComplete", 1);
14412
14413 return RESULT_SUCCESS;
14414}

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(), voicemailpwcheck::context, find_user(), free_user(), LOG_ERROR, voicemailpwcheck::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 14567 of file app_voicemail_odbc.c.

14568{
14569 const char *from_mailbox = astman_get_header(m, "Mailbox");
14570 const char *from_context = astman_get_header(m, "Context");
14571 const char *from_folder = astman_get_header(m, "Folder");
14572 const char *id[] = { astman_get_header(m, "ID") };
14573 const char *to_mailbox = astman_get_header(m, "ToMailbox");
14574 const char *to_context = astman_get_header(m, "ToContext");
14575 const char *to_folder = astman_get_header(m, "ToFolder");
14576
14578 astman_send_error(s, m, "Mailbox not specified, required");
14579 return 0;
14580 }
14581 if (ast_strlen_zero(from_context)) {
14582 astman_send_error(s, m, "Context not specified, required");
14583 return 0;
14584 }
14585 if (ast_strlen_zero(from_folder)) {
14586 astman_send_error(s, m, "Folder not specified, required");
14587 return 0;
14588 }
14589 if (ast_strlen_zero(id[0])) {
14590 astman_send_error(s, m, "ID not specified, required");
14591 return 0;
14592 }
14593 if (ast_strlen_zero(to_mailbox)) {
14594 astman_send_error(s, m, "ToMailbox not specified, required");
14595 return 0;
14596 }
14597 if (ast_strlen_zero(to_context)) {
14598 astman_send_error(s, m, "ToContext not specified, required");
14599 return 0;
14600 }
14601 if (ast_strlen_zero(to_folder)) {
14602 astman_send_error(s, m, "ToFolder not specified, required");
14603 return 0;
14604 }
14605
14606 if (vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1, id, 0)) {
14607 astman_send_ack(s, m, "Message forward failed\n");
14608 } else {
14609 astman_send_ack(s, m, "Message forward successful\n");
14610 }
14611
14612 return 0;
14613}

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), sip_to_pjsip::from_mailbox(), 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 14496 of file app_voicemail_odbc.c.

14497{
14498 const char *mailbox = astman_get_header(m, "Mailbox");
14499 const char *context = astman_get_header(m, "Context");
14500 const char *from_folder = astman_get_header(m, "Folder");
14501 const char *id[] = { astman_get_header(m, "ID") };
14502 const char *to_folder = astman_get_header(m, "ToFolder");
14503
14504 if (ast_strlen_zero(mailbox)) {
14505 astman_send_error(s, m, "Mailbox not specified, required");
14506 return 0;
14507 }
14508 if (ast_strlen_zero(context)) {
14509 astman_send_error(s, m, "Context not specified, required");
14510 return 0;
14511 }
14512 if (ast_strlen_zero(from_folder)) {
14513 astman_send_error(s, m, "Folder not specified, required");
14514 return 0;
14515 }
14516 if (ast_strlen_zero(id[0])) {
14517 astman_send_error(s, m, "ID not specified, required");
14518 return 0;
14519 }
14520 if (ast_strlen_zero(to_folder)) {
14521 astman_send_error(s, m, "ToFolder not specified, required");
14522 return 0;
14523 }
14524
14525 if (vm_msg_move(mailbox, context, 1, from_folder, id, to_folder)) {
14526 astman_send_ack(s, m, "Message move failed\n");
14527 } else {
14528 astman_send_ack(s, m, "Message move successful\n");
14529 }
14530
14531 return 0;
14532}
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(), voicemailpwcheck::context, voicemailpwcheck::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 14364 of file app_voicemail_odbc.c.

14365{
14367 astman_send_ack(s, m, "Refresh sent");
14368 return RESULT_SUCCESS;
14369}
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 14534 of file app_voicemail_odbc.c.

14535{
14536 const char *mailbox = astman_get_header(m, "Mailbox");
14537 const char *context = astman_get_header(m, "Context");
14538 const char *folder = astman_get_header(m, "Folder");
14539 const char *id[] = { astman_get_header(m, "ID") };
14540
14541 if (ast_strlen_zero(mailbox)) {
14542 astman_send_error(s, m, "Mailbox not specified, required");
14543 return 0;
14544 }
14545 if (ast_strlen_zero(context)) {
14546 astman_send_error(s, m, "Context not specified, required");
14547 return 0;
14548 }
14549 if (ast_strlen_zero(folder)) {
14550 astman_send_error(s, m, "Folder not specified, required");
14551 return 0;
14552 }
14553 if (ast_strlen_zero(id[0])) {
14554 astman_send_error(s, m, "ID not specified, required");
14555 return 0;
14556 }
14557
14558 if (vm_msg_remove(mailbox, context, 1, folder, id)) {
14559 astman_send_ack(s, m, "Message remove failed\n");
14560 } else {
14561 astman_send_ack(s, m, "Message remove successful\n");
14562 }
14563
14564 return 0;
14565}
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(), voicemailpwcheck::context, voicemailpwcheck::mailbox, and vm_msg_remove().

Referenced by load_module().

◆ mb_poll_thread()

static void * mb_poll_thread ( void *  data)
static

Definition at line 14001 of file app_voicemail_odbc.c.

14002{
14003 while (poll_thread_run) {
14004 struct timespec ts = { 0, };
14005 struct timeval wait;
14006
14008
14009 if (!poll_thread_run) {
14010 break;
14011 }
14012
14014 ts.tv_sec = wait.tv_sec;
14015 ts.tv_nsec = wait.tv_usec * 1000;
14016
14020 }
14021
14022 return NULL;
14023}
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:2282

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_odbc.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}
enum queue_result id
Definition: app_queue.c:1808

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 17208 of file app_voicemail_odbc.c.

17209{
17210 int i;
17211 int res = 0;
17212 for (i = 0; i < num_msgs; ++i) {
17213 const char *msg_id = msg_ids[i];
17214 int found = 0;
17215 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17216 const char *other_msg_id;
17217 char filename[PATH_MAX];
17218 struct ast_config *msg_cfg;
17219 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
17220
17221 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
17222 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
17223 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
17224 msg_cfg = ast_config_load(filename, config_flags);
17225 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17226 DISPOSE(vms->curdir, vms->curmsg);
17227 res = -1;
17228 goto done;
17229 }
17230
17231 other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
17232
17233 if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17234 /* Message found. We can get out of this inner loop
17235 * and move on to the next message to find
17236 */
17237 found = 1;
17238 msg_nums[i] = vms->curmsg;
17239 ast_config_destroy(msg_cfg);
17240 DISPOSE(vms->curdir, vms->curmsg);
17241 break;
17242 }
17243 ast_config_destroy(msg_cfg);
17244 DISPOSE(vms->curdir, vms->curmsg);
17245 }
17246 if (!found) {
17247 /* If we can't find one of the message IDs requested, then OH NO! */
17248 res = -1;
17249 goto done;
17250 }
17251 }
17252
17253done:
17254 return res;
17255}

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_odbc.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(), voicemailpwcheck::context, voicemailpwcheck::mailbox, and separate_mailbox().

Referenced by acf_vm_info().

◆ move_message_from_mailbox()

static int move_message_from_mailbox ( struct ast_cli_args a)
static

Definition at line 12061 of file app_voicemail_odbc.c.

12062{
12063 const char *mailbox = a->argv[2];
12064 const char *context = a->argv[3];
12065 const char *from_folder = a->argv[4];
12066 const char *id[] = { a->argv[5] };
12067 const char *to_folder = a->argv[6];
12068 int ret = vm_msg_move(mailbox, context, 1, from_folder, id, to_folder);
12069 if (ret) {
12070 ast_cli(a->fd, "Error moving message %s from mailbox %s@%s %s to %s\n",
12071 id[0], mailbox, context, from_folder, to_folder);
12072 } else {
12073 ast_cli(a->fd, "Moved message %s from mailbox %s@%s %s to %s\n",
12074 id[0], mailbox, context, from_folder, to_folder);
12075 }
12076 return ret;
12077}

References a, ast_cli(), voicemailpwcheck::context, voicemailpwcheck::mailbox, 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_odbc.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:1093
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1083
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:1379
int ast_ratestream(struct ast_filestream *fs)
Return the sample rate of the stream's format.
Definition: file.c:1098
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1119
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 14108 of file app_voicemail_odbc.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_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
struct stasis_forward * sub
Definition: res_corosync.c:240
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.

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 14101 of file app_voicemail_odbc.c.

14102{
14104 ao2_ref(data, -1);
14105 return 0;
14106}

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 14090 of file app_voicemail_odbc.c.

14091{
14092 void *data = ast_mwi_subscriber_data(sub);
14093
14094 /* Don't bump data's reference. We'll just use the one returned above */
14096 /* A reference was returned for data when retrieving, so remove it on error */
14097 ao2_ref(data, -1);
14098 }
14099}
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 14071 of file app_voicemail_odbc.c.

14072{
14073 struct ast_mwi_state *mwi_state = data;
14074
14075 /*
14076 * Go ahead and clear the implicit MWI publisher here to avoid a leak. If a backing
14077 * configuration is available it'll re-initialize (reset the cached state) on its
14078 * next publish.
14079 */
14081
14082#ifdef IMAP_STORAGE
14083 imap_close_subscribed_mailbox(mwi_state, NULL);
14084#endif
14085
14086 ao2_ref(mwi_state, -1);
14087 return 0;
14088}
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 8573 of file app_voicemail_odbc.c.

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

17258{
17259 int new = 0, old = 0, urgent = 0;
17260 char ext_context[1024];
17261
17262 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
17263 run_externnotify(vmu->context, vmu->mailbox, NULL);
17264 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
17265 queue_mwi_event(NULL, ext_context, urgent, new, old);
17266}

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 9520 of file app_voicemail_odbc.c.

9521{
9522 int count_msg, last_msg;
9523 SCOPE_ENTER(3, "user: %s dir: %s msg: %d box %d\n",
9524 vms->username, vms->curdir, vms->curmsg, box);
9525
9526 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
9527
9528 /* Rename the member vmbox HERE so that we don't try to return before
9529 * we know what's going on.
9530 */
9531 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
9532
9533 /* Faster to make the directory than to check if it exists. */
9534 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
9535
9536 /* traverses directory using readdir (or select query for ODBC) */
9537 count_msg = COUNT(vmu, vms->curdir);
9538 if (count_msg < 0) {
9539 SCOPE_EXIT_RTN_VALUE(count_msg, "msgs: %d\n", count_msg);
9540 } else {
9541 vms->lastmsg = count_msg - 1;
9542 }
9543
9544 if (vm_allocate_dh(vms, vmu, count_msg)) {
9545 SCOPE_EXIT_RTN_VALUE(-1, "failed to allocate dh\n");
9546 }
9547
9548 /*
9549 The following test is needed in case sequencing gets messed up.
9550 There appears to be more than one way to mess up sequence, so
9551 we will not try to find all of the root causes--just fix it when
9552 detected.
9553 */
9554
9555 if (vm_lock_path(vms->curdir)) {
9556 SCOPE_EXIT_LOG_RTN_VALUE(ERROR_LOCK_PATH, AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
9557 }
9558
9559 /* for local storage, checks directory for messages up to MAXMSGLIMIT */
9560 last_msg = LAST_MSG_INDEX(vms->curdir);
9561 ast_unlock_path(vms->curdir);
9562
9563 if (last_msg < -1) {
9564 SCOPE_EXIT_RTN_VALUE(last_msg, "last msg: %d\n", last_msg);
9565 } else if (vms->lastmsg != last_msg) {
9566 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);
9567 resequence_mailbox(vmu, vms->curdir, count_msg);
9568 }
9569
9570 SCOPE_EXIT_RTN_VALUE(0, "Done\n");
9571}
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 9266 of file app_voicemail_odbc.c.

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

11877{
11878 struct vm_state vms;
11879 struct ast_vm_user *vmu = NULL, vmus;
11880 int res = 0;
11881 int open = 0;
11882 int played = 0;
11883 int i;
11884
11885 memset(&vmus, 0, sizeof(vmus));
11886 memset(&vms, 0, sizeof(vms));
11887
11888 if (!(vmu = find_user(&vmus, context, mailbox))) {
11889 goto play_msg_cleanup;
11890 }
11891
11892 /* Iterate through every folder, find the msg, and play it */
11893 for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
11894 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
11895 vms.lastmsg = -1;
11896
11897 /* open the mailbox state */
11898 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
11899 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
11900 res = -1;
11901 goto play_msg_cleanup;
11902 }
11903 open = 1;
11904
11905 /* play msg if it exists in this mailbox */
11906 if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
11907 played = 1;
11908 }
11909
11910 /* close mailbox */
11911 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
11912 res = -1;
11913 goto play_msg_cleanup;
11914 }
11915 open = 0;
11916 }
11917
11918play_msg_cleanup:
11919 if (!played) {
11920 res = -1;
11921 }
11922
11923 if (vmu && open) {
11924 close_mailbox(&vms, vmu);
11925 }
11926
11927#ifdef IMAP_STORAGE
11928 if (vmu) {
11929 vmstate_delete(&vms);
11930 }
11931#endif
11932
11933 free_user(vmu);
11934
11935 return res;
11936}
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(), voicemailpwcheck::context, ERROR_LOCK_PATH, find_user(), free_user(), vm_state::lastmsg, LOG_WARNING, voicemailpwcheck::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 11833 of file app_voicemail_odbc.c.

11837{
11838 if (message_range_and_existence_check(vms, &msg_id, 1, &vms->curmsg, vmu)) {
11839 return -1;
11840 }
11841 /* Found the msg, so play it back */
11842
11843 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
11844
11845#ifdef IMAP_STORAGE
11846 /*IMAP storage stores any prepended message from a forward
11847 * as a separate file from the rest of the message
11848 */
11849 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
11850 wait_file(chan, vms, vms->introfn);
11851 }
11852#endif
11853 RETRIEVE(vms->curdir,vms->curmsg,vmu->mailbox, vmu->context);
11854
11855 if ((wait_file(chan, vms, vms->fn)) < 0) {
11856 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
11857 } else {
11858#ifdef IMAP_STORAGE
11859 ast_mutex_lock(&vms->lock);
11860#endif
11861 vms->heard[vms->curmsg] = 1;
11862#ifdef IMAP_STORAGE
11863 ast_mutex_unlock(&vms->lock);
11864#endif
11865 }
11866 DISPOSE(vms->curdir, vms->curmsg);
11867 return 0;
11868}
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 9139 of file app_voicemail_odbc.c.

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

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, voicemailpwcheck::context, 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 9046 of file app_voicemail_odbc.c.

9047{
9048 int res = 0;
9049
9050 if (!ast_strlen_zero(category))
9051 res = ast_play_and_wait(chan, category);
9052
9053 if (res) {
9054 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
9055 res = 0;
9056 }
9057
9058 return res;
9059}

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 9061 of file app_voicemail_odbc.c.

9062{
9063 int res = 0;
9064 struct vm_zone *the_zone = NULL;
9065 time_t t;
9066
9067 if (ast_get_time_t(origtime, &t, 0, NULL)) {
9068 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
9069 return 0;
9070 }
9071
9072 /* Does this user have a timezone specified? */
9073 if (!ast_strlen_zero(vmu->zonetag)) {
9074 /* Find the zone in the list */
9075 struct vm_zone *z;
9078 if (!strcmp(z->name, vmu->zonetag)) {
9079 the_zone = z;
9080 break;
9081 }
9082 }
9084 }
9085
9086/* No internal variable parsing for now, so we'll comment it out for the time being */
9087#if 0
9088 /* Set the DIFF_* variables */
9089 ast_localtime(&t, &time_now, NULL);
9090 tv_now = ast_tvnow();
9091 ast_localtime(&tv_now, &time_then, NULL);
9092
9093 /* Day difference */
9094 if (time_now.tm_year == time_then.tm_year)
9095 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
9096 else
9097 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
9098 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
9099
9100 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
9101#endif
9102 if (the_zone) {
9103 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
9104 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
9105 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9106 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
9107 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
9108 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
9109 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9110 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
9111 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);
9112 } else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
9113 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "PHM q 'jp-ni' 'vm-received'", NULL);
9114 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
9115 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
9116 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
9117 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
9118 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
9119 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q HM", NULL);
9120 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* Brazilian PORTUGUESE syntax */
9121 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);
9122 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
9123 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL);
9124 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
9125 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "qR 'vm-received'", NULL);
9126 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
9127 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);
9128 } else {
9129 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL);
9130 }
9131#if 0
9132 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
9133#endif
9134 return res;
9135}
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:2446

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 9216 of file app_voicemail_odbc.c.

9217{
9218 int res = 0;
9219 int durationm;
9220 int durations;
9221 /* Verify that we have a duration for the message */
9222 if (duration == NULL)
9223 return res;
9224
9225 /* Convert from seconds to minutes */
9226 durations = atoi(duration);
9227 durationm = (durations / 60);
9228
9229 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
9230
9231 if ((!res) && (durationm >= minduration)) {
9232 res = wait_file2(chan, vms, "vm-duration");
9233
9234 /* POLISH syntax */
9235 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9236 div_t num = div(durationm, 10);
9237
9238 if (durationm == 1) {
9239 res = ast_play_and_wait(chan, "digits/1z");
9240 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
9241 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9242 if (num.rem == 2) {
9243 if (!num.quot) {
9244 res = ast_play_and_wait(chan, "digits/2-ie");
9245 } else {
9246 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
9247 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
9248 }
9249 } else {
9250 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9251 }
9252 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
9253 } else {
9254 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9255 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
9256 }
9257 /* DEFAULT syntax */
9258 } else {
9259 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9260 res = wait_file2(chan, vms, "vm-minutes");
9261 }
9262 }
9263 return res;
9264}
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 16613 of file app_voicemail_odbc.c.

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

13977{
13978 int new = 0, old = 0, urgent = 0;
13979
13980 if (!mwi_state) {
13981 /* This should only occur due to allocation failure of a default mwi state object */
13982 return 0;
13983 }
13984
13985 inboxcount2(mwi_state->uniqueid, &urgent, &new, &old);
13986
13987#ifdef IMAP_STORAGE
13988 if (imap_poll_logout) {
13989 imap_logout(mwi_state->uniqueid);
13990 }
13991#endif
13992
13993 if (urgent != mwi_state->urgent_msgs || new != mwi_state->new_msgs || old != mwi_state->old_msgs) {
13994 queue_mwi_event(NULL, mwi_state->uniqueid, urgent, new, old);
13995 run_externnotify(NULL, mwi_state->uniqueid, NULL);
13996 }
13997
13998 return 0;
13999}
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_odbc.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:84
#define AST_FLAGS_ALL
Definition: utils.h:214

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_odbc.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, voicemailpwcheck::context, emaildateformat, ast_vm_user::fullname, ast_vm_user::locale, ast_vm_user::mailbox, voicemailpwcheck::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 16206 of file app_voicemail_odbc.c.

16207{
16208 struct alias_mailbox_mapping *mapping = v_obj;
16209
16210 if (!mapping) {
16211 return;
16212 }
16213 prnt(where, "Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);
16214}

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 8528 of file app_voicemail_odbc.c.

8529{
8530 char *mailbox;
8531 char *context;
8532
8534 return;
8535 }
8536
8537 ast_debug(3, "Queueing event for mailbox %s New: %d Old: %d\n", box, new + urgent, old);
8538 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
8539
8541 struct ao2_iterator *aliases;
8542 struct mailbox_alias_mapping *mapping;
8543
8545 while ((mapping = ao2_iterator_next(aliases))) {
8546 char alias[strlen(mapping->alias) + 1];
8547 strcpy(alias, mapping->alias); /* safe */
8548 mailbox = NULL;
8549 context = NULL;
8550 ast_debug(3, "Found alias mapping: %s -> %s\n", mapping->alias, box);
8552 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
8553 ao2_ref(mapping, -1);
8554 }
8556 }
8557}
#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(), voicemailpwcheck::context, voicemailpwcheck::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 15494 of file app_voicemail_odbc.c.

15494 {
15495 struct ast_config *pwconf;
15496 struct ast_flags config_flags = { 0 };
15497
15498 pwconf = ast_config_load(secretfn, config_flags);
15499 if (valid_config(pwconf)) {
15500 const char *val = ast_variable_retrieve(pwconf, "general", "password");
15501 if (val) {
15502 ast_copy_string(password, val, passwordlen);
15503 ast_config_destroy(pwconf);
15504 return;
15505 }
15506 ast_config_destroy(pwconf);
15507 }
15508 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
15509}

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 16148 of file app_voicemail_odbc.c.

16149{
16150 return load_config(1);
16151}

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 12079 of file app_voicemail_odbc.c.

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

References a, ast_cli(), voicemailpwcheck::context, voicemailpwcheck::mailbox, 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_odbc.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 7575 of file app_voicemail_odbc.c.

7576{
7577 /* we know the actual number of messages, so stop process when number is hit */
7578
7579 int x, dest;
7580 char sfn[PATH_MAX];
7581 char dfn[PATH_MAX];
7582
7583 if (vm_lock_path(dir)) {
7584 return ERROR_LOCK_PATH;
7585 }
7586
7587 for (x = 0, dest = 0; dest != stopcount && x < MAXMSGLIMIT; x++) {
7588 make_file(sfn, sizeof(sfn), dir, x);
7589 if (EXISTS(dir, x, sfn, NULL)) {
7590
7591 if (x != dest) {
7592 make_file(dfn, sizeof(dfn), dir, dest);
7593 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
7594 }
7595
7596 dest++;
7597 }
7598 }
7599 ast_unlock_path(dir);
7600
7601 return dest;
7602}

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_odbc.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:634
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, voicemailpwcheck::context, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, ast_vm_user::list, ast_vm_user::mailbox, voicemailpwcheck::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_odbc.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
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_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_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout, const char *station)
Definition: res_smdi.c:562
int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
Definition: res_smdi.c:320
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, voicemailpwcheck::context, 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 7612 of file app_voicemail_odbc.c.

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

15458{
15459 int res = -1;
15460 char dir[PATH_MAX];
15461 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
15462 ast_debug(2, "About to try retrieving name file %s\n", dir);
15463 RETRIEVE(dir, -1, mailbox, context);
15464 if (ast_fileexists(dir, NULL, NULL)) {
15465 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
15466 }
15467 DISPOSE(dir, -1);
15468 return res;
15469}

References ast_debug, AST_DIGIT_ANY, ast_fileexists(), ast_stream_and_wait(), voicemailpwcheck::context, DISPOSE, voicemailpwcheck::mailbox, NULL, PATH_MAX, RETRIEVE, and VM_SPOOL_DIR.

Referenced by 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_odbc.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:187

References ast_debug, ast_file_mkftemp(), ast_log, AST_LOG_WARNING, ast_safe_system(), ast_strdupa, ast_strlen_zero(), ast_test_flag, voicemailpwcheck::context, ast_vm_user::email, globalflags, ast_vm_user::mailbox, voicemailpwcheck::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_odbc.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(), voicemailpwcheck::context, ENDL, ast_vm_user::fullname, ast_vm_user::locale, voicemailpwcheck::mailbox, 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_odbc.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(), voicemailpwcheck::context, voicemailpwcheck::mailbox, 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 11977 of file app_voicemail_odbc.c.

11978{
11979#define VMBOX_STRING_HEADER_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11980#define VMBOX_STRING_DATA_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11981
11982 const char *mailbox = a->argv[3];
11983 const char *context = a->argv[4];
11984 struct vm_state vms;
11985 struct ast_vm_user *vmu = NULL, vmus;
11986 memset(&vmus, 0, sizeof(vmus));
11987 memset(&vms, 0, sizeof(vms));
11988
11989 if (!(vmu = find_user(&vmus, context, mailbox))) {
11990 ast_cli(a->fd, "Can't find voicemail user %s@%s\n", mailbox, context);
11991 return -1;
11992 }
11993
11994 ast_cli(a->fd, VMBOX_STRING_HEADER_FORMAT, "Full Name", "Email", "Pager", "Language", "Locale", "Time Zone");
11995 ast_cli(a->fd, VMBOX_STRING_DATA_FORMAT, vmu->fullname, vmu->email, vmu->pager, vmu->language, vmu->locale, vmu->zonetag);
11996
11997 return 0;
11998}
#define VMBOX_STRING_DATA_FORMAT
#define VMBOX_STRING_HEADER_FORMAT

References a, ast_cli(), voicemailpwcheck::context, ast_vm_user::email, find_user(), ast_vm_user::fullname, ast_vm_user::language, ast_vm_user::locale, voicemailpwcheck::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 12000 of file app_voicemail_odbc.c.

12001{
12002#define VM_STRING_HEADER_FORMAT "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
12003 const char *mailbox = a->argv[3];
12004 const char *context = a->argv[4];
12005 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
12006 struct ast_vm_msg_snapshot *msg;
12007 int i;
12008
12009 /* Take a snapshot of the mailbox and walk through each folder's contents */
12011 if (!mailbox_snapshot) {
12012 ast_cli(a->fd, "Can't create snapshot for voicemail user %s@%s\n", mailbox, context);
12013 return -1;
12014 }
12015
12016 ast_cli(a->fd, VM_STRING_HEADER_FORMAT, "Folder", "Caller ID", "Date", "Duration", "Flag", "ID");
12017
12018 for (i = 0; i < mailbox_snapshot->folders; i++) {
12019 AST_LIST_TRAVERSE(&((mailbox_snapshot)->snapshots[i]), msg, msg) {
12020 ast_cli(a->fd, VM_STRING_HEADER_FORMAT, msg->folder_name, msg->callerid, msg->origdate, msg->duration,
12021 msg->flag, msg->msg_id);
12022 }
12023 }
12024
12025 ast_cli(a->fd, "%d Message%s Total\n", mailbox_snapshot->total_msg_num, ESS(mailbox_snapshot->total_msg_num));
12026 /* done, destroy. */
12027 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
12028
12029 return 0;
12030}
#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, voicemailpwcheck::context, ESS, ast_vm_mailbox_snapshot::folders, voicemailpwcheck::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 12032 of file app_voicemail_odbc.c.

12033{
12034 if (show_mailbox_details(a)){
12035 return -1;
12036 }
12037 ast_cli(a->fd, "\n");
12038 return show_mailbox_snapshot(a);
12039}
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 13723 of file app_voicemail_odbc.c.

13724{
13725 struct ast_config *cfg;
13726 const char *cat = NULL;
13727
13728 if (!(cfg = ast_load_realtime_multientry("voicemail",
13729 "context", context, SENTINEL))) {
13730 return CLI_FAILURE;
13731 }
13732
13733 ast_cli(fd,
13734 "\n"
13735 "=============================================================\n"
13736 "=== Configured Voicemail Users ==============================\n"
13737 "=============================================================\n"
13738 "===\n");
13739
13740 while ((cat = ast_category_browse(cfg, cat))) {
13741 struct ast_variable *var = NULL;
13742 ast_cli(fd,
13743 "=== Mailbox ...\n"
13744 "===\n");
13745 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
13746 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
13747 ast_cli(fd,
13748 "===\n"
13749 "=== ---------------------------------------------------------\n"
13750 "===\n");
13751 }
13752
13753 ast_cli(fd,
13754 "=============================================================\n"
13755 "\n");
13756
13757 ast_config_destroy(cfg);
13758
13759 return CLI_SUCCESS;
13760}
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3854

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

Referenced by handle_voicemail_show_users().

◆ start_poll_thread()

static void start_poll_thread ( void  )
static

Definition at line 14124 of file app_voicemail_odbc.c.

14125{
14126 int errcode;
14128
14129 poll_thread_run = 1;
14130
14131 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
14132 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
14133 }
14134}
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:608

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 14136 of file app_voicemail_odbc.c.

14137{
14138 poll_thread_run = 0;
14139
14143
14144 pthread_join(poll_thread, NULL);
14146
14148}
#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_odbc.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}
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570

References buf, and input().

Referenced by make_email_file(), and sendpage().

◆ substitute_escapes()

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

Definition at line 14637 of file app_voicemail_odbc.c.

14638{
14639 char *current;
14640
14641 /* Add 16 for fudge factor */
14642 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
14643
14645
14646 /* Substitute strings \r, \n, and \t into the appropriate characters */
14647 for (current = (char *) value; *current; current++) {
14648 if (*current == '\\') {
14649 current++;
14650 if (!*current) {
14651 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
14652 break;
14653 }
14654 switch (*current) {
14655 case '\\':
14656 ast_str_append(&str, 0, "\\");
14657 break;
14658 case 'r':
14659 ast_str_append(&str, 0, "\r");
14660 break;
14661 case 'n':
14662#ifdef IMAP_STORAGE
14663 if (!str->used || str->str[str->used - 1] != '\r') {
14664 ast_str_append(&str, 0, "\r");
14665 }
14666#endif
14667 ast_str_append(&str, 0, "\n");
14668 break;
14669 case 't':
14670 ast_str_append(&str, 0, "\t");
14671 break;
14672 default:
14673 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
14674 break;
14675 }
14676 } else {
14677 ast_str_append(&str, 0, "%c", *current);
14678 }
14679 }
14680
14681 return ast_str_buffer(str);
14682}
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 16153 of file app_voicemail_odbc.c.

16154{
16155 int res;
16156
16163 res |= ast_manager_unregister("VoicemailUsersList");
16164 res |= ast_manager_unregister("VoicemailUserStatus");
16165 res |= ast_manager_unregister("VoicemailRefresh");
16166 res |= ast_manager_unregister("VoicemailBoxSummary");
16167 res |= ast_manager_unregister("VoicemailMove");
16168 res |= ast_manager_unregister("VoicemailRemove");
16169 res |= ast_manager_unregister("VoicemailForward");
16170#ifdef TEST_FRAMEWORK
16171 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
16172 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
16173 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
16174 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
16175 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
16176 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
16177#endif
16181#ifdef TEST_FRAMEWORK
16182 ast_uninstall_vm_test_functions();
16183#endif
16185
16186 ao2_container_unregister("voicemail_alias_mailbox_mappings");
16188 ao2_container_unregister("voicemail_mailbox_alias_mappings");
16190
16193
16195 ast_unload_realtime("voicemail");
16196 ast_unload_realtime("voicemail_data");
16197
16198#ifdef IMAP_STORAGE
16199 ast_mwi_state_callback_all(imap_close_subscribed_mailbox, NULL);
16200#endif
16201 free_vm_users();
16202 free_vm_zones();
16203 return res;
16204}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7695
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:392
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_odbc.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_odbc.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 11698 of file app_voicemail_odbc.c.

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

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(), voicemailpwcheck::context, find_user(), free_user(), voicemailpwcheck::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 11675 of file app_voicemail_odbc.c.

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

11488{
11489 int cmd = 0;
11490
11491 if (vms->lastmsg > -1) {
11492 cmd = play_message(chan, vmu, vms);
11493 } else {
11494 cmd = ast_play_and_wait(chan, "vm-youhave");
11495 if (!cmd)
11496 cmd = ast_play_and_wait(chan, "vm-no");
11497 if (!cmd) {
11498 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11499 cmd = ast_play_and_wait(chan, vms->fn);
11500 }
11501 if (!cmd)
11502 cmd = ast_play_and_wait(chan, "vm-messages");
11503 }
11504 return cmd;
11505}
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 11568 of file app_voicemail_odbc.c.

11569{
11570 int cmd;
11571
11572 if (vms->lastmsg > -1) {
11573 cmd = play_message(chan, vmu, vms);
11574 } else {
11575 cmd = ast_play_and_wait(chan, "vm-youhaveno");
11576 if (!cmd)
11577 cmd = ast_play_and_wait(chan, "vm-messages");
11578 if (!cmd) {
11579 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11580 cmd = ast_play_and_wait(chan, vms->fn);
11581 }
11582 }
11583 return cmd;
11584}

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 11435 of file app_voicemail_odbc.c.

11436{
11437 int cmd = 0;
11438
11439 if (vms->lastmsg > -1) {
11440 cmd = play_message(chan, vmu, vms);
11441 } else {
11442 cmd = ast_play_and_wait(chan, "vm-youhaveno");
11443 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
11444 if (!cmd) {
11445 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
11446 cmd = ast_play_and_wait(chan, vms->fn);
11447 }
11448 if (!cmd)
11449 cmd = ast_play_and_wait(chan, "vm-messages");
11450 } else {
11451 if (!cmd)
11452 cmd = ast_play_and_wait(chan, "vm-messages");
11453 if (!cmd) {
11454 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11455 cmd = ast_play_and_wait(chan, vms->fn);
11456 }
11457 }
11458 }
11459 return cmd;
11460}

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 11463 of file app_voicemail_odbc.c.

11464{
11465 int cmd = 0;
11466
11467 if (vms->lastmsg > -1) {
11468 cmd = play_message(chan, vmu, vms);
11469 } else {
11470 if (!strcasecmp(vms->fn, "INBOX")) {
11471 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
11472 } else {
11473 cmd = ast_play_and_wait(chan, "vm-nomessages");
11474 }
11475 }
11476 return cmd;
11477}

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 11515 of file app_voicemail_odbc.c.

11516{
11517 int cmd;
11518
11519 if (vms->lastmsg > -1) {
11520 cmd = play_message(chan, vmu, vms);
11521 } else {
11522 cmd = ast_play_and_wait(chan, "vm-no");
11523 if (!cmd)
11524 cmd = ast_play_and_wait(chan, "vm-message");
11525 if (!cmd) {
11526 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11527 cmd = ast_play_and_wait(chan, vms->fn);
11528 }
11529 }
11530 return cmd;
11531}

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 11541 of file app_voicemail_odbc.c.

11542{
11543 int cmd = 0;
11544
11545 if (vms->lastmsg > -1) {
11546 cmd = play_message(chan, vmu, vms);
11547 } else {
11548 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11549 cmd = ast_play_and_wait(chan, vms->fn);
11550 if (!cmd)
11551 cmd = ast_play_and_wait(chan, "vm-messages");
11552 if (!cmd)
11553 cmd = ast_play_and_wait(chan, "jp-wa");
11554 if (!cmd)
11555 cmd = ast_play_and_wait(chan, "jp-arimasen");
11556 }
11557 return cmd;
11558}

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 11594 of file app_voicemail_odbc.c.

11595{
11596 int cmd;
11597
11598 if (vms->lastmsg > -1) {
11599 cmd = play_message(chan, vmu, vms);
11600 } else {
11601 cmd = ast_play_and_wait(chan, "vm-no");
11602 if (!cmd) {
11603 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11604 cmd = ast_play_and_wait(chan, vms->fn);
11605 }
11606 if (!cmd)
11607 cmd = ast_play_and_wait(chan, "vm-messages");
11608 }
11609 return cmd;
11610}

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 11648 of file app_voicemail_odbc.c.

11649{
11650 int cmd = 0;
11651
11652 if (vms->lastmsg > -1) {
11653 cmd = play_message(chan, vmu, vms);
11654 } else {
11655 cmd = ast_play_and_wait(chan, "vm-no");
11656 if (!cmd) {
11657 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11658 cmd = ast_play_and_wait(chan, vms->fn);
11659 }
11660 }
11661 return cmd;
11662}

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 11620 of file app_voicemail_odbc.c.

11621{
11622 int cmd;
11623
11624 if (vms->lastmsg > -1) {
11625 cmd = play_message(chan, vmu, vms);
11626 } else {
11627 cmd = ast_play_and_wait(chan, "vm-you");
11628 if (!cmd)
11629 cmd = ast_play_and_wait(chan, "vm-haveno");
11630 if (!cmd)
11631 cmd = ast_play_and_wait(chan, "vm-messages");
11632 if (!cmd) {
11633 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11634 cmd = ast_play_and_wait(chan, vms->fn);
11635 }
11636 }
11637 return cmd;
11638}

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_odbc.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 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.
Definition: main/config.c:1645
@ 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_odbc.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_odbc.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:3207
#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:3202

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_odbc.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, make_ari_stubs::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 13187 of file app_voicemail_odbc.c.

13188{
13189 int res = 0;
13190 char *tmp;
13191 struct leave_vm_options leave_options;
13192 struct ast_flags flags = { 0 };
13193 char *opts[OPT_ARG_ARRAY_SIZE];
13195 AST_APP_ARG(argv0);
13196 AST_APP_ARG(argv1);
13197 );
13198 SCOPE_ENTER(3, "%s\n", ast_channel_name(chan));
13199
13200 memset(&leave_options, 0, sizeof(leave_options));
13201
13202 if (!ast_strlen_zero(data)) {
13203 tmp = ast_strdupa(data);
13205 if (args.argc == 2) {
13206 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
13207 SCOPE_EXIT_RTN_VALUE(-1, "parse options failed for '%s'\n", args.argv1);
13208 }
13211 int gain;
13212
13213 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
13214 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
13215 } else {
13216 leave_options.record_gain = (signed char) gain;
13217 }
13218 }
13221 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
13222 }
13223 }
13224 if (ast_test_flag(&flags, OPT_BEEP)) { /* Use custom beep (or none at all) */
13225 leave_options.beeptone = opts[OPT_ARG_BEEP_TONE];
13226 } else { /* Use default beep */
13227 leave_options.beeptone = "beep";
13228 }
13229 } else {
13230 char temp[256];
13231 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
13232 if (res < 0) {
13233 SCOPE_EXIT_RTN_VALUE(res, "getdata failed. RC: %d", res);
13234 }
13235 if (ast_strlen_zero(temp)) {
13237 }
13238 args.argv0 = ast_strdupa(temp);
13239 }
13240
13241 if (ast_channel_state(chan) != AST_STATE_UP) {
13244 } else {
13245 ast_answer(chan);
13246 }
13247 }
13248
13249 res = SCOPE_CALL_WITH_INT_RESULT(-1, leave_voicemail, chan, args.argv0, &leave_options);
13250 if (res == 't') {
13251 ast_play_and_wait(chan, "vm-goodbye");
13252 res = 0;
13253 }
13254
13255 if (res == OPERATOR_EXIT) {
13256 res = 0;
13257 }
13258
13259 if (res == ERROR_LOCK_PATH) {
13260 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
13261 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
13262 res = 0;
13263 }
13264
13265 SCOPE_EXIT_RTN_VALUE(res, "Done. RC: %d", res);
13266}
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:4230
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:3066
@ AST_CONTROL_PROGRESS
unsigned int flags
Definition: utils.h:218

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 12356 of file app_voicemail_odbc.c.

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

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

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_odbc.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 11106 of file app_voicemail_odbc.c.

11107{
11108 if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
11109 return vm_instructions_ja(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11110 } else if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
11111 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11112 } else { /* Default to ENGLISH */
11113 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11114 }
11115}
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 10896 of file app_voicemail_odbc.c.

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

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 10986 of file app_voicemail_odbc.c.

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

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 11082 of file app_voicemail_odbc.c.

11083{
11084 int res = 0;
11085 /* Play instructions and wait for new command */
11086 while (!res) {
11087 if (vms->lastmsg > -1) {
11088 res = ast_play_and_wait(chan, "vm-listen");
11089 if (!res)
11090 res = vm_play_folder_name(chan, vms->vmbox);
11091 if (!res)
11092 res = ast_play_and_wait(chan, "press");
11093 if (!res)
11094 res = ast_play_and_wait(chan, "digits/1");
11095 }
11096 if (!res)
11097 res = ast_play_and_wait(chan, "vm-opts");
11098 if (!res) {
11099 vms->starting = 0;
11100 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11101 }
11102 }
11103 return res;
11104}

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 10834 of file app_voicemail_odbc.c.

10835{
10836 char prefile[256];
10837
10838 /* Notify the user that the temp greeting is set and give them the option to remove it */
10839 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10840 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10841 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10842 if (ast_fileexists(prefile, NULL, NULL) > 0) {
10843 ast_play_and_wait(chan, "vm-tempgreetactive");
10844 }
10845 DISPOSE(prefile, -1);
10846 }
10847
10848 /* Play voicemail intro - syntax is different for different languages */
10849 if (0) {
10850 return 0;
10851 } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) { /* CZECH syntax */
10852 return vm_intro_cs(chan, vms);
10853 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
10854 return vm_intro_de(chan, vms);
10855 } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH syntax */
10856 return vm_intro_es(chan, vms);
10857 } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) { /* FRENCH syntax */
10858 return vm_intro_fr(chan, vms);
10859 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
10860 return vm_intro_gr(chan, vms);
10861 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */
10862 return vm_intro_he(chan, vms);
10863 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
10864 return vm_intro_is(chan, vms);
10865 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
10866 return vm_intro_it(chan, vms);
10867 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */
10868 return vm_intro_ja(chan, vms);
10869 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
10870 return vm_intro_nl(chan, vms);
10871 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
10872 return vm_intro_no(chan, vms);
10873 } else if (!strncasecmp(ast_channel_language(chan), "da", 2)) { /* DANISH syntax */
10874 return vm_intro_da(chan, vms);
10875 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
10876 return vm_intro_pl(chan, vms);
10877 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* BRAZILIAN PORTUGUESE syntax */
10878 return vm_intro_pt_BR(chan, vms);
10879 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE syntax */
10880 return vm_intro_pt(chan, vms);
10881 } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) { /* RUSSIAN syntax */
10882 return vm_intro_multilang(chan, vms, "n");
10883 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
10884 return vm_intro_se(chan, vms);
10885 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* UKRAINIAN syntax */
10886 return vm_intro_multilang(chan, vms, "n");
10887 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
10888 return vm_intro_vi(chan, vms);
10889 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
10890 return vm_intro_zh(chan, vms);
10891 } else { /* Default to ENGLISH */
10892 return vm_intro_en(chan, vms);
10893 }
10894}
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 10704 of file app_voicemail_odbc.c.

10705{
10706 int res;
10707 res = ast_play_and_wait(chan, "vm-youhave");
10708 if (!res) {
10709 if (vms->newmessages) {
10710 if (vms->newmessages == 1) {
10711 res = ast_play_and_wait(chan, "digits/jednu");
10712 } else {
10713 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10714 }
10715 if (!res) {
10716 if (vms->newmessages == 1)
10717 res = ast_play_and_wait(chan, "vm-novou");
10718 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10719 res = ast_play_and_wait(chan, "vm-nove");
10720 if (vms->newmessages > 4)
10721 res = ast_play_and_wait(chan, "vm-novych");
10722 }
10723 if (vms->oldmessages && !res)
10724 res = ast_play_and_wait(chan, "vm-and");
10725 else if (!res) {
10726 if (vms->newmessages == 1)
10727 res = ast_play_and_wait(chan, "vm-zpravu");
10728 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10729 res = ast_play_and_wait(chan, "vm-zpravy");
10730 if (vms->newmessages > 4)
10731 res = ast_play_and_wait(chan, "vm-zprav");
10732 }
10733 }
10734 if (!res && vms->oldmessages) {
10735 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10736 if (!res) {
10737 if (vms->oldmessages == 1)
10738 res = ast_play_and_wait(chan, "vm-starou");
10739 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10740 res = ast_play_and_wait(chan, "vm-stare");
10741 if (vms->oldmessages > 4)
10742 res = ast_play_and_wait(chan, "vm-starych");
10743 }
10744 if (!res) {
10745 if (vms->oldmessages == 1)
10746 res = ast_play_and_wait(chan, "vm-zpravu");
10747 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10748 res = ast_play_and_wait(chan, "vm-zpravy");
10749 if (vms->oldmessages > 4)
10750 res = ast_play_and_wait(chan, "vm-zprav");
10751 }
10752 }
10753 if (!res) {
10754 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10755 res = ast_play_and_wait(chan, "vm-no");
10756 if (!res)
10757 res = ast_play_and_wait(chan, "vm-zpravy");
10758 }
10759 }
10760 }
10761 return res;
10762}

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 10355 of file app_voicemail_odbc.c.

10356{
10357 /* Introduce messages they have */
10358 int res;
10359
10360 res = ast_play_and_wait(chan, "vm-youhave");
10361 if (res)
10362 return res;
10363
10364 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10365 res = ast_play_and_wait(chan, "vm-no");
10366 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10367 return res;
10368 }
10369
10370 if (vms->newmessages) {
10371 if ((vms->newmessages == 1)) {
10372 res = ast_play_and_wait(chan, "digits/1");
10373 res = res ? res : ast_play_and_wait(chan, "vm-INBOX");
10374 res = res ? res : ast_play_and_wait(chan, "vm-message");
10375 } else {
10376 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10377 res = res ? res : ast_play_and_wait(chan, "vm-INBOXs");
10378 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10379 }
10380 if (!res && vms->oldmessages)
10381 res = ast_play_and_wait(chan, "vm-and");
10382 }
10383 if (!res && vms->oldmessages) {
10384 if (vms->oldmessages == 1) {
10385 res = ast_play_and_wait(chan, "digits/1");
10386 res = res ? res : ast_play_and_wait(chan, "vm-Old");
10387 res = res ? res : ast_play_and_wait(chan, "vm-message");
10388 } else {
10389 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10390 res = res ? res : ast_play_and_wait(chan, "vm-Olds");
10391 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10392 }
10393 }
10394
10395 return res;
10396}

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 10400 of file app_voicemail_odbc.c.

10401{
10402 /* Introduce messages they have */
10403 int res;
10404 res = ast_play_and_wait(chan, "vm-youhave");
10405 if (!res) {
10406 if (vms->newmessages) {
10407 if (vms->newmessages == 1)
10408 res = ast_play_and_wait(chan, "digits/1F");
10409 else
10410 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10411 if (!res)
10412 res = ast_play_and_wait(chan, "vm-INBOX");
10413 if (vms->oldmessages && !res)
10414 res = ast_play_and_wait(chan, "vm-and");
10415 else if (!res) {
10416 if (vms->newmessages == 1)
10417 res = ast_play_and_wait(chan, "vm-message");
10418 else
10419 res = ast_play_and_wait(chan, "vm-messages");
10420 }
10421
10422 }
10423 if (!res && vms->oldmessages) {
10424 if (vms->oldmessages == 1)
10425 res = ast_play_and_wait(chan, "digits/1F");
10426 else
10427 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10428 if (!res)
10429 res = ast_play_and_wait(chan, "vm-Old");
10430 if (!res) {
10431 if (vms->oldmessages == 1)
10432 res = ast_play_and_wait(chan, "vm-message");
10433 else
10434 res = ast_play_and_wait(chan, "vm-messages");
10435 }
10436 }
10437 if (!res) {
10438 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10439 res = ast_play_and_wait(chan, "vm-no");
10440 if (!res)
10441 res = ast_play_and_wait(chan, "vm-messages");
10442 }
10443 }
10444 }
10445 return res;
10446}

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 10035 of file app_voicemail_odbc.c.

10036{
10037 int res;
10038
10039 /* Introduce messages they have */
10040 res = ast_play_and_wait(chan, "vm-youhave");
10041 if (!res) {
10042 if (vms->urgentmessages) {
10043 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
10044 if (!res)
10045 res = ast_play_and_wait(chan, "vm-Urgent");
10046 if ((vms->oldmessages || vms->newmessages) && !res) {
10047 res = ast_play_and_wait(chan, "vm-and");
10048 } else if (!res) {
10049 if (vms->urgentmessages == 1)
10050 res = ast_play_and_wait(chan, "vm-message");
10051 else
10052 res = ast_play_and_wait(chan, "vm-messages");
10053 }
10054 }
10055 if (vms->newmessages) {
10056 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10057 if (!res)
10058 res = ast_play_and_wait(chan, "vm-INBOX");
10059 if (vms->oldmessages && !res)
10060 res = ast_play_and_wait(chan, "vm-and");
10061 else if (!res) {
10062 if (vms->newmessages == 1)
10063 res = ast_play_and_wait(chan, "vm-message");
10064 else
10065 res = ast_play_and_wait(chan, "vm-messages");
10066 }
10067
10068 }
10069 if (!res && vms->oldmessages) {
10070 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10071 if (!res)
10072 res = ast_play_and_wait(chan, "vm-Old");
10073 if (!res) {
10074 if (vms->oldmessages == 1)
10075 res = ast_play_and_wait(chan, "vm-message");
10076 else
10077 res = ast_play_and_wait(chan, "vm-messages");
10078 }
10079 }
10080 if (!res) {
10081 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10082 res = ast_play_and_wait(chan, "vm-no");
10083 if (!res)
10084 res = ast_play_and_wait(chan, "vm-messages");
10085 }
10086 }
10087 }
10088 return res;
10089}

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 10449 of file app_voicemail_odbc.c.

10450{
10451 /* Introduce messages they have */
10452 int res;
10453 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10454 res = ast_play_and_wait(chan, "vm-youhaveno");
10455 if (!res)
10456 res = ast_play_and_wait(chan, "vm-messages");
10457 } else {
10458 res = ast_play_and_wait(chan, "vm-youhave");
10459 }
10460 if (!res) {
10461 if (vms->newmessages) {
10462 if (!res) {
10463 if (vms->newmessages == 1) {
10464 res = ast_play_and_wait(chan, "digits/1M");
10465 if (!res)
10466 res = ast_play_and_wait(chan, "vm-message");
10467 if (!res)
10468 res = ast_play_and_wait(chan, "vm-INBOXs");
10469 } else {
10470 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10471 if (!res)
10472 res = ast_play_and_wait(chan, "vm-messages");
10473 if (!res)
10474 res = ast_play_and_wait(chan, "vm-INBOX");
10475 }
10476 }
10477 if (vms->oldmessages && !res)
10478 res = ast_play_and_wait(chan, "vm-and");
10479 }
10480 if (vms->oldmessages) {
10481 if (!res) {
10482 if (vms->oldmessages == 1) {
10483 res = ast_play_and_wait(chan, "digits/1M");
10484 if (!res)
10485 res = ast_play_and_wait(chan, "vm-message");
10486 if (!res)
10487 res = ast_play_and_wait(chan, "vm-Olds");
10488 } else {
10489 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10490 if (!res)
10491 res = ast_play_and_wait(chan, "vm-messages");
10492 if (!res)
10493 res = ast_play_and_wait(chan, "vm-Old");
10494 }
10495 }
10496 }
10497 }
10498return res;
10499}

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 10547 of file app_voicemail_odbc.c.

10548{
10549 /* Introduce messages they have */
10550 int res;
10551 res = ast_play_and_wait(chan, "vm-youhave");
10552 if (!res) {
10553 if (vms->newmessages) {
10554 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10555 if (!res)
10556 res = ast_play_and_wait(chan, "vm-INBOX");
10557 if (vms->oldmessages && !res)
10558 res = ast_play_and_wait(chan, "vm-and");
10559 else if (!res) {
10560 if (vms->newmessages == 1)
10561 res = ast_play_and_wait(chan, "vm-message");
10562 else
10563 res = ast_play_and_wait(chan, "vm-messages");
10564 }
10565
10566 }
10567 if (!res && vms->oldmessages) {
10568 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10569 if (!res)
10570 res = ast_play_and_wait(chan, "vm-Old");
10571 if (!res) {
10572 if (vms->oldmessages == 1)
10573 res = ast_play_and_wait(chan, "vm-message");
10574 else
10575 res = ast_play_and_wait(chan, "vm-messages");
10576 }
10577 }
10578 if (!res) {
10579 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10580 res = ast_play_and_wait(chan, "vm-no");
10581 if (!res)
10582 res = ast_play_and_wait(chan, "vm-messages");
10583 }
10584 }
10585 }
10586 return res;
10587}

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 9795 of file app_voicemail_odbc.c.

9796{
9797 int res = 0;
9798
9799 if (vms->newmessages) {
9800 res = ast_play_and_wait(chan, "vm-youhave");
9801 if (!res)
9803 if (!res) {
9804 if (vms->newmessages == 1) {
9805 res = ast_play_and_wait(chan, "vm-INBOX");
9806 if (!res)
9807 res = ast_play_and_wait(chan, "vm-message");
9808 } else {
9809 res = ast_play_and_wait(chan, "vm-INBOXs");
9810 if (!res)
9811 res = ast_play_and_wait(chan, "vm-messages");
9812 }
9813 }
9814 } else if (vms->oldmessages){
9815 res = ast_play_and_wait(chan, "vm-youhave");
9816 if (!res)
9818 if (vms->oldmessages == 1){
9819 res = ast_play_and_wait(chan, "vm-Old");
9820 if (!res)
9821 res = ast_play_and_wait(chan, "vm-message");
9822 } else {
9823 res = ast_play_and_wait(chan, "vm-Olds");
9824 if (!res)
9825 res = ast_play_and_wait(chan, "vm-messages");
9826 }
9827 } else if (!vms->oldmessages && !vms->newmessages)
9828 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
9829 return res;
9830}

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 9929 of file app_voicemail_odbc.c.

9930{
9931 int res = 0;
9932
9933 /* Introduce messages they have */
9934 if (!res) {
9935 if ((vms->newmessages) || (vms->oldmessages)) {
9936 res = ast_play_and_wait(chan, "vm-youhave");
9937 }
9938 /*
9939 * The word "shtei" refers to the number 2 in hebrew when performing a count
9940 * of elements. In Hebrew, there are 6 forms of enumerating the number 2 for
9941 * an element, this is one of them.
9942 */
9943 if (vms->newmessages) {
9944 if (!res) {
9945 if (vms->newmessages == 1) {
9946 res = ast_play_and_wait(chan, "vm-INBOX1");
9947 } else {
9948 if (vms->newmessages == 2) {
9949 res = ast_play_and_wait(chan, "vm-shtei");
9950 } else {
9951 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9952 }
9953 res = ast_play_and_wait(chan, "vm-INBOX");
9954 }
9955 }
9956 if (vms->oldmessages && !res) {
9957 res = ast_play_and_wait(chan, "vm-and");
9958 if (vms->oldmessages == 1) {
9959 res = ast_play_and_wait(chan, "vm-Old1");
9960 } else {
9961 if (vms->oldmessages == 2) {
9962 res = ast_play_and_wait(chan, "vm-shtei");
9963 } else {
9964 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9965 }
9966 res = ast_play_and_wait(chan, "vm-Old");
9967 }
9968 }
9969 }
9970 if (!res && vms->oldmessages && !vms->newmessages) {
9971 if (!res) {
9972 if (vms->oldmessages == 1) {
9973 res = ast_play_and_wait(chan, "vm-Old1");
9974 } else {
9975 if (vms->oldmessages == 2) {
9976 res = ast_play_and_wait(chan, "vm-shtei");
9977 } else {
9978 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
9979 }
9980 res = ast_play_and_wait(chan, "vm-Old");
9981 }
9982 }
9983 }
9984 if (!res) {
9985 if (!vms->oldmessages && !vms->newmessages) {
9986 if (!res) {
9987 res = ast_play_and_wait(chan, "vm-nomessages");
9988 }
9989 }
9990 }
9991 }
9992 return res;
9993}

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 10092 of file app_voicemail_odbc.c.

10093{
10094 int res;
10095
10096 /* Introduce messages they have */
10097 res = ast_play_and_wait(chan, "vm-youhave");
10098 if (!res) {
10099 if (vms->urgentmessages) {
10100 /* Digits 1-4 are spoken in neutral and plural when talking about messages,
10101 however, feminine is used for 1 as it is the same as the neutral for plural,
10102 and singular neutral is the same after 1. */
10103 if (vms->urgentmessages < 5) {
10104 char recname[16];
10105 if (vms->urgentmessages == 1)
10106 snprintf(recname, sizeof(recname), "digits/1kvk");
10107 else
10108 snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages);
10109 res = ast_play_and_wait(chan, recname);
10110 } else if (!res)
10111 res = ast_play_and_wait(chan, "vm-Urgent");
10112 if ((vms->oldmessages || vms->newmessages) && !res) {
10113 res = ast_play_and_wait(chan, "vm-and");
10114 } else if (!res)
10115 res = ast_play_and_wait(chan, "vm-messages");
10116 }
10117 if (vms->newmessages) {
10118 if (vms->newmessages < 5) {
10119 char recname[16];
10120 if (vms->newmessages == 1)
10121 snprintf(recname, sizeof(recname), "digits/1kvk");
10122 else
10123 snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages);
10124 res = ast_play_and_wait(chan, recname);
10125 } else
10126 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10127 if (!res)
10128 res = ast_play_and_wait(chan, "vm-INBOX");
10129 if (vms->oldmessages && !res)
10130 res = ast_play_and_wait(chan, "vm-and");
10131 else if (!res)
10132 res = ast_play_and_wait(chan, "vm-messages");
10133 }
10134 if (!res && vms->oldmessages) {
10135 if (vms->oldmessages < 5) {
10136 char recname[16];
10137 if (vms->oldmessages == 1)
10138 snprintf(recname, sizeof(recname), "digits/1kvk");
10139 else
10140 snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages);
10141 res = ast_play_and_wait(chan, recname);
10142 } else
10143 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10144 if (!res)
10145 res = ast_play_and_wait(chan, "vm-Old");
10146 if (!res)
10147 res = ast_play_and_wait(chan, "vm-messages");
10148 }
10149 if (!res) {
10150 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10151 res = ast_play_and_wait(chan, "vm-no");
10152 if (!res)
10153 res = ast_play_and_wait(chan, "vm-messages");
10154 }
10155 }
10156 }
10157 return res;
10158}

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 10161 of file app_voicemail_odbc.c.

10162{
10163 /* Introduce messages they have */
10164 int res;
10165 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
10166 res = ast_play_and_wait(chan, "vm-no") ||
10167 ast_play_and_wait(chan, "vm-message");
10168 else
10169 res = ast_play_and_wait(chan, "vm-youhave");
10170 if (!res && vms->newmessages) {
10171 res = (vms->newmessages == 1) ?
10172 ast_play_and_wait(chan, "digits/un") ||
10173 ast_play_and_wait(chan, "vm-nuovo") ||
10174 ast_play_and_wait(chan, "vm-message") :
10175 /* 2 or more new messages */
10176 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
10177 ast_play_and_wait(chan, "vm-nuovi") ||
10178 ast_play_and_wait(chan, "vm-messages");
10179 if (!res && vms->oldmessages)
10180 res = ast_play_and_wait(chan, "vm-and");
10181 }
10182 if (!res && vms->oldmessages) {
10183 res = (vms->oldmessages == 1) ?
10184 ast_play_and_wait(chan, "digits/un") ||
10185 ast_play_and_wait(chan, "vm-vecchio") ||
10186 ast_play_and_wait(chan, "vm-message") :
10187 /* 2 or more old messages */
10188 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
10189 ast_play_and_wait(chan, "vm-vecchi") ||
10190 ast_play_and_wait(chan, "vm-messages");
10191 }
10192 return res;
10193}

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 9996 of file app_voicemail_odbc.c.

9997{
9998 /* Introduce messages they have */
9999 int res;
10000 if (vms->newmessages) {
10001 res = ast_play_and_wait(chan, "vm-INBOX");
10002 if (!res)
10003 res = ast_play_and_wait(chan, "vm-message");
10004 if (!res)
10005 res = ast_play_and_wait(chan, "jp-ga");
10006 if (!res)
10007 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10008 if (vms->oldmessages && !res)
10009 res = ast_play_and_wait(chan, "silence/1");
10010
10011 }
10012 if (vms->oldmessages) {
10013 res = ast_play_and_wait(chan, "vm-Old");
10014 if (!res)
10015 res = ast_play_and_wait(chan, "vm-message");
10016 if (!res)
10017 res = ast_play_and_wait(chan, "jp-ga");
10018 if (!res)
10019 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10020 }
10021 if (!vms->oldmessages && !vms->newmessages) {
10022 res = ast_play_and_wait(chan, "vm-messages");
10023 if (!res)
10024 res = ast_play_and_wait(chan, "jp-wa");
10025 if (!res)
10026 res = ast_play_and_wait(chan, "jp-arimasen");
10027 }
10028 else {
10029 res = ast_play_and_wait(chan, "jp-arimasu");
10030 }
10031 return res;
10032} /* 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 9889 of file app_voicemail_odbc.c.

9890{
9891 int res;
9892 int lastnum = 0;
9893
9894 res = ast_play_and_wait(chan, "vm-youhave");
9895
9896 if (!res && vms->newmessages) {
9897 lastnum = vms->newmessages;
9898
9899 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9900 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
9901 }
9902
9903 if (!res && vms->oldmessages) {
9904 res = ast_play_and_wait(chan, "vm-and");
9905 }
9906 }
9907
9908 if (!res && vms->oldmessages) {
9909 lastnum = vms->oldmessages;
9910
9911 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9912 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
9913 }
9914 }
9915
9916 if (!res) {
9917 if (lastnum == 0) {
9918 res = ast_play_and_wait(chan, "vm-no");
9919 }
9920 if (!res) {
9921 res = ast_say_counted_noun(chan, lastnum, "vm-message");
9922 }
9923 }
9924
9925 return res;
9926}
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 10590 of file app_voicemail_odbc.c.

10591{
10592 /* Introduce messages they have */
10593 int res;
10594 res = ast_play_and_wait(chan, "vm-youhave");
10595 if (!res) {
10596 if (vms->newmessages) {
10597 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10598 if (!res) {
10599 if (vms->newmessages == 1)
10600 res = ast_play_and_wait(chan, "vm-INBOXs");
10601 else
10602 res = ast_play_and_wait(chan, "vm-INBOX");
10603 }
10604 if (vms->oldmessages && !res)
10605 res = ast_play_and_wait(chan, "vm-and");
10606 else if (!res) {
10607 if (vms->newmessages == 1)
10608 res = ast_play_and_wait(chan, "vm-message");
10609 else
10610 res = ast_play_and_wait(chan, "vm-messages");
10611 }
10612
10613 }
10614 if (!res && vms->oldmessages) {
10615 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10616 if (!res) {
10617 if (vms->oldmessages == 1)
10618 res = ast_play_and_wait(chan, "vm-Olds");
10619 else
10620 res = ast_play_and_wait(chan, "vm-Old");
10621 }
10622 if (!res) {
10623 if (vms->oldmessages == 1)
10624 res = ast_play_and_wait(chan, "vm-message");
10625 else
10626 res = ast_play_and_wait(chan, "vm-messages");
10627 }
10628 }
10629 if (!res) {
10630 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10631 res = ast_play_and_wait(chan, "vm-no");
10632 if (!res)
10633 res = ast_play_and_wait(chan, "vm-messages");
10634 }
10635 }
10636 }
10637 return res;
10638}

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 10311 of file app_voicemail_odbc.c.

10312{
10313 /* Introduce messages they have */
10314 int res;
10315
10316 res = ast_play_and_wait(chan, "vm-youhave");
10317 if (res)
10318 return res;
10319
10320 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10321 res = ast_play_and_wait(chan, "vm-no");
10322 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10323 return res;
10324 }
10325
10326 if (vms->newmessages) {
10327 if (vms->newmessages == 1) {
10328 res = ast_play_and_wait(chan, "digits/1");
10329 res = res ? res : ast_play_and_wait(chan, "vm-ny");
10330 res = res ? res : ast_play_and_wait(chan, "vm-message");
10331 } else {
10332 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10333 res = res ? res : ast_play_and_wait(chan, "vm-nye");
10334 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10335 }
10336 if (!res && vms->oldmessages)
10337 res = ast_play_and_wait(chan, "vm-and");
10338 }
10339 if (!res && vms->oldmessages) {
10340 if (vms->oldmessages == 1) {
10341 res = ast_play_and_wait(chan, "digits/1");
10342 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
10343 res = res ? res : ast_play_and_wait(chan, "vm-message");
10344 } else {
10345 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10346 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
10347 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10348 }
10349 }
10350
10351 return res;
10352}

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 10196 of file app_voicemail_odbc.c.

10197{
10198 /* Introduce messages they have */
10199 int res;
10200 div_t num;
10201
10202 if (!vms->oldmessages && !vms->newmessages) {
10203 res = ast_play_and_wait(chan, "vm-no");
10204 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10205 return res;
10206 } else {
10207 res = ast_play_and_wait(chan, "vm-youhave");
10208 }
10209
10210 if (vms->newmessages) {
10211 num = div(vms->newmessages, 10);
10212 if (vms->newmessages == 1) {
10213 res = ast_play_and_wait(chan, "digits/1-a");
10214 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
10215 res = res ? res : ast_play_and_wait(chan, "vm-message");
10216 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10217 if (num.rem == 2) {
10218 if (!num.quot) {
10219 res = ast_play_and_wait(chan, "digits/2-ie");
10220 } else {
10221 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
10222 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
10223 }
10224 } else {
10225 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10226 }
10227 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
10228 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10229 } else {
10230 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10231 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
10232 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10233 }
10234 if (!res && vms->oldmessages)
10235 res = ast_play_and_wait(chan, "vm-and");
10236 }
10237 if (!res && vms->oldmessages) {
10238 num = div(vms->oldmessages, 10);
10239 if (vms->oldmessages == 1) {
10240 res = ast_play_and_wait(chan, "digits/1-a");
10241 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
10242 res = res ? res : ast_play_and_wait(chan, "vm-message");
10243 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10244 if (num.rem == 2) {
10245 if (!num.quot) {
10246 res = ast_play_and_wait(chan, "digits/2-ie");
10247 } else {
10248 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
10249 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
10250 }
10251 } else {
10252 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10253 }
10254 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
10255 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10256 } else {
10257 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10258 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
10259 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10260 }
10261 }
10262
10263 return res;
10264}

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 10641 of file app_voicemail_odbc.c.

10642{
10643 /* Introduce messages they have */
10644 int res;
10645 res = ast_play_and_wait(chan, "vm-youhave");
10646 if (!res) {
10647 if (vms->newmessages) {
10648 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10649 if (!res) {
10650 if (vms->newmessages == 1) {
10651 res = ast_play_and_wait(chan, "vm-message");
10652 if (!res)
10653 res = ast_play_and_wait(chan, "vm-INBOXs");
10654 } else {
10655 res = ast_play_and_wait(chan, "vm-messages");
10656 if (!res)
10657 res = ast_play_and_wait(chan, "vm-INBOX");
10658 }
10659 }
10660 if (vms->oldmessages && !res)
10661 res = ast_play_and_wait(chan, "vm-and");
10662 }
10663 if (!res && vms->oldmessages) {
10664 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10665 if (!res) {
10666 if (vms->oldmessages == 1) {
10667 res = ast_play_and_wait(chan, "vm-message");
10668 if (!res)
10669 res = ast_play_and_wait(chan, "vm-Olds");
10670 } else {
10671 res = ast_play_and_wait(chan, "vm-messages");
10672 if (!res)
10673 res = ast_play_and_wait(chan, "vm-Old");
10674 }
10675 }
10676 }
10677 if (!res) {
10678 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10679 res = ast_play_and_wait(chan, "vm-no");
10680 if (!res)
10681 res = ast_play_and_wait(chan, "vm-messages");
10682 }
10683 }
10684 }
10685 return res;
10686}

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 10502 of file app_voicemail_odbc.c.

10502 {
10503 /* Introduce messages they have */
10504 int res;
10505 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10506 res = ast_play_and_wait(chan, "vm-nomessages");
10507 return res;
10508 } else {
10509 res = ast_play_and_wait(chan, "vm-youhave");
10510 }
10511 if (vms->newmessages) {
10512 if (!res)
10513 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10514 if (vms->newmessages == 1) {
10515 if (!res)
10516 res = ast_play_and_wait(chan, "vm-message");
10517 if (!res)
10518 res = ast_play_and_wait(chan, "vm-INBOXs");
10519 } else {
10520 if (!res)
10521 res = ast_play_and_wait(chan, "vm-messages");
10522 if (!res)
10523 res = ast_play_and_wait(chan, "vm-INBOX");
10524 }
10525 if (vms->oldmessages && !res)
10526 res = ast_play_and_wait(chan, "vm-and");
10527 }
10528 if (vms->oldmessages) {
10529 if (!res)
10530 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
10531 if (vms->oldmessages == 1) {
10532 if (!res)
10533 res = ast_play_and_wait(chan, "vm-message");
10534 if (!res)
10535 res = ast_play_and_wait(chan, "vm-Olds");
10536 } else {
10537 if (!res)
10538 res = ast_play_and_wait(chan, "vm-messages");
10539 if (!res)
10540 res = ast_play_and_wait(chan, "vm-Old");
10541 }
10542 }
10543 return res;
10544}

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 10267 of file app_voicemail_odbc.c.

10268{
10269 /* Introduce messages they have */
10270 int res;
10271
10272 res = ast_play_and_wait(chan, "vm-youhave");
10273 if (res)
10274 return res;
10275
10276 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10277 res = ast_play_and_wait(chan, "vm-no");
10278 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10279 return res;
10280 }
10281
10282 if (vms->newmessages) {
10283 if (vms->newmessages == 1) {
10284 res = ast_play_and_wait(chan, "digits/ett");
10285 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
10286 res = res ? res : ast_play_and_wait(chan, "vm-message");
10287 } else {
10288 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10289 res = res ? res : ast_play_and_wait(chan, "vm-nya");
10290 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10291 }
10292 if (!res && vms->oldmessages)
10293 res = ast_play_and_wait(chan, "vm-and");
10294 }
10295 if (!res && vms->oldmessages) {
10296 if (vms->oldmessages == 1) {
10297 res = ast_play_and_wait(chan, "digits/ett");
10298 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
10299 res = res ? res : ast_play_and_wait(chan, "vm-message");
10300 } else {
10301 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10302 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
10303 res = res ? res : ast_play_and_wait(chan, "vm-messages");
10304 }
10305 }
10306
10307 return res;
10308}

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 10804 of file app_voicemail_odbc.c.

10805{
10806 int res;
10807
10808 /* Introduce messages they have */
10809 res = ast_play_and_wait(chan, "vm-youhave");
10810 if (!res) {
10811 if (vms->newmessages) {
10812 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10813 if (!res)
10814 res = ast_play_and_wait(chan, "vm-INBOX");
10815 if (vms->oldmessages && !res)
10816 res = ast_play_and_wait(chan, "vm-and");
10817 }
10818 if (!res && vms->oldmessages) {
10819 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10820 if (!res)
10821 res = ast_play_and_wait(chan, "vm-Old");
10822 }
10823 if (!res) {
10824 if (!vms->oldmessages && !vms->newmessages) {
10825 res = ast_play_and_wait(chan, "vm-no");
10826 if (!res)
10827 res = ast_play_and_wait(chan, "vm-message");
10828 }
10829 }
10830 }
10831 return res;
10832}

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 10765 of file app_voicemail_odbc.c.

10766{
10767 int res;
10768 /* Introduce messages they have */
10769 res = ast_play_and_wait(chan, "vm-you");
10770
10771 if (!res && vms->newmessages) {
10772 res = ast_play_and_wait(chan, "vm-have");
10773 if (!res)
10774 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10775 if (!res)
10776 res = ast_play_and_wait(chan, "vm-tong");
10777 if (!res)
10778 res = ast_play_and_wait(chan, "vm-INBOX");
10779 if (vms->oldmessages && !res)
10780 res = ast_play_and_wait(chan, "vm-and");
10781 else if (!res)
10782 res = ast_play_and_wait(chan, "vm-messages");
10783 }
10784 if (!res && vms->oldmessages) {
10785 res = ast_play_and_wait(chan, "vm-have");
10786 if (!res)
10787 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10788 if (!res)
10789 res = ast_play_and_wait(chan, "vm-tong");
10790 if (!res)
10791 res = ast_play_and_wait(chan, "vm-Old");
10792 if (!res)
10793 res = ast_play_and_wait(chan, "vm-messages");
10794 }
10795 if (!res && !vms->oldmessages && !vms->newmessages) {
10796 res = ast_play_and_wait(chan, "vm-haveno");
10797 if (!res)
10798 res = ast_play_and_wait(chan, "vm-messages");
10799 }
10800 return res;
10801}

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_odbc.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:2614

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 17057 of file app_voicemail_odbc.c.

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

References ARRAY_LEN, ast_calloc, ast_copy_string(), ast_free, ast_log, AST_LOG_ERROR, AST_LOG_WARNING, ast_strlen_zero(), close_mailbox(), voicemailpwcheck::context, ERROR_LOCK_PATH, find_user(), ast_vm_mailbox_snapshot::folders, free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, voicemailpwcheck::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 17174 of file app_voicemail_odbc.c.

17175{
17176 int i;
17177 struct ast_vm_msg_snapshot *msg_snapshot;
17178
17179 for (i = 0; i < mailbox_snapshot->folders; i++) {
17180 while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg))) {
17181 msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
17182 }
17183 }
17184 ast_free(mailbox_snapshot->snapshots);
17185 ast_free(mailbox_snapshot);
17186 return NULL;
17187}
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 17268 of file app_voicemail_odbc.c.

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

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(), sip_to_pjsip::from_mailbox(), 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 17411 of file app_voicemail_odbc.c.

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

References ast_alloca, ast_copy_string(), ast_log, ast_strlen_zero(), close_mailbox(), voicemailpwcheck::context, vm_state::deleted, ERROR_LOCK_PATH, find_user(), free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, voicemailpwcheck::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 17613 of file app_voicemail_odbc.c.

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

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, voicemailpwcheck::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, voicemailpwcheck::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 17515 of file app_voicemail_odbc.c.

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

References ast_alloca, ast_copy_string(), ast_log, AST_LOG_ERROR, ast_strlen_zero(), close_mailbox(), voicemailpwcheck::context, vm_state::deleted, ERROR_LOCK_PATH, find_user(), free_user(), get_folder_by_name(), vm_state::lastmsg, LOG_WARNING, voicemailpwcheck::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 16874 of file app_voicemail_odbc.c.

16875{
16876 struct ast_vm_msg_snapshot *msg_snapshot;
16877
16878 if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot)))) {
16879 return NULL;
16880 }
16881
16882 if (ast_string_field_init(msg_snapshot, 512)) {
16883 ast_free(msg_snapshot);
16884 return NULL;
16885 }
16886
16887 return msg_snapshot;
16888}
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359

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 16942 of file app_voicemail_odbc.c.

16949{
16950 struct ast_vm_msg_snapshot *msg_snapshot;
16951 struct ast_vm_msg_snapshot *msg_snapshot_tmp;
16952 struct ast_config *msg_cfg;
16953 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
16954 char filename[PATH_MAX];
16955 const char *value;
16956
16957 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
16958 int inserted = 0;
16959 /* Find the msg */
16960 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
16961 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
16962 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
16963 msg_cfg = ast_config_load(filename, config_flags);
16964 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
16965 DISPOSE(vms->curdir, vms->curmsg);
16966 continue;
16967 }
16968
16969 /* Create the snapshot object */
16970 if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
16971 ast_config_destroy(msg_cfg);
16972 return -1;
16973 }
16974
16975 /* Fill in the snapshot object */
16976 if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
16977 ast_string_field_set(msg_snapshot, msg_id, value);
16978 } else {
16979 /* Message snapshots *really* should have a
16980 * message ID. Add one to the message config
16981 * if it does not already exist
16982 */
16983 char id[MSG_ID_LEN];
16984 if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
16985 filename, id, sizeof(id), vmu, mailbox_index))) {
16986 ast_string_field_set(msg_snapshot, msg_id, id);
16987 } else {
16988 ast_log(LOG_WARNING, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
16989 }
16990 }
16991 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
16992 ast_string_field_set(msg_snapshot, callerid, value);
16993 }
16994 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
16995 ast_string_field_set(msg_snapshot, callerchan, value);
16996 }
16997 if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
16998 ast_string_field_set(msg_snapshot, exten, value);
16999 }
17000 if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
17001 ast_string_field_set(msg_snapshot, origdate, value);
17002 }
17003 if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
17004 ast_string_field_set(msg_snapshot, origtime, value);
17005 }
17006 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
17007 ast_string_field_set(msg_snapshot, duration, value);
17008 }
17009 if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
17010 ast_string_field_set(msg_snapshot, flag, value);
17011 }
17012 msg_snapshot->msg_number = vms->curmsg;
17013 ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);
17014
17015 /* store msg snapshot in mailbox snapshot */
17016 switch (sort_val) {
17017 default:
17019 if (descending) {
17020 AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17021 } else {
17022 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17023 }
17024 inserted = 1;
17025 break;
17027 AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
17028 int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
17029 if (descending && val >= 0) {
17030 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17031 inserted = 1;
17032 break;
17033 } else if (!descending && val <= 0) {
17034 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
17035 inserted = 1;
17036 break;
17037 }
17038 }
17040 break;
17041 }
17042
17043 if (!inserted) {
17044 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
17045 }
17046
17047 mailbox_snapshot->total_msg_num++;
17048
17049 /* cleanup configs and msg */
17050 ast_config_destroy(msg_cfg);
17051 DISPOSE(vms->curdir, vms->curmsg);
17052 }
17053
17054 return 0;
17055}
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.
Definition: linkedlists.h:599
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
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 16890 of file app_voicemail_odbc.c.

16891{
16892 ast_string_field_free_memory(msg_snapshot);
16893 ast_free(msg_snapshot);
16894
16895 return NULL;
16896}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

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 11117 of file app_voicemail_odbc.c.

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

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 11215 of file app_voicemail_odbc.c.

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

9757{
9758 int cmd;
9759
9760 if ( !strncasecmp(ast_channel_language(chan), "it", 2) ||
9761 !strncasecmp(ast_channel_language(chan), "es", 2) ||
9762 !strncasecmp(ast_channel_language(chan), "pt", 2)) { /* Italian, Spanish, or Portuguese syntax */
9763 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
9764 return cmd ? cmd : ast_play_and_wait(chan, box);
9765 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
9766 return vm_play_folder_name_gr(chan, box);
9767 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* Hebrew syntax */
9768 return ast_play_and_wait(chan, box);
9769 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
9770 return vm_play_folder_name_ja(chan, box);
9771 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9772 return vm_play_folder_name_pl(chan, box);
9773 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* Ukrainian syntax */
9774 return vm_play_folder_name_ua(chan, box);
9775 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
9776 return ast_play_and_wait(chan, box);
9777 } else { /* Default English */
9778 cmd = ast_play_and_wait(chan, box);
9779 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages */
9780 }
9781}
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 9696 of file app_voicemail_odbc.c.

9697{
9698 int cmd;
9699 char *buf;
9700
9701 buf = ast_alloca(strlen(box) + 2);
9702 strcpy(buf, box);
9703 strcat(buf, "s");
9704
9705 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
9706 cmd = ast_play_and_wait(chan, buf); /* "NEA / PALIA" */
9707 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9708 } else {
9709 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9710 return cmd ? cmd : ast_play_and_wait(chan, box); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
9711 }
9712}

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 9714 of file app_voicemail_odbc.c.

9715{
9716 int cmd;
9717
9718 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9719 cmd = ast_play_and_wait(chan, box);
9720 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9721 } else {
9722 cmd = ast_play_and_wait(chan, box);
9723 return cmd;
9724 }
9725}

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 9727 of file app_voicemail_odbc.c.

9728{
9729 int cmd;
9730
9731 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9732 if (!strcasecmp(box, "vm-INBOX"))
9733 cmd = ast_play_and_wait(chan, "vm-new-e");
9734 else
9735 cmd = ast_play_and_wait(chan, "vm-old-e");
9736 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9737 } else {
9738 cmd = ast_play_and_wait(chan, "vm-messages");
9739 return cmd ? cmd : ast_play_and_wait(chan, box);
9740 }
9741}

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 9743 of file app_voicemail_odbc.c.

9744{
9745 int cmd;
9746
9747 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
9748 cmd = ast_play_and_wait(chan, "vm-messages");
9749 return cmd ? cmd : ast_play_and_wait(chan, box);
9750 } else {
9751 cmd = ast_play_and_wait(chan, box);
9752 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9753 }
9754}

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 11938 of file app_voicemail_odbc.c.

11939{
11940 char *parse;
11941 char *mailbox = NULL;
11942 char *context = NULL;
11943 int res;
11944
11947 AST_APP_ARG(msg_id);
11948 );
11949
11950 if (ast_channel_state(chan) != AST_STATE_UP) {
11951 ast_debug(1, "Before ast_answer\n");
11952 ast_answer(chan);
11953 }
11954
11955 if (ast_strlen_zero(data)) {
11956 return -1;
11957 }
11958
11959 parse = ast_strdupa(data);
11961
11962 if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
11963 return -1;
11964 }
11965
11966 if ((context = strchr(args.mailbox, '@'))) {
11967 *context++ = '\0';
11968 }
11969 mailbox = args.mailbox;
11970
11971 res = play_message_by_id(chan, mailbox, context, args.msg_id);
11972 pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
11973
11974 return 0;
11975}
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(), voicemailpwcheck::context, voicemailpwcheck::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 15482 of file app_voicemail_odbc.c.

15483{
15484 char *context;
15485 char *mailbox;
15486
15487 if (ast_strlen_zero(mailbox_id)
15488 || separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
15489 return -1;
15490 }
15491 return sayname(chan, mailbox, context);
15492}
static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)

References ast_strdupa, ast_strlen_zero(), voicemailpwcheck::context, voicemailpwcheck::mailbox, 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 11360 of file app_voicemail_odbc.c.

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

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 13682 of file app_voicemail_odbc.c.

13683{
13684 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
13685 struct ast_vm_user vmus = {{0}};
13686 char *options = NULL;
13687 int silent = 0, skipuser = 0;
13688 int res = -1;
13689
13690 if (data) {
13691 s = ast_strdupa(data);
13692 user = strsep(&s, ",");
13693 options = strsep(&s, ",");
13694 if (user) {
13695 s = user;
13696 user = strsep(&s, "@");
13697 context = strsep(&s, "");
13698 if (!ast_strlen_zero(user))
13699 skipuser++;
13701 }
13702 }
13703
13704 if (options) {
13705 silent = (strchr(options, 's')) != NULL;
13706 }
13707
13708 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
13709 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
13710 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
13711 ast_play_and_wait(chan, "auth-thankyou");
13712 res = 0;
13713 } else if (mailbox[0] == '*') {
13714 /* user entered '*' */
13715 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
13716 res = 0; /* prevent hangup */
13717 }
13718 }
13719
13720 return res;
13721}
static char user[512]
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, voicemailpwcheck::context, voicemailpwcheck::mailbox, NULL, options, pbx_builtin_setvar_helper(), strsep(), user, and vm_authenticate().

Referenced by load_module().

◆ vmsayname_exec()

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

Definition at line 15544 of file app_voicemail_odbc.c.

15545{
15546 char *context;
15547 char *mailbox;
15548 int res;
15549
15550 if (ast_strlen_zero(data)
15552 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
15553 return -1;
15554 }
15555
15556 if ((res = sayname(chan, mailbox, context)) < 0) {
15557 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", mailbox, context);
15558 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
15559 if (!res) {
15561 }
15562 }
15563
15564 return res;
15565}
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:8272
@ 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(), voicemailpwcheck::context, LOG_WARNING, voicemailpwcheck::mailbox, 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_odbc.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 9040 of file app_voicemail_odbc.c.

9041{
9042 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
9044}
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:1465

References ast_control_streamfile(), ast_test_suite_event_notify, make_ari_stubs::file, 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 9032 of file app_voicemail_odbc.c.

9033{
9034 int res;
9035 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
9036 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
9037 return res;
9038}

References AST_DIGIT_ANY, ast_log, AST_LOG_WARNING, ast_stream_and_wait(), and make_ari_stubs::file.

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 15511 of file app_voicemail_odbc.c.

15511 {
15512 struct ast_config *conf;
15513 struct ast_category *cat;
15514 struct ast_variable *var;
15515 int res = -1;
15516
15517 if (!(conf = ast_config_new())) {
15518 ast_log(LOG_ERROR, "Error creating new config structure\n");
15519 return res;
15520 }
15521 if (!(cat = ast_category_new("general", "", 1))) {
15522 ast_log(LOG_ERROR, "Error creating new category structure\n");
15524 return res;
15525 }
15526 if (!(var = ast_variable_new("password", password, ""))) {
15527 ast_log(LOG_ERROR, "Error creating new variable structure\n");
15530 return res;
15531 }
15534 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
15535 res = 0;
15536 } else {
15537 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
15538 }
15539
15541 return res;
15542}
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: extconf.c:2833
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition: extconf.c:2788
void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2845
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 = "Comedian Mail (Voicemail System)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .optional_modules = "res_adsi,res_smdi", }
static

Definition at line 17737 of file app_voicemail_odbc.c.

◆ addesc

char* addesc = "Comedian Mail"
static

Definition at line 1088 of file app_voicemail_odbc.c.

Referenced by adsi_load_vmail().

◆ adsifdn

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

Definition at line 1211 of file app_voicemail_odbc.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_odbc.c.

Referenced by actual_load_config(), and adsi_load_vmail().

◆ adsiver

int adsiver = 1
static

Definition at line 1213 of file app_voicemail_odbc.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 17737 of file app_voicemail_odbc.c.

◆ callcontext

char callcontext[AST_MAX_CONTEXT] = ""
static

Definition at line 1197 of file app_voicemail_odbc.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_odbc.c.

◆ cidinternalcontexts

char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]
static

Definition at line 1200 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and play_message_callerid().

◆ cli_voicemail

struct ast_cli_entry cli_voicemail[]
static

Definition at line 13965 of file app_voicemail_odbc.c.

Referenced by load_module(), and unload_module().

◆ dialcontext

char dialcontext[AST_MAX_CONTEXT] = ""
static

Definition at line 1196 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ emailbody

char* emailbody
static

Definition at line 1203 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and make_email_file().

◆ emaildateformat

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

Definition at line 1214 of file app_voicemail_odbc.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_odbc.c.

Referenced by actual_load_config(), and make_email_file().

◆ exitcontext

char exitcontext[AST_MAX_CONTEXT] = ""
static

Definition at line 1198 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ ext_pass_check_cmd

char ext_pass_check_cmd[128]
static

Definition at line 1070 of file app_voicemail_odbc.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_odbc.c.

Referenced by actual_load_config(), and run_externnotify().

◆ fromstring

char fromstring[100]
static

◆ globalflags

struct ast_flags globalflags = {0}
static

◆ inprocess_container

struct ao2_container* inprocess_container

Definition at line 1298 of file app_voicemail_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.c.

Referenced by actual_load_config(), and wait_file().

◆ locale

char locale[20]
static

Definition at line 1105 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ mailbox_alias_mappings

struct ao2_container* mailbox_alias_mappings
static

◆ mailbox_folders

const char* const mailbox_folders[]
static

◆ mailcmd

char mailcmd[160] = SENDMAIL
static

◆ maxdeletedmsg

int maxdeletedmsg
static

Definition at line 1108 of file app_voicemail_odbc.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_odbc.c.

Referenced by actual_load_config(), and vm_execmain().

◆ maxmsg

int maxmsg = MAXMSG
static

Definition at line 1107 of file app_voicemail_odbc.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_odbc.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_odbc.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 14119 of file app_voicemail_odbc.c.

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_odbc.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_odbc.c.

Referenced by actual_load_config(), and sendpage().

◆ pagerfromstring

char pagerfromstring[100]
static

Definition at line 1208 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and sendpage().

◆ pagersubject

char* pagersubject
static

Definition at line 1206 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and sendpage().

◆ passwordlocation

int passwordlocation
static

Definition at line 1122 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ playmsg_app

char* playmsg_app = "VoiceMailPlayMsg"
static

Definition at line 1098 of file app_voicemail_odbc.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_odbc.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_odbc.c.

Referenced by actual_load_config(), and mb_poll_thread().

◆ poll_lock

ast_mutex_t poll_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 1134 of file app_voicemail_odbc.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_odbc.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_odbc.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_odbc.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_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ sayname_app

char* sayname_app = "VMSayName"
static

Definition at line 1100 of file app_voicemail_odbc.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

Definition at line 1119 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and wait_file().

◆ smdi_iface

struct ast_smdi_interface* smdi_iface = NULL
static

Definition at line 1113 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and run_externnotify().

◆ users

struct users users = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ 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_odbc.c.

Referenced by vm_exec(), and vm_execmain().

◆ vm_greeter_table

const struct ast_vm_greeter_functions vm_greeter_table
static

Definition at line 16141 of file app_voicemail_odbc.c.

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 13677 of file app_voicemail_odbc.c.

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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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_odbc.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 16123 of file app_voicemail_odbc.c.

Referenced by load_module(), and unload_module().

◆ vmauthenticate_app

char* vmauthenticate_app = "VMAuthenticate"
static

Definition at line 1096 of file app_voicemail_odbc.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_odbc.c.

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

◆ vmminsecs

int vmminsecs
static

Definition at line 1116 of file app_voicemail_odbc.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_odbc.c.

Referenced by load_module(), and unload_module().

◆ voicemailmain_app

char* voicemailmain_app = "VoiceMailMain"
static

Definition at line 1094 of file app_voicemail_odbc.c.

Referenced by load_module(), and unload_module().

◆ volgain

double volgain
static

Definition at line 1115 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().

◆ zones

struct zones zones = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ zonetag

char zonetag[80]
static

Definition at line 1104 of file app_voicemail_odbc.c.

Referenced by actual_load_config(), and populate_defaults().