Migrate a large number of AMI events over to Stasis-Core
[asterisk/asterisk.git] / apps / app_minivm.c
index 8b68294..ba6d6e5 100644 (file)
@@ -26,7 +26,6 @@
  * based on the Comedian Mail voicemail system (app_voicemail.c).
  * 
  * \par See also
- * \arg \ref Config_minivm
  * \arg \ref Config_minivm_examples
  * \arg \ref App_minivm
  *
  * Back: \ref App_minivm
  */
 
+/*** MODULEINFO
+       <support_level>extended</support_level>
+ ***/
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -163,14 +166,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/say.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
-#include "asterisk/manager.h"
 #include "asterisk/dsp.h"
 #include "asterisk/localtime.h"
 #include "asterisk/cli.h"
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/callerid.h"
-#include "asterisk/event.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/json.h"
 
 /*** DOCUMENTATION
 <application name="MinivmRecord" language="en_US">
@@ -400,6 +404,115 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                subscribed to the mailbox passed in the first parameter.</para>
        </description>
 </application>
+<function name="MINIVMCOUNTER" language="en_US">
+       <synopsis>
+               Reads or sets counters for MiniVoicemail message.
+       </synopsis>
+       <syntax argsep=":">
+               <parameter name="account" required="true">
+                       <para>If account is given and it exists, the counter is specific for the account.</para>
+                       <para>If account is a domain and the domain directory exists, counters are specific for a domain.</para>
+               </parameter>
+               <parameter name="name" required="true">
+                       <para>The name of the counter is a string, up to 10 characters.</para>
+               </parameter>
+               <parameter name="operand">
+                       <para>The counters never goes below zero. Valid operands for changing the value of a counter when assigning a value are:</para>
+                       <enumlist>
+                               <enum name="i"><para>Increment by value.</para></enum>
+                               <enum name="d"><para>Decrement by value.</para></enum>
+                               <enum name="s"><para>Set to value.</para></enum>
+                       </enumlist>
+               </parameter>
+       </syntax>
+       <description>
+               <para>The operation is atomic and the counter is locked while changing the value. The counters are stored as text files in the minivm account directories. It might be better to use realtime functions if you are using a database to operate your Asterisk.</para>
+       </description>
+       <see-also>
+               <ref type="application">MinivmRecord</ref>
+               <ref type="application">MinivmGreet</ref>
+               <ref type="application">MinivmNotify</ref>
+               <ref type="application">MinivmDelete</ref>
+               <ref type="application">MinivmAccMess</ref>
+               <ref type="application">MinivmMWI</ref>
+               <ref type="function">MINIVMACCOUNT</ref>
+       </see-also>
+</function>
+<function name="MINIVMACCOUNT" language="en_US">
+       <synopsis>
+               Gets MiniVoicemail account information.
+       </synopsis>
+       <syntax argsep=":">
+               <parameter name="account" required="true" />
+               <parameter name="item" required="true">
+                       <para>Valid items are:</para>
+                       <enumlist>
+                               <enum name="path">
+                                       <para>Path to account mailbox (if account exists, otherwise temporary mailbox).</para>
+                               </enum>
+                               <enum name="hasaccount">
+                                       <para>1 is static Minivm account exists, 0 otherwise.</para>
+                               </enum>
+                               <enum name="fullname">
+                                       <para>Full name of account owner.</para>
+                               </enum>
+                               <enum name="email">
+                                       <para>Email address used for account.</para>
+                               </enum>
+                               <enum name="etemplate">
+                                       <para>Email template for account (default template if none is configured).</para>
+                               </enum>
+                               <enum name="ptemplate">
+                                       <para>Pager template for account (default template if none is configured).</para>
+                               </enum>
+                               <enum name="accountcode">
+                                       <para>Account code for the voicemail account.</para>
+                               </enum>
+                               <enum name="pincode">
+                                       <para>Pin code for voicemail account.</para>
+                               </enum>
+                               <enum name="timezone">
+                                       <para>Time zone for voicemail account.</para>
+                               </enum>
+                               <enum name="language">
+                                       <para>Language for voicemail account.</para>
+                               </enum>
+                               <enum name="&lt;channel variable name&gt;">
+                                       <para>Channel variable value (set in configuration for account).</para>
+                               </enum>
+                       </enumlist>
+               </parameter>
+       </syntax>
+       <description>
+               <para />
+       </description>
+       <see-also>
+               <ref type="application">MinivmRecord</ref>
+               <ref type="application">MinivmGreet</ref>
+               <ref type="application">MinivmNotify</ref>
+               <ref type="application">MinivmDelete</ref>
+               <ref type="application">MinivmAccMess</ref>
+               <ref type="application">MinivmMWI</ref>
+               <ref type="function">MINIVMCOUNTER</ref>
+       </see-also>
+</function>
+       <managerEvent language="en_US" name="MiniVoiceMail">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a notification is sent out by a MiniVoiceMail application</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <parameter name="Action">
+                                       <para>What action was taken. Currently, this will always be <literal>SentNotification</literal></para>
+                               </parameter>
+                               <parameter name="Mailbox">
+                                       <para>The mailbox that the notification was about, specified as <literal>mailbox</literal>@<literal>context</literal></para>
+                               </parameter>
+                               <parameter name="Counter">
+                                       <para>A message counter derived from the <literal>MVM_COUNTER</literal> channel variable.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
 ***/
 
 #ifndef TRUE
@@ -455,19 +568,19 @@ static char *app_minivm_mwi = "MinivmMWI";
 
 
 
-enum {
+enum minivm_option_flags {
        OPT_SILENT =       (1 << 0),
        OPT_BUSY_GREETING =    (1 << 1),
        OPT_UNAVAIL_GREETING = (1 << 2),
        OPT_TEMP_GREETING = (1 << 3),
        OPT_NAME_GREETING = (1 << 4),
        OPT_RECORDGAIN =  (1 << 5),
-} minivm_option_flags;
+};
 
-enum {
+enum minivm_option_args {
        OPT_ARG_RECORDGAIN = 0,
        OPT_ARG_ARRAY_SIZE = 1,
-} minivm_option_args;
+};
 
 AST_APP_OPTIONS(minivm_app_options, {
        AST_APP_OPTION('s', OPT_SILENT),
@@ -577,7 +690,7 @@ static struct minivm_stats global_stats;
 AST_MUTEX_DEFINE_STATIC(minivmlock);   /*!< Lock to protect voicemail system */
 AST_MUTEX_DEFINE_STATIC(minivmloglock);        /*!< Lock to protect voicemail system log file */
 
-FILE *minivmlogfile;                   /*!< The minivm log file */
+static FILE *minivmlogfile;            /*!< The minivm log file */
 
 static int global_vmminmessage;                /*!< Minimum duration of messages */
 static int global_vmmaxmessage;                /*!< Maximum duration of message */
@@ -1062,7 +1175,6 @@ static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, con
 {
        struct ast_str *tmp = ast_str_alloca(80);
        int first_section = 1;
-       *end = '\0';
 
        ast_str_reset(*end);
        ast_str_set(&tmp, -1, "=?%s?Q?", charset);
@@ -1132,11 +1244,12 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
        char dur[PATH_MAX];
        char tmp[80] = "/tmp/astmail-XXXXXX";
        char tmp2[PATH_MAX];
+       char newtmp[PATH_MAX]; /* Only used with volgain */
        struct timeval now;
        struct ast_tm tm;
        struct minivm_zone *the_zone = NULL;
        struct ast_channel *ast;
-       char *finalfilename;
+       char *finalfilename = "";
        struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
        char *fromaddress;
        char *fromemail;
@@ -1158,6 +1271,8 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
 
        if (ast_strlen_zero(email)) {
                ast_log(LOG_WARNING, "No address to send message to.\n");
+               ast_free(str1);
+               ast_free(str2);
                return -1;      
        }
 
@@ -1169,15 +1284,21 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
 
        /* If we have a gain option, process it now with sox */
        if (type == MVM_MESSAGE_EMAIL && (vmu->volgain < -.001 || vmu->volgain > .001) ) {
-               char newtmp[PATH_MAX];
                char tmpcmd[PATH_MAX];
                int tmpfd;
 
                ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
                ast_debug(3, "newtmp: %s\n", newtmp);
                tmpfd = mkstemp(newtmp);
+               if (tmpfd < 0) {
+                       ast_log(LOG_WARNING, "Failed to create temporary file for volgain: %d\n", errno);
+                       ast_free(str1);
+                       ast_free(str2);
+                       return -1;
+               }
                snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
                ast_safe_system(tmpcmd);
+               close(tmpfd);
                finalfilename = newtmp;
                ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
        } else {
@@ -1203,11 +1324,17 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
        }
        if (!p) {
                ast_log(LOG_WARNING, "Unable to open temporary file '%s'\n", tmp);
+               ast_free(str1);
+               ast_free(str2);
                return -1;
        }
        /* Allocate channel used for chanvar substitution */
-       ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
-
+       ast = ast_dummy_channel_alloc();
+       if (!ast) {
+               ast_free(str1);
+               ast_free(str2);
+               return -1;
+       }
 
        snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
 
@@ -1368,9 +1495,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
        ast_safe_system(tmp2);
        ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : "");
        ast_debug(3, "Actual command used: %s\n", tmp2);
-       if (ast) {
-               ast = ast_channel_release(ast);
-       }
+       ast = ast_channel_unref(ast);
        ast_free(str1);
        ast_free(str2);
        return 0;
@@ -1437,7 +1562,7 @@ static int invent_message(struct ast_channel *chan, char *domain, char *username
        snprintf(fn, sizeof(fn), "%s%s/%s/greet", MVM_SPOOL_DIR, domain, username);
 
        if (ast_fileexists(fn, NULL, NULL) > 0) {
-               res = ast_streamfile(chan, fn, chan->language);
+               res = ast_streamfile(chan, fn, ast_channel_language(chan));
                if (res) 
                        return -1;
                res = ast_waitstream(chan, ecodes);
@@ -1459,23 +1584,23 @@ static int invent_message(struct ast_channel *chan, char *domain, char *username
                }
 
                if (numericusername) {
-                       if (ast_streamfile(chan, "vm-theperson", chan->language))
+                       if (ast_streamfile(chan, "vm-theperson", ast_channel_language(chan)))
                                return -1;
                        if ((res = ast_waitstream(chan, ecodes)))
                                return res;
 
-                       res = ast_say_digit_str(chan, username, ecodes, chan->language);
+                       res = ast_say_digit_str(chan, username, ecodes, ast_channel_language(chan));
                        if (res)
                                return res;
                } else {
-                       if (ast_streamfile(chan, "vm-theextensionis", chan->language))
+                       if (ast_streamfile(chan, "vm-theextensionis", ast_channel_language(chan)))
                                return -1;
                        if ((res = ast_waitstream(chan, ecodes)))
                                return res;
                }
        }
 
-       res = ast_streamfile(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language);
+       res = ast_streamfile(chan, busy ? "vm-isonphone" : "vm-isunavail", ast_channel_language(chan));
        if (res)
                return -1;
        res = ast_waitstream(chan, ecodes);
@@ -1499,7 +1624,7 @@ static int vm_delete(char *file)
 /*!\internal
  * \brief Record voicemail message & let caller review or re-record it, or set options if applicable */
 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
-                             int outsidecaller, struct minivm_account *vmu, int *duration, const char *unlockdir,
+                             int outsidecaller, struct minivm_account *vmu, int *duration, int *sound_duration, const char *unlockdir,
                              signed char record_gain)
 {
        int cmd = 0;
@@ -1531,7 +1656,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                case '2':
                        /* Review */
                        ast_verb(3, "Reviewing the message\n");
-                       ast_streamfile(chan, recordfile, chan->language);
+                       ast_streamfile(chan, recordfile, ast_channel_language(chan));
                        cmd = ast_waitstream(chan, AST_DIGIT_ANY);
                        break;
                case '3':
@@ -1549,7 +1674,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
                        if (ast_test_flag(vmu, MVM_OPERATOR))
                                canceldtmf = "0";
-                       cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
+                       cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
                        if (record_gain)
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
                        if (cmd == -1) /* User has hung up, no options to give */
@@ -1640,7 +1765,10 @@ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vm
        snprintf(arguments, sizeof(arguments), "%s %s@%s %s %s&", 
                ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify, 
                vmu->username, vmu->domain,
-               chan->cid.cid_name, chan->cid.cid_num);
+               (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str)
+                       ? ast_channel_caller(chan)->id.name.str : "",
+               (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str)
+                       ? ast_channel_caller(chan)->id.number.str : "");
 
        ast_debug(1, "Executing: %s\n", arguments);
        ast_safe_system(arguments);
@@ -1650,6 +1778,9 @@ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vm
  * \brief Send message to voicemail account owner */
 static int notify_new_message(struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
 {
+       RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
        char *stringp;
        struct minivm_template *etemplate;
        char *messageformat;
@@ -1715,8 +1846,26 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
                res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter);
        }
 
-       manager_event(EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter);
+       mwi_state = ast_mwi_create(vmu->username, vmu->domain);
+       if (!mwi_state) {
+               goto notify_cleanup;
+       }
+       mwi_state->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
 
+       json_object = ast_json_pack("{s: s, s: s}",
+                       "Event", "MiniVoiceMail"
+                       "Action", "SentNotification",
+                       "Counter", counter);
+       if (!json_object) {
+               goto notify_cleanup;
+       }
+       message = ast_mwi_blob_create(mwi_state, ast_mwi_vm_app_type(), json_object);
+       if (!message) {
+               goto notify_cleanup;
+       }
+       stasis_publish(ast_mwi_topic(mwi_state->uniqueid), message);
+
+notify_cleanup:
        run_externnotify(chan, vmu);            /* Run external notification */
 
        if (etemplate->locale) {
@@ -1734,8 +1883,8 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
        char callerid[256];
        FILE *txt;
        int res = 0, txtdes;
-       int msgnum;
        int duration = 0;
+       int sound_duration = 0;
        char date[256];
        char tmpdir[PATH_MAX];
        char ext_context[256] = "";
@@ -1777,7 +1926,6 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
                pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
                return res;
        }
-       msgnum = 0;
 
        userdir = check_dirpath(tmpdir, sizeof(tmpdir), vmu->domain, username, "tmp");
 
@@ -1794,7 +1942,7 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
        txtdes = mkstemp(tmptxtfile);
        if (txtdes < 0) {
                ast_log(LOG_ERROR, "Unable to create message file %s: %s\n", tmptxtfile, strerror(errno));
-               res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
+               res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
                if (!res)
                        res = ast_waitstream(chan, "");
                pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
@@ -1803,7 +1951,7 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
 
        if (res >= 0) {
                /* Unless we're *really* silent, try to send the beep */
-               res = ast_streamfile(chan, "beep", chan->language);
+               res = ast_streamfile(chan, "beep", ast_channel_language(chan));
                if (!res)
                        res = ast_waitstream(chan, "");
        }
@@ -1812,7 +1960,7 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
        /* Store information */
        ast_debug(2, "Open file for metadata: %s\n", tmptxtfile);
 
-       res = play_record_review(chan, NULL, tmptxtfile, global_vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain);
+       res = play_record_review(chan, NULL, tmptxtfile, global_vmmaxmessage, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain);
 
        txt = fdopen(txtdes, "w+");
        if (!txt) {
@@ -1826,16 +1974,20 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
                ast_localtime(&now, &tm, NULL);
                ast_strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm);
 
+               ast_callerid_merge(callerid, sizeof(callerid),
+                       S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
+                       "Unknown");
                snprintf(logbuf, sizeof(logbuf),
                        /* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
                        "%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
                        username,
-                       chan->context,
-                       chan->macrocontext, 
-                       chan->exten,
-                       chan->priority,
-                       chan->name,
-                       ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
+                       ast_channel_context(chan),
+                       ast_channel_macrocontext(chan), 
+                       ast_channel_exten(chan),
+                       ast_channel_priority(chan),
+                       ast_channel_name(chan),
+                       callerid,
                        date, 
                        timebuf,
                        duration,
@@ -1849,8 +2001,8 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
                        ast_mutex_unlock(&minivmloglock);
                }
 
-               if (duration < global_vmminmessage) {
-                       ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, global_vmminmessage);
+               if (sound_duration < global_vmminmessage) {
+                       ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, global_vmminmessage);
                        fclose(txt);
                        ast_filedelete(tmptxtfile, NULL);
                        unlink(tmptxtfile);
@@ -1897,9 +2049,8 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
 
 /*!\internal
  * \brief Queue a message waiting event */
-static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int new, int old)
+static void queue_mwi_event(const char *channel_id, const char *mbx, const char *ctx, int urgent, int new, int old)
 {
-       struct ast_event *event;
        char *mailbox, *context;
 
        mailbox = ast_strdupa(mbx);
@@ -1908,16 +2059,7 @@ static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int ne
                context = "default";
        }
 
-       if (!(event = ast_event_new(AST_EVENT_MWI,
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-                       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-                       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
-                       AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
-                       AST_EVENT_IE_END))) {
-               return;
-       }
-
-       ast_event_queue_and_cache(event);
+       ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
 }
 
 /*!\internal
@@ -1936,10 +2078,6 @@ static int minivm_mwi_exec(struct ast_channel *chan, const char *data)
                return -1;
        }
        tmpptr = ast_strdupa((char *)data);
-       if (!tmpptr) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
-       }
        argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
        if (argc < 4) {
                ast_log(LOG_ERROR, "%d arguments passed to MiniVM_MWI, need 4.\n", argc);
@@ -1956,7 +2094,7 @@ static int minivm_mwi_exec(struct ast_channel *chan, const char *data)
                ast_log(LOG_ERROR, "Need mailbox@context as argument. Sorry. Argument 0 %s\n", argv[0]);
                return -1;
        }
-       queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
+       queue_mwi_event(ast_channel_uniqueid(chan), mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
 
        return res;
 }
@@ -1973,21 +2111,16 @@ static int minivm_notify_exec(struct ast_channel *chan, const char *data)
        char *domain;
        char *tmpptr;
        struct minivm_account *vmu;
-       char *username = argv[0];
+       char *username;
        const char *template = "";
        const char *filename;
        const char *format;
        const char *duration_string;
-
        if (ast_strlen_zero(data))  {
                ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
                return -1;
        }
        tmpptr = ast_strdupa((char *)data);
-       if (!tmpptr) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
-       }
        argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
 
        if (argc == 2 && !ast_strlen_zero(argv[1]))
@@ -2027,7 +2160,10 @@ static int minivm_notify_exec(struct ast_channel *chan, const char *data)
                        duration_string = ast_strdupa(duration_string);
                }
                ast_channel_unlock(chan);
-               res = notify_new_message(chan, template, vmu, filename, atoi(duration_string), format, chan->cid.cid_num, chan->cid.cid_name);
+               res = notify_new_message(chan, template, vmu, filename, atoi(duration_string),
+                       format,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
+                       S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL));
        }
 
        pbx_builtin_setvar_helper(chan, "MVM_NOTIFY_STATUS", res == 0 ? "SUCCESS" : "FAILED");
@@ -2057,7 +2193,7 @@ static int minivm_record_exec(struct ast_channel *chan, const char *data)
        memset(&leave_options, 0, sizeof(leave_options));
 
        /* Answer channel if it's not already answered */
-       if (chan->_state != AST_STATE_UP)
+       if (ast_channel_state(chan) != AST_STATE_UP)
                ast_answer(chan);
 
        if (ast_strlen_zero(data))  {
@@ -2065,10 +2201,6 @@ static int minivm_record_exec(struct ast_channel *chan, const char *data)
                return -1;
        }
        tmp = ast_strdupa((char *)data);
-       if (!tmp) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
-       }
        argc = ast_app_separate_args(tmp, ',', argv, ARRAY_LEN(argv));
        if (argc == 2) {
                if (ast_app_parse_options(minivm_app_options, &flags, opts, argv[1])) {
@@ -2078,7 +2210,7 @@ static int minivm_record_exec(struct ast_channel *chan, const char *data)
                if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
                        int gain;
 
-                       if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
+                       if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
                                ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
                                return -1;
                        } else 
@@ -2128,10 +2260,6 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
                return -1;
        }
        tmpptr = ast_strdupa((char *)data);
-       if (!tmpptr) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
-       }
        argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
 
        if (argc == 2) {
@@ -2159,7 +2287,7 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
        }
 
        /* Answer channel if it's not already answered */
-       if (chan->_state != AST_STATE_UP)
+       if (ast_channel_state(chan) != AST_STATE_UP)
                ast_answer(chan);
 
        /* Setup pre-file if appropriate */
@@ -2188,26 +2316,35 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
        /* Check current or macro-calling context for special extensions */
        if (ast_test_flag(vmu, MVM_OPERATOR)) {
                if (!ast_strlen_zero(vmu->exit)) {
-                       if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
+                       if (ast_exists_extension(chan, vmu->exit, "o", 1,
+                               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                                strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
                                ouseexten = 1;
                        }
-               } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
+               } else if (ast_exists_extension(chan, ast_channel_context(chan), "o", 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                        strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
                        ouseexten = 1;
                }
-               else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
+               else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
+                       && ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
+                               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                        strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
                        ousemacro = 1;
                }
        }
 
        if (!ast_strlen_zero(vmu->exit)) {
-               if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
+               if (ast_exists_extension(chan, vmu->exit, "a", 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                        strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
-       } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
+               }
+       } else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
+               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
-       else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
+       } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
+               && ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
                ausemacro = 1;
        }
@@ -2215,7 +2352,7 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
        res = 0;        /* Reset */
        /* Play the beginning intro if desired */
        if (!ast_strlen_zero(prefile)) {
-               if (ast_streamfile(chan, prefile, chan->language) > -1) 
+               if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1) 
                        res = ast_waitstream(chan, ecodes);
        } else {
                ast_debug(2, "%s doesn't exist, doing what we can\n", prefile);
@@ -2234,7 +2371,7 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
                res = 0;
        }
        if (!res && !ast_test_flag(&leave_options, OPT_SILENT)) {
-               res = ast_streamfile(chan, SOUND_INTRO, chan->language);
+               res = ast_streamfile(chan, SOUND_INTRO, ast_channel_language(chan));
                if (!res)
                        res = ast_waitstream(chan, ecodes);
                if (res == '#') {
@@ -2247,27 +2384,25 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
        /* Check for a '*' here in case the caller wants to escape from voicemail to something
           other than the operator -- an automated attendant or mailbox login for example */
        if (res == '*') {
-               chan->exten[0] = 'a';
-               chan->exten[1] = '\0';
+               ast_channel_exten_set(chan, "a");
                if (!ast_strlen_zero(vmu->exit)) {
-                       ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
-               } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
-                       ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
+                       ast_channel_context_set(chan, vmu->exit);
+               } else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
+                       ast_channel_context_set(chan, ast_channel_macrocontext(chan));
                }
-               chan->priority = 0;
+               ast_channel_priority_set(chan, 0);
                pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
                res = 0;
        } else if (res == '0') { /* Check for a '0' here */
                if(ouseexten || ousemacro) {
-                       chan->exten[0] = 'o';
-                       chan->exten[1] = '\0';
+                       ast_channel_exten_set(chan, "o");
                        if (!ast_strlen_zero(vmu->exit)) {
-                               ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
-                       } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
-                               ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
+                               ast_channel_context_set(chan, vmu->exit);
+                       } else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
+                               ast_channel_context_set(chan, ast_channel_macrocontext(chan));
                        }
                        ast_play_and_wait(chan, "transfer");
-                       chan->priority = 0;
+                       ast_channel_priority_set(chan, 0);
                        pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
                }
                res =  0;
@@ -2335,26 +2470,20 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
        char *domain;
        char *tmpptr = NULL;
        struct minivm_account *vmu;
-       char *username = argv[0];
+       char *username;
        struct ast_flags flags = { 0 };
        char *opts[OPT_ARG_ARRAY_SIZE];
        int error = FALSE;
        char *message = NULL;
        char *prompt = NULL;
        int duration;
-       int cmd;
 
        if (ast_strlen_zero(data))  {
                ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
                error = TRUE;
-       } else 
+       } else {
                tmpptr = ast_strdupa((char *)data);
-       if (!error) {
-               if (!tmpptr) {
-                       ast_log(LOG_ERROR, "Out of memory\n");
-                       error = TRUE;
-               } else
-                       argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
+               argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
        }
 
        if (argc <=1) {
@@ -2397,7 +2526,7 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
        }
 
        /* Answer channel if it's not already answered */
-       if (chan->_state != AST_STATE_UP)
+       if (ast_channel_state(chan) != AST_STATE_UP)
                ast_answer(chan);
        
        /* Here's where the action is */
@@ -2416,7 +2545,7 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
        }
        snprintf(filename,sizeof(filename), "%s%s/%s/%s", MVM_SPOOL_DIR, vmu->domain, vmu->username, message);
        /* Maybe we should check the result of play_record_review ? */
-       cmd = play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, FALSE);
+       play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, NULL, FALSE);
 
        ast_debug(1, "Recorded new %s message in %s (duration %d)\n", message, filename, duration);
 
@@ -2494,7 +2623,7 @@ static int create_vmaccount(char *name, struct ast_variable *var, int realtime)
                        char *varname = ast_strdupa(var->value);
                        struct ast_variable *tmpvar;
 
-                       if (varname && (varval = strchr(varname, '='))) {
+                       if ((varval = strchr(varname, '='))) {
                                *varval = '\0';
                                varval++;
                                if ((tmpvar = ast_variable_new(varname, varval, ""))) {
@@ -2505,7 +2634,7 @@ static int create_vmaccount(char *name, struct ast_variable *var, int realtime)
                } else if (!strcasecmp(var->name, "pager")) {
                        ast_copy_string(vmu->pager, var->value, sizeof(vmu->pager));
                } else if (!strcasecmp(var->name, "volgain")) {
-                       sscanf(var->value, "%lf", &vmu->volgain);
+                       sscanf(var->value, "%30lf", &vmu->volgain);
                } else {
                        ast_log(LOG_ERROR, "Unknown configuration option for minivm account %s : %s\n", name, var->name);
                }
@@ -2552,11 +2681,6 @@ static int timezone_add(const char *zonename, const char *config)
                return 0;
 
        msg_format = ast_strdupa(config);
-       if (msg_format == NULL) {
-               ast_log(LOG_WARNING, "Out of memory.\n");
-               ast_free(newzone);
-               return 0;
-       }
 
        timezone_str = strsep(&msg_format, "|");
        if (!msg_format) {
@@ -2675,7 +2799,7 @@ static int apply_general_options(struct ast_variable *var)
                        global_silencethreshold = atoi(var->value);
                } else if (!strcmp(var->name, "maxmessage")) {
                        int x;
-                       if (sscanf(var->value, "%d", &x) == 1) {
+                       if (sscanf(var->value, "%30d", &x) == 1) {
                                global_vmmaxmessage = x;
                        } else {
                                error ++;
@@ -2683,7 +2807,7 @@ static int apply_general_options(struct ast_variable *var)
                        }
                } else if (!strcmp(var->name, "minmessage")) {
                        int x;
-                       if (sscanf(var->value, "%d", &x) == 1) {
+                       if (sscanf(var->value, "%30d", &x) == 1) {
                                global_vmminmessage = x;
                                if (global_maxsilence <= global_vmminmessage)
                                        ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
@@ -3072,10 +3196,7 @@ static int minivm_account_func_read(struct ast_channel *chan, const char *cmd, c
        struct minivm_account *vmu;
        char *username, *domain, *colname;
 
-       if (!(username = ast_strdupa(data))) {
-               ast_log(LOG_ERROR, "Memory Error!\n");
-               return -1;
-       }
+       username = ast_strdupa(data);
 
        if ((colname = strchr(username, ':'))) {
                *colname = '\0';
@@ -3128,12 +3249,10 @@ static int minivm_account_func_read(struct ast_channel *chan, const char *cmd, c
                check_dirpath(buf, len, vmu->domain, vmu->username, NULL);
        } else {        /* Look in channel variables */
                struct ast_variable *var;
-               int found = 0;
 
                for (var = vmu->chanvars ; var ; var = var->next)
                        if (!strcmp(var->name, colname)) {
                                ast_copy_string(buf, var->value, len);
-                               found = 1;
                                break;
                        }
        }
@@ -3222,16 +3341,13 @@ static int access_counter_file(char *directory, char *countername, int value, in
 static int minivm_counter_func_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
        char *username, *domain, *countername;
-       struct minivm_account *vmu = NULL;
        char userpath[BUFSIZ];
        int res;
 
        *buf = '\0';
 
-       if (!(username = ast_strdupa(data))) {  /* Copy indata to local buffer */
-               ast_log(LOG_WARNING, "Memory error!\n");
-               return -1;
-       }
+       username = ast_strdupa(data);
+
        if ((countername = strchr(username, ':'))) {
                *countername = '\0';
                countername++;
@@ -3260,7 +3376,7 @@ static int minivm_counter_func_read(struct ast_channel *chan, const char *cmd, c
        }
 
        /* If we can't find account or if the account is temporary, return. */
-       if (!ast_strlen_zero(username) && !(vmu = find_account(domain, username, FALSE))) {
+       if (!ast_strlen_zero(username) && !find_account(domain, username, FALSE)) {
                ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
                return 0;
        }
@@ -3279,7 +3395,6 @@ static int minivm_counter_func_write(struct ast_channel *chan, const char *cmd,
 {
        char *username, *domain, *countername, *operand;
        char userpath[BUFSIZ];
-       struct minivm_account *vmu;
        int change = 0;
        int operation = 0;
 
@@ -3287,10 +3402,7 @@ static int minivm_counter_func_write(struct ast_channel *chan, const char *cmd,
                return -1;
        change = atoi(value);
 
-       if (!(username = ast_strdupa(data))) {  /* Copy indata to local buffer */
-               ast_log(LOG_WARNING, "Memory error!\n");
-               return -1;
-       }
+       username = ast_strdupa(data);
 
        if ((countername = strchr(username, ':'))) {
                *countername = '\0';
@@ -3324,7 +3436,7 @@ static int minivm_counter_func_write(struct ast_channel *chan, const char *cmd,
        }
 
        /* If we can't find account or if the account is temporary, return. */
-       if (!ast_strlen_zero(username) && !(vmu = find_account(domain, username, FALSE))) {
+       if (!ast_strlen_zero(username) && !find_account(domain, username, FALSE)) {
                ast_log(LOG_ERROR, "Minivm account does not exist: %s@%s\n", username, domain);
                return 0;
        }
@@ -3361,41 +3473,13 @@ static struct ast_cli_entry cli_minivm[] = {
 
 static struct ast_custom_function minivm_counter_function = {
        .name = "MINIVMCOUNTER",
-       .synopsis = "Reads or sets counters for MiniVoicemail message",
-       .syntax = "MINIVMCOUNTER(<account>:name[:operand])",
        .read = minivm_counter_func_read,
        .write = minivm_counter_func_write,
-       .desc = "Valid operands for changing the value of a counter when assigning a value are:\n"
-       "- i   Increment by value\n"
-       "- d   Decrement by value\n"
-       "- s   Set to value\n"
-       "\nThe counters never goes below zero.\n"
-       "- The name of the counter is a string, up to 10 characters\n"
-       "- If account is given and it exists, the counter is specific for the account\n"
-       "- If account is a domain and the domain directory exists, counters are specific for a domain\n"
-       "The operation is atomic and the counter is locked while changing the value\n"
-       "\nThe counters are stored as text files in the minivm account directories. It might be better to use\n"
-       "realtime functions if you are using a database to operate your Asterisk\n",
 };
 
 static struct ast_custom_function minivm_account_function = {
        .name = "MINIVMACCOUNT",
-       .synopsis = "Gets MiniVoicemail account information",
-       .syntax = "MINIVMACCOUNT(<account>:item)",
        .read = minivm_account_func_read,
-       .desc = "Valid items are:\n"
-       "- path           Path to account mailbox (if account exists, otherwise temporary mailbox)\n"
-       "- hasaccount     1 if static Minivm account exists, 0 otherwise\n"
-       "- fullname       Full name of account owner\n"
-       "- email          Email address used for account\n"
-       "- etemplate      E-mail template for account (default template if none is configured)\n"   
-       "- ptemplate      Pager template for account (default template if none is configured)\n"   
-       "- accountcode    Account code for voicemail account\n"
-       "- pincode        Pin code for voicemail account\n"
-       "- timezone       Time zone for voicemail account\n"
-       "- language       Language for voicemail account\n"
-       "- <channel variable name> Channel variable value (set in configuration for account)\n"
-       "\n",
 };
 
 /*! \brief Load mini voicemail module */