Fix SendDTMF crash and channel reference leak using channel name parameter.
authorRichard Mudgett <rmudgett@digium.com>
Thu, 27 Sep 2012 22:25:34 +0000 (22:25 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Thu, 27 Sep 2012 22:25:34 +0000 (22:25 +0000)
The SendDTMF channel name parameter has two issues.
1) Crashes if the channel name does not exist.
2) Leaks a channel reference if the channel is the current channel.
Problem introduced by ASTERISK-15956.

* Updated SendDTMF documentation.

* Renamed app to senddtmf_name and tweaked the type.
........

Merged revisions 373945 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 373946 from http://svn.asterisk.org/svn/asterisk/branches/10
........

Merged revisions 373954 from http://svn.asterisk.org/svn/asterisk/branches/11

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@373965 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_senddtmf.c

index 5c8425a..e1e8ee9 100644 (file)
  * \brief App to send DTMF digits
  *
  * \author Mark Spencer <markster@digium.com>
- * 
+ *
  * \ingroup applications
  */
 
 /*** MODULEINFO
        <support_level>core</support_level>
  ***/
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -46,7 +46,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </synopsis>
                <syntax>
                        <parameter name="digits" required="true">
-                               <para>List of digits 0-9,*#,abcd</para>
+                               <para>List of digits 0-9,*#,a-d,A-D to send also w for a half second pause,
+                               and f or F for a flash-hook if the channel supports
+                               flash-hook.</para>
                        </parameter>
                        <parameter name="timeout_ms" required="false">
                                <para>Amount of time to wait in ms between tones. (defaults to .25s)</para>
@@ -54,13 +56,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <parameter name="duration_ms" required="false">
                                <para>Duration of each digit</para>
                        </parameter>
-                        <parameter name="channel" required="false">
-                                <para>Channel where digits will be played</para>
-                        </parameter>
+                       <parameter name="channel" required="false">
+                               <para>Channel where digits will be played</para>
+                       </parameter>
                </syntax>
                <description>
-                       <para>DTMF digits sent to a channel with half second pause</para>
-                       <para>It will pass all digits or terminate if it encounters an error.</para>
+                       <para>It will send all digits or terminate if it encounters an error.</para>
                </description>
                <see-also>
                        <ref type="application">Read</ref>
@@ -84,14 +85,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
        </manager>
  ***/
-static char *app = "SendDTMF";
+
+static const char senddtmf_name[] = "SendDTMF";
 
 static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
 {
-       int res = 0;
+       int res;
        char *data;
        int dinterval = 0, duration = 0;
-       struct ast_channel *dchan;
+       struct ast_channel *chan_found = NULL;
+       struct ast_channel *chan_dest = chan;
+       struct ast_channel *chan_autoservice = NULL;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(digits);
                AST_APP_ARG(dinterval);
@@ -100,15 +104,17 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
        );
 
        if (ast_strlen_zero(vdata)) {
-               ast_log(LOG_WARNING, "SendDTMF requires an argument (digits or *#aAbBcCdD)\n");
+               ast_log(LOG_WARNING, "SendDTMF requires an argument\n");
                return 0;
        }
 
-       dchan = chan;
-
        data = ast_strdupa(vdata);
        AST_STANDARD_APP_ARGS(args, data);
 
+       if (ast_strlen_zero(args.digits)) {
+               ast_log(LOG_WARNING, "The digits argument is required (0-9,*#,a-d,A-D,wfF)\n");
+               return 0;
+       }
        if (!ast_strlen_zero(args.dinterval)) {
                ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
        }
@@ -116,18 +122,23 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
                ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
        }
        if (!ast_strlen_zero(args.channel)) {
-               dchan = ast_channel_get_by_name(args.channel);
-       }
-       if (dchan != chan) {
-               ast_autoservice_start(chan);
+               chan_found = ast_channel_get_by_name(args.channel);
+               if (!chan_found) {
+                       ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
+                       return 0;
+               }
+               chan_dest = chan_found;
+               if (chan_found != chan) {
+                       chan_autoservice = chan;
+               }
        }
-       res = ast_dtmf_stream(dchan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration);
-       if (dchan != chan) {
-               ast_autoservice_stop(chan);
-               ast_channel_unref(dchan);
+       res = ast_dtmf_stream(chan_dest, chan_autoservice, args.digits,
+               dinterval <= 0 ? 250 : dinterval, duration);
+       if (chan_found) {
+               ast_channel_unref(chan_found);
        }
 
-       return res;
+       return chan_autoservice ? 0 : res;
 }
 
 static int manager_play_dtmf(struct mansession *s, const struct message *m)
@@ -160,10 +171,10 @@ static int unload_module(void)
 {
        int res;
 
-       res = ast_unregister_application(app);
+       res = ast_unregister_application(senddtmf_name);
        res |= ast_manager_unregister("PlayDTMF");
 
-       return res;     
+       return res;
 }
 
 static int load_module(void)
@@ -171,7 +182,7 @@ static int load_module(void)
        int res;
 
        res = ast_manager_register_xml("PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf);
-       res |= ast_register_application_xml(app, senddtmf_exec);
+       res |= ast_register_application_xml(senddtmf_name, senddtmf_exec);
 
        return res;
 }