diff options
author | Mark Michelson <mmichelson@digium.com> | 2012-06-04 20:26:12 +0000 |
---|---|---|
committer | Mark Michelson <mmichelson@digium.com> | 2012-06-04 20:26:12 +0000 |
commit | 14a985560ed5830aa3e1b5880890a59a5d0f0c2f (patch) | |
tree | 4d6f57c4358566c5508d79e97560640ce59df5c8 /apps/app_mixmonitor.c | |
parent | c1bbe79748bb1615ab116fe287b8d5d28a83b330 (diff) |
Merge changes dealing with support for Digium phones.
Presence support has been added. This is accomplished by
allowing for presence hints in addition to device state
hints. A dialplan function called PRESENCE_STATE has been
added to allow for setting and reading presence. Presence
can be transmitted to Digium phones using custom XML
elements in a PIDF presence document.
Voicemail has new APIs that allow for moving, removing,
forwarding, and playing messages. Messages have had a new
unique message ID added to them so that the APIs will work
reliably. The state of a voicemail mailbox can be obtained
using an API that allows one to get a snapshot of the mailbox.
A voicemail Dialplan App called VoiceMailPlayMsg has been
added to be able to play back a specific message.
Configuration hooks have been added. Configuration hooks
allow for a piece of code to be executed when a specific
configuration file is loaded by a specific module. This is
useful for modules that are dependent on the configuration
of other modules.
chan_sip now has a public method that allows for a custom
SIP INFO request to be sent mid-dialog. Digium phones use
this in order to display progress bars when files are played.
Messaging support has been expanded a bit. The main
visible difference is the addition of an AMI action
MessageSend.
Finally, a ParkingLots manager action has been added in order
to get a list of parking lots.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps/app_mixmonitor.c')
-rw-r--r-- | apps/app_mixmonitor.c | 258 |
1 files changed, 243 insertions, 15 deletions
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index c1f5ada72..8eda3997f 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */ +#include "asterisk/stringfields.h" #include "asterisk/file.h" #include "asterisk/audiohook.h" #include "asterisk/pbx.h" @@ -51,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/autochan.h" #include "asterisk/manager.h" +#include "asterisk/callerid.h" #include "asterisk/mod_format.h" #include "asterisk/linkedlists.h" @@ -112,6 +114,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <argument name="chanvar" required="true" /> <para>Stores the MixMonitor's ID on this channel variable.</para> </option> + <option name="m"> + <argument name="mailbox" required="true" /> + <para>Create a copy of the recording as a voicemail in the indicated <emphasis>mailbox</emphasis>(es) + separated by commas eg. m(1111@default,2222@default,...). Folders can be optionally specified using + the syntax: mailbox@context/folder</para> + </option> </optionlist> </parameter> <parameter name="command"> @@ -238,6 +246,17 @@ static const char * const stop_app = "StopMixMonitor"; static const char * const mixmonitor_spy_type = "MixMonitor"; +/*! + * \internal + * \brief This struct is a list item holds data needed to find a vm_recipient within voicemail + */ +struct vm_recipient { + char mailbox[AST_MAX_CONTEXT]; + char context[AST_MAX_EXTENSION]; + char folder[80]; + AST_LIST_ENTRY(vm_recipient) list; +}; + struct mixmonitor { struct ast_audiohook audiohook; struct ast_callid *callid; @@ -249,6 +268,20 @@ struct mixmonitor { unsigned int flags; struct ast_autochan *autochan; struct mixmonitor_ds *mixmonitor_ds; + + /* the below string fields describe data used for creating voicemails from the recording */ + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(call_context); + AST_STRING_FIELD(call_macrocontext); + AST_STRING_FIELD(call_extension); + AST_STRING_FIELD(call_callerchan); + AST_STRING_FIELD(call_callerid); + ); + int call_priority; + + /* FUTURE DEVELOPMENT NOTICE + * recipient_list will need locks if we make it editable after the monitor is started */ + AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list; }; enum mixmonitor_flags { @@ -260,7 +293,8 @@ enum mixmonitor_flags { MUXFLAG_READ = (1 << 6), MUXFLAG_WRITE = (1 << 7), MUXFLAG_COMBINED = (1 << 8), - MUXFLAG_UID = (1 << 9), + MUXFLAG_UID = (1 << 9), + MUXFLAG_VMRECIPIENTS = (1 << 10), }; enum mixmonitor_args { @@ -269,7 +303,8 @@ enum mixmonitor_args { OPT_ARG_VOLUME, OPT_ARG_WRITENAME, OPT_ARG_READNAME, - OPT_ARG_UID, + OPT_ARG_UID, + OPT_ARG_VMRECIPIENTS, OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */ }; @@ -282,6 +317,7 @@ AST_APP_OPTIONS(mixmonitor_opts, { AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME), AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME), AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID), + AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS), }); struct mixmonitor_ds { @@ -382,6 +418,70 @@ static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) return res; } +/*! + * \internal + * \brief adds recipients to a mixmonitor's recipient list + * \param mixmonitor mixmonitor being affected + * \param vm_recipients string containing the desired recipients to add + */ +static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients) +{ + /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */ + char *cur_mailbox = ast_strdupa(vm_recipients); + char *cur_context; + char *cur_folder; + char *next; + int elements_processed = 0; + + while (!ast_strlen_zero(cur_mailbox)) { + ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox); + if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) { + *(next++) = '\0'; + } + + if ((cur_folder = strchr(cur_mailbox, '/'))) { + *(cur_folder++) = '\0'; + } else { + cur_folder = "INBOX"; + } + + if ((cur_context = strchr(cur_mailbox, '@'))) { + *(cur_context++) = '\0'; + } else { + cur_context = "default"; + } + + if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) { + struct vm_recipient *recipient; + if (!(recipient = ast_malloc(sizeof(*recipient)))) { + ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n"); + return; + } + ast_copy_string(recipient->context, cur_context, sizeof(recipient->context)); + ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox)); + ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder)); + + /* Add to list */ + ast_verb(5, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context); + AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list); + } else { + ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients); + } + + cur_mailbox = next; + elements_processed++; + } +} + +static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor) +{ + struct vm_recipient *current; + while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) { + /* Clear list element data */ + ast_free(current); + } +} + #define SAMPLES_PER_FRAME 160 static void mixmonitor_free(struct mixmonitor *mixmonitor) @@ -397,6 +497,12 @@ static void mixmonitor_free(struct mixmonitor *mixmonitor) ast_free(mixmonitor->post_process); } + /* Free everything in the recipient list */ + clear_mixmonitor_recipient_list(mixmonitor); + + /* clean stringfields */ + ast_string_field_free_memory(mixmonitor); + if (mixmonitor->callid) { ast_callid_unref(mixmonitor->callid); } @@ -404,10 +510,50 @@ static void mixmonitor_free(struct mixmonitor *mixmonitor) } } -static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag) +/*! + * \internal + * \brief Copies the mixmonitor to all voicemail recipients + * \param mixmonitor The mixmonitor that needs to forward its file to recipients + * \param ext Format of the file that was saved + */ +static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename) +{ + struct vm_recipient *recipient = NULL; + struct ast_vm_recording_data recording_data; + if (ast_string_field_init(&recording_data, 512)) { + ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n"); + return; + } + + /* Copy strings to stringfields that will be used for all recipients */ + ast_string_field_set(&recording_data, recording_file, filename); + ast_string_field_set(&recording_data, recording_ext, ext); + ast_string_field_set(&recording_data, call_context, mixmonitor->call_context); + ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext); + ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension); + ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan); + ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid); + /* and call_priority gets copied too */ + recording_data.call_priority = mixmonitor->call_priority; + + AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) { + /* context, mailbox, and folder need to be set per recipient */ + ast_string_field_set(&recording_data, context, recipient->context); + ast_string_field_set(&recording_data, mailbox, recipient->mailbox); + ast_string_field_set(&recording_data, folder, recipient->folder); + + ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox, + recording_data.context); + ast_app_copy_recording_to_vm(&recording_data); + } + + /* Free the string fields for recording_data before exiting the function. */ + ast_string_field_free_memory(&recording_data); +} + +static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext) { /* Initialize the file if not already done so */ - char *ext = NULL; char *last_slash = NULL; if (!ast_strlen_zero(filename)) { if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) { @@ -416,14 +562,19 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, last_slash = strrchr(filename, '/'); - if ((ext = strrchr(filename, '.')) && (ext > last_slash)) { - *(ext++) = '\0'; + ast_log(LOG_NOTICE, "!!!!!! File name is %s\n", filename); + + if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) { + ast_log(LOG_NOTICE, "Found a dot. *ext is %s\n", *ext); + **ext = '\0'; + *ext = *ext + 1; + ast_log(LOG_NOTICE, "After increment *ext is %s\n", *ext); } else { - ext = "raw"; + *ext = "raw"; } - if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) { - ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext); + if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) { + ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext); *errflag = 1; } else { struct ast_filestream *tmp = *fs; @@ -436,6 +587,9 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, static void *mixmonitor_thread(void *obj) { struct mixmonitor *mixmonitor = obj; + char *fs_ext = ""; + char *fs_read_ext = ""; + char *fs_write_ext = ""; struct ast_filestream **fs = NULL; struct ast_filestream **fs_read = NULL; @@ -457,9 +611,9 @@ static void *mixmonitor_thread(void *obj) fs_write = &mixmonitor->mixmonitor_ds->fs_write; ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); - mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag); - mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag); - mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag); + mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext); + mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext); + mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext); ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0); @@ -554,6 +708,27 @@ static void *mixmonitor_thread(void *obj) } ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); + + if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) { + if (ast_strlen_zero(fs_ext)) { + ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n", + mixmonitor -> name); + } else { + ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name); + copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename); + } + if (!ast_strlen_zero(fs_read_ext)) { + ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name); + copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read); + } + if (!ast_strlen_zero(fs_write_ext)) { + ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name); + copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write); + } + } else { + ast_debug(3, "No recipients to forward monitor to, moving on.\n"); + } + mixmonitor_free(mixmonitor); return NULL; } @@ -597,7 +772,8 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, - char *filename_read, const char *uid_channel_var) + char *filename_read, const char *uid_channel_var, + const char *recipients) { pthread_t thread; struct mixmonitor *mixmonitor; @@ -623,6 +799,12 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename return; } + /* Now that the struct has been calloced, go ahead and initialize the string fields. */ + if (ast_string_field_init(mixmonitor, 512)) { + mixmonitor_free(mixmonitor); + return; + } + /* Setup the actual spy before creating our thread */ if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) { mixmonitor_free(mixmonitor); @@ -650,7 +832,6 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename } ast_free(datastore_id); - mixmonitor->name = ast_strdup(ast_channel_name(chan)); if (!ast_strlen_zero(postprocess2)) { @@ -669,6 +850,35 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename mixmonitor->filename_read = ast_strdup(filename_read); } + if (!ast_strlen_zero(recipients)) { + char callerid[256]; + struct ast_party_connected_line *connected; + + ast_channel_lock(chan); + + /* We use the connected line of the invoking channel for caller ID. */ + + connected = ast_channel_connected(chan); + ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid, + connected->id.name.str, connected->id.number.valid, + connected->id.number.str); + ast_callerid_merge(callerid, sizeof(callerid), + S_COR(connected->id.name.valid, connected->id.name.str, NULL), + S_COR(connected->id.number.valid, connected->id.number.str, NULL), + "Unknown"); + + ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan)); + ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan)); + ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan)); + ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan)); + ast_string_field_set(mixmonitor, call_callerid, callerid); + mixmonitor->call_priority = ast_channel_priority(chan); + + ast_channel_unlock(chan); + + add_vm_recipients_from_string(mixmonitor, recipients); + } + ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); if (readvol) @@ -723,6 +933,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data) char *uid_channel_var = NULL; struct ast_flags flags = { 0 }; + char *recipients = NULL; char *parse; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(filename); @@ -774,6 +985,14 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data) } } + if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) { + if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) { + ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n"); + } else { + recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]); + } + } + if (ast_test_flag(&flags, MUXFLAG_WRITE)) { filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer))); } @@ -799,7 +1018,16 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data) } pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); - launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read, uid_channel_var); + launch_monitor_thread(chan, + args.filename, + flags.flags, + readvol, + writevol, + args.post_process, + filename_write, + filename_read, + uid_channel_var, + recipients); return 0; } |