Merge "astobj2: Create function to copy weak proxied objects from container."
[asterisk/asterisk.git] / apps / app_privacy.c
index f5b7281..86aec01 100644 (file)
  * \brief Block all calls without Caller*ID, require phone # to be entered
  *
  * \author Mark Spencer <markster@digium.com>
- * 
+ *
  * \ingroup applications
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
 #include "asterisk/utils.h"
-#include "asterisk/logger.h"
-#include "asterisk/options.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
-#include "asterisk/image.h"
 #include "asterisk/callerid.h"
 #include "asterisk/app.h"
 #include "asterisk/config.h"
 
-#define PRIV_CONFIG "privacy.conf"
+/*** DOCUMENTATION
+       <application name="PrivacyManager" language="en_US">
+               <synopsis>
+                       Require phone number to be entered, if no CallerID sent
+               </synopsis>
+               <syntax>
+                       <parameter name="maxretries">
+                               <para>Total tries caller is allowed to input a callerid. Defaults to <literal>3</literal>.</para>
+                       </parameter>
+                       <parameter name="minlength">
+                               <para>Minimum allowable digits in the input callerid number. Defaults to <literal>10</literal>.</para>
+                       </parameter>
+                       <parameter name="options">
+                               <para>Position reserved for options.</para>
+                       </parameter>
+                       <parameter name="context">
+                               <para>Context to check the given callerid against patterns.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>If no Caller*ID is sent, PrivacyManager answers the channel and asks
+                       the caller to enter their phone number. The caller is given
+                       <replaceable>maxretries</replaceable> attempts to do so. The application does
+                       <emphasis>nothing</emphasis> if Caller*ID was received on the channel.</para>
+                       <para>The application sets the following channel variable upon completion:</para>
+                       <variablelist>
+                               <variable name="PRIVACYMGRSTATUS">
+                                       <para>The status of the privacy manager's attempt to collect a phone number from the user.</para>
+                                       <value name="SUCCESS"/>
+                                       <value name="FAILED"/>
+                               </variable>
+                       </variablelist>
+               </description>
+               <see-also>
+                       <ref type="application">Zapateller</ref>
+               </see-also>
+       </application>
+ ***/
 
-static char *tdesc = "Require phone number to be entered, if no CallerID sent";
 
 static char *app = "PrivacyManager";
 
-static char *synopsis = "Require phone number to be entered, if no CallerID sent";
-
-static char *descrip =
-  "  PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
-  "is sent, PrivacyManager answers the channel and asks the caller to\n"
-  "enter their phone number. The caller is given 3 attempts to do so.\n"
-  "The application does nothing if Caller*ID was received on the channel.\n"
-  "  Configuration file privacy.conf contains two variables:\n"
-  "   maxretries  default 3  -maximum number of attempts the caller is allowed \n"
-  "               to input a callerid.\n"
-  "   minlength   default 10 -minimum allowable digits in the input callerid number.\n"
-  "If you don't want to use the config file and have an i/o operation with\n"
-  "every call, you can also specify maxretries and minlength as application\n"
-  "parameters. Doing so supercedes any values set in privacy.conf.\n"
-  "The option string may contain the following character: \n"
-  "  'j' -- jump to n+101 priority after <maxretries> failed attempts to collect\n"
-  "         the minlength number of digits.\n"
-  "The application sets the following channel variable upon completion: \n"
-  "PRIVACYMGRSTATUS  The status of the privacy manager's attempt to collect \n"
-  "                  a phone number from the user. A text string that is either:\n" 
-  "          SUCCESS | FAILED \n"
-;
-
-STANDARD_LOCAL_USER;
-
-LOCAL_USER_DECL;
-
-
-
-static int privacy_exec (struct ast_channel *chan, void *data)
+static int privacy_exec(struct ast_channel *chan, const char *data)
 {
        int res=0;
        int retries;
        int maxretries = 3;
        int minlength = 10;
        int x = 0;
-       char *s;
        char phone[30];
-       struct localuser *u;
-       struct ast_config *cfg = NULL;
        char *parse = NULL;
-       int priority_jump = 0;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(maxretries);
                AST_APP_ARG(minlength);
                AST_APP_ARG(options);
+               AST_APP_ARG(checkcontext);
        );
 
-       LOCAL_USER_ADD (u);
-       if (!ast_strlen_zero(chan->cid.cid_num)) {
-               if (option_verbose > 2)
-                       ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
+       if (ast_channel_caller(chan)->id.number.valid
+               && !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
+               ast_verb(3, "CallerID number present: Skipping\n");
        } else {
                /*Answer the channel if it is not already*/
-               if (chan->_state != AST_STATE_UP) {
-                       res = ast_answer(chan);
-                       if (res) {
-                               LOCAL_USER_REMOVE(u);
+               if (ast_channel_state(chan) != AST_STATE_UP) {
+                       if ((res = ast_answer(chan))) {
                                return -1;
                        }
                }
 
-               if (!ast_strlen_zero((char *)data))
-               {
-                       parse = ast_strdupa(data);
-                       if (!parse) {
-                               ast_log(LOG_ERROR, "Out of memory!\n");
-                               LOCAL_USER_REMOVE(u);
-                               return -1;
-                       }
-                       
-                       AST_STANDARD_APP_ARGS(args, parse);
+               parse = ast_strdupa(data);
 
-                       if (args.maxretries) {
-                               if (sscanf(args.maxretries, "%d", &x) == 1)
-                                       maxretries = x;
-                               else
-                                       ast_log(LOG_WARNING, "Invalid max retries argument\n");
+               AST_STANDARD_APP_ARGS(args, parse);
+
+               if (!ast_strlen_zero(args.maxretries)) {
+                       if (sscanf(args.maxretries, "%30d", &x) == 1 && x > 0) {
+                               maxretries = x;
+                       } else {
+                               ast_log(LOG_WARNING, "Invalid max retries argument: '%s'\n", args.maxretries);
                        }
-                       if (args.minlength) {
-                               if (sscanf(args.minlength, "%d", &x) == 1)
-                                       minlength = x;
-                               else
-                                       ast_log(LOG_WARNING, "Invalid min length argument\n");
+               }
+               if (!ast_strlen_zero(args.minlength)) {
+                       if (sscanf(args.minlength, "%30d", &x) == 1 && x > 0) {
+                               minlength = x;
+                       } else {
+                               ast_log(LOG_WARNING, "Invalid min length argument: '%s'\n", args.minlength);
                        }
-                       if (args.options)
-                               if (strchr(args.options, 'j'))
-                                       priority_jump = 1;
-
-               }               
-
-               if (!x)
-               {
-                       /*Read in the config file*/
-                       cfg = ast_config_load(PRIV_CONFIG);
-               
-                       if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
-                               if (sscanf(s, "%d", &x) == 1) 
-                                       maxretries = x;
-                               else
-                                       ast_log(LOG_WARNING, "Invalid max retries argument\n");
-                       }
+               }
 
-                       if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
-                               if (sscanf(s, "%d", &x) == 1) 
-                                       minlength = x;
-                               else
-                                       ast_log(LOG_WARNING, "Invalid min length argument\n");
-                       }
-               }       
-               
-               /*Play unidentified call*/
+               /* Play unidentified call */
                res = ast_safe_sleep(chan, 1000);
-               if (!res)
-                       res = ast_streamfile(chan, "privacy-unident", chan->language);
-               if (!res)
+               if (!res) {
+                       res = ast_streamfile(chan, "privacy-unident", ast_channel_language(chan));
+               }
+               if (!res) {
                        res = ast_waitstream(chan, "");
+               }
 
-               /*Ask for 10 digit number, give 3 attempts*/
+               /* Ask for 10 digit number, give 3 attempts */
                for (retries = 0; retries < maxretries; retries++) {
-                       if (!res)
-                               res = ast_streamfile(chan, "privacy-prompt", chan->language);
-                       if (!res)
+                       if (!res) {
+                               res = ast_streamfile(chan, "privacy-prompt", ast_channel_language(chan));
+                       }
+                       if (!res) {
                                res = ast_waitstream(chan, "");
+                       }
 
-                       if (!res ) 
+                       if (!res) {
                                res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
+                       }
 
-                       if (res < 0)
+                       if (res < 0) {
                                break;
+                       }
 
-                       /*Make sure we get at least digits*/
-                       if (strlen(phone) >= minlength ) 
-                               break;
-                       else {
-                               res = ast_streamfile(chan, "privacy-incorrect", chan->language);
-                               if (!res)
+                       /* Make sure we get at least digits */
+                       if (strlen(phone) >= minlength ) {
+                               /* if we have a checkcontext argument, do pattern matching */
+                               if (!ast_strlen_zero(args.checkcontext)) {
+                                       if (!ast_exists_extension(NULL, args.checkcontext, phone, 1, NULL)) {
+                                               res = ast_streamfile(chan, "privacy-incorrect", ast_channel_language(chan));
+                                               if (!res) {
+                                                       res = ast_waitstream(chan, "");
+                                               }
+                                       } else {
+                                               break;
+                                       }
+                               } else {
+                                       break;
+                               }
+                       } else {
+                               res = ast_streamfile(chan, "privacy-incorrect", ast_channel_language(chan));
+                               if (!res) {
                                        res = ast_waitstream(chan, "");
+                               }
                        }
                }
-               
-               /*Got a number, play sounds and send them on their way*/
-               if ((retries < maxretries) && res == 1 ) {
-                       res = ast_streamfile(chan, "privacy-thankyou", chan->language);
-                       if (!res)
+
+               /* Got a number, play sounds and send them on their way */
+               if ((retries < maxretries) && res >= 0) {
+                       res = ast_streamfile(chan, "privacy-thankyou", ast_channel_language(chan));
+                       if (!res) {
                                res = ast_waitstream(chan, "");
-                       ast_set_callerid (chan, phone, "Privacy Manager", NULL);
-                       if (option_verbose > 2)
-                               ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",phone);
+                       }
+
+                       /*
+                        * This is a caller entered number that is going to be used locally.
+                        * Therefore, the given number presentation is allowed and should
+                        * be passed out to other channels.  This is the point of the
+                        * privacy application.
+                        */
+                       ast_channel_caller(chan)->id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+                       ast_channel_caller(chan)->id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+                       ast_channel_caller(chan)->id.number.plan = 0;/* Unknown */
+
+                       ast_set_callerid(chan, phone, "Privacy Manager", NULL);
+
+                       ast_verb(3, "Changed Caller*ID number to '%s'\n", phone);
+
                        pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
                } else {
-                       if (priority_jump || ast_opt_priority_jumping)  
-                               ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
                        pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
                }
-               if (cfg) 
-                       ast_config_destroy(cfg);
        }
 
-  LOCAL_USER_REMOVE (u);
-  return 0;
-}
-
-int
-unload_module (void)
-{
-       int res;
-
-       res = ast_unregister_application (app);
-
-       STANDARD_HANGUP_LOCALUSERS;
-
-       return res;
+       return 0;
 }
 
-int
-load_module (void)
+static int unload_module(void)
 {
-  return ast_register_application (app, privacy_exec, synopsis,
-                                  descrip);
+       return ast_unregister_application(app);
 }
 
-char *
-description (void)
+static int load_module(void)
 {
-  return tdesc;
+       return ast_register_application_xml(app, privacy_exec);
 }
 
-int
-usecount (void)
-{
-  int res;
-  STANDARD_USECOUNT (res);
-  return res;
-}
-
-char *
-key ()
-{
-  return ASTERISK_GPL_KEY;
-}
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");