Sat Apr 26 2014 22:01:27

Asterisk developer's documentation


app_parkandannounce.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Author: Ben Miller <bgmiller@dccinc.com>
00009  *    With TONS of help from Mark!
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief ParkAndAnnounce application for Asterisk
00025  *
00026  * \author Ben Miller <bgmiller@dccinc.com>
00027  * \arg With TONS of help from Mark!
00028  *
00029  * \ingroup applications
00030  */
00031 
00032 /*** MODULEINFO
00033    <support_level>core</support_level>
00034  ***/
00035 
00036 #include "asterisk.h"
00037 
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 381917 $")
00039 
00040 #include "asterisk/file.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/features.h"
00045 #include "asterisk/say.h"
00046 #include "asterisk/lock.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/app.h"
00049 
00050 /*** DOCUMENTATION
00051    <application name="ParkAndAnnounce" language="en_US">
00052       <synopsis>
00053          Park and Announce.
00054       </synopsis>
00055       <syntax>
00056          <parameter name="announce_template" required="true" argsep=":">
00057             <argument name="announce" required="true">
00058                <para>Colon-separated list of files to announce. The word
00059                <literal>PARKED</literal> will be replaced by a say_digits of the extension in which
00060                the call is parked.</para>
00061             </argument>
00062             <argument name="announce1" multiple="true" />
00063          </parameter>
00064          <parameter name="timeout" required="true">
00065             <para>Time in seconds before the call returns into the return
00066             context.</para>
00067          </parameter>
00068          <parameter name="dial" required="true">
00069             <para>The app_dial style resource to call to make the
00070             announcement. Console/dsp calls the console.</para>
00071          </parameter>
00072          <parameter name="return_context">
00073             <para>The goto-style label to jump the call back into after
00074             timeout. Default <literal>priority+1</literal>.</para>
00075          </parameter>
00076       </syntax>
00077       <description>
00078          <para>Park a call into the parkinglot and announce the call to another channel.</para>
00079          <para>The variable <variable>PARKEDAT</variable> will contain the parking extension
00080          into which the call was placed.  Use with the Local channel to allow the dialplan to make
00081          use of this information.</para>
00082       </description>
00083       <see-also>
00084          <ref type="application">Park</ref>
00085          <ref type="application">ParkedCall</ref>
00086       </see-also>
00087    </application>
00088  ***/
00089 
00090 static char *app = "ParkAndAnnounce";
00091 
00092 static int parkandannounce_exec(struct ast_channel *chan, const char *data)
00093 {
00094    int res = -1;
00095    int lot, timeout = 0, dres;
00096    char *dialtech, *tmp[100], buf[13];
00097    int looptemp, i;
00098    char *s;
00099    struct ast_party_id caller_id;
00100 
00101    struct ast_channel *dchan;
00102    struct outgoing_helper oh = { 0, };
00103    int outstate;
00104    struct ast_format tmpfmt;
00105    struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
00106 
00107    AST_DECLARE_APP_ARGS(args,
00108       AST_APP_ARG(template);
00109       AST_APP_ARG(timeout);
00110       AST_APP_ARG(dial);
00111       AST_APP_ARG(return_context);
00112    );
00113    if (ast_strlen_zero(data)) {
00114       ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce_template,timeout,dial,[return_context])\n");
00115       res = -1;
00116       goto parkcleanup;
00117    }
00118    if (!cap_slin) {
00119       res = -1;
00120       goto parkcleanup;
00121    }
00122    ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
00123 
00124    s = ast_strdupa(data);
00125    AST_STANDARD_APP_ARGS(args, s);
00126 
00127    if (args.timeout)
00128       timeout = atoi(args.timeout) * 1000;
00129 
00130    if (ast_strlen_zero(args.dial)) {
00131       ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or DAHDI/g1/5551212\n");
00132       res = -1;
00133       goto parkcleanup;
00134    }
00135 
00136    dialtech = strsep(&args.dial, "/");
00137    ast_verb(3, "Dial Tech,String: (%s,%s)\n", dialtech, args.dial);
00138 
00139    if (!ast_strlen_zero(args.return_context)) {
00140       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
00141       ast_parseable_goto(chan, args.return_context);
00142    } else {
00143       ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
00144    }
00145 
00146    ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", ast_channel_context(chan), ast_channel_exten(chan),
00147       ast_channel_priority(chan),
00148       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
00149    if (!ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
00150       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
00151       ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
00152    }
00153 
00154    /* Save the CallerID because the masquerade turns chan into a ZOMBIE. */
00155    ast_party_id_init(&caller_id);
00156    ast_channel_lock(chan);
00157    ast_party_id_copy(&caller_id, &ast_channel_caller(chan)->id);
00158    ast_channel_unlock(chan);
00159 
00160    /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
00161    before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
00162 
00163    res = ast_masq_park_call(chan, NULL, timeout, &lot);
00164    if (res) {
00165       /* Parking failed. */
00166       ast_party_id_free(&caller_id);
00167       res = -1;
00168       goto parkcleanup;
00169    }
00170 
00171    ast_verb(3, "Call parked in space: %d, timeout: %d, return-context: %s\n",
00172       lot, timeout, args.return_context ? args.return_context : "");
00173 
00174    /* Now place the call to the extension */
00175 
00176    snprintf(buf, sizeof(buf), "%d", lot);
00177    oh.parent_channel = chan;
00178    oh.vars = ast_variable_new("_PARKEDAT", buf, "");
00179    dchan = __ast_request_and_dial(dialtech, cap_slin, chan, args.dial, 30000,
00180       &outstate,
00181       S_COR(caller_id.number.valid, caller_id.number.str, NULL),
00182       S_COR(caller_id.name.valid, caller_id.name.str, NULL),
00183       &oh);
00184    ast_variables_destroy(oh.vars);
00185    ast_party_id_free(&caller_id);
00186    if (dchan) {
00187       if (ast_channel_state(dchan) == AST_STATE_UP) {
00188          ast_verb(4, "Channel %s was answered.\n", ast_channel_name(dchan));
00189       } else {
00190          ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(dchan));
00191          ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", ast_channel_name(dchan));
00192          ast_hangup(dchan);
00193          res = -1;
00194          goto parkcleanup;
00195       }
00196    } else {
00197       ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
00198       res = -1;
00199       goto parkcleanup;
00200    }
00201 
00202    ast_stopstream(dchan);
00203 
00204    /* now we have the call placed and are ready to play stuff to it */
00205 
00206    ast_verb(4, "Announce Template:%s\n", args.template);
00207 
00208    for (looptemp = 0; looptemp < ARRAY_LEN(tmp); looptemp++) {
00209       if ((tmp[looptemp] = strsep(&args.template, ":")) != NULL)
00210          continue;
00211       else
00212          break;
00213    }
00214 
00215    for (i = 0; i < looptemp; i++) {
00216       ast_verb(4, "Announce:%s\n", tmp[i]);
00217       if (!strcmp(tmp[i], "PARKED")) {
00218          ast_say_digits(dchan, lot, "", ast_channel_language(dchan));
00219       } else {
00220          dres = ast_streamfile(dchan, tmp[i], ast_channel_language(dchan));
00221          if (!dres) {
00222             dres = ast_waitstream(dchan, "");
00223          } else {
00224             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], ast_channel_name(dchan));
00225          }
00226       }
00227    }
00228 
00229    ast_stopstream(dchan);  
00230    ast_hangup(dchan);
00231 
00232 parkcleanup:
00233    cap_slin = ast_format_cap_destroy(cap_slin);
00234 
00235    return res;
00236 }
00237 
00238 static int unload_module(void)
00239 {
00240    return ast_unregister_application(app);
00241 }
00242 
00243 static int load_module(void)
00244 {
00245    /* return ast_register_application(app, park_exec); */
00246    return ast_register_application_xml(app, parkandannounce_exec);
00247 }
00248 
00249 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");