add privacy/screening functionality to app_dial (bug #752)
authorKevin P. Fleming <kpfleming@digium.com>
Tue, 12 Jul 2005 03:23:31 +0000 (03:23 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Tue, 12 Jul 2005 03:23:31 +0000 (03:23 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6102 65c4cc65-6c06-0410-ace0-fbb531ad65f3

Makefile
apps/app_dial.c
configs/extensions.conf.sample
doc/README.privacy [new file with mode: 0755]
sounds.txt
sounds/priv-callee-options.gsm [new file with mode: 0755]
sounds/priv-callpending.gsm [new file with mode: 0755]
sounds/priv-introsaved.gsm [new file with mode: 0755]
sounds/priv-recordintro.gsm [new file with mode: 0755]
sounds/screen-callee-options.gsm [new file with mode: 0755]

index 78861f1..dc2edc9 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -462,6 +462,7 @@ clean:
 datafiles: all
        sh mkpkgconfig $(DESTDIR)/usr/lib/pkgconfig
        mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/digits
+       mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/priv-callerintros
        for x in sounds/digits/*.gsm; do \
                if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \
                        install -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds/digits ; \
index 07d07aa..b07f999 100755 (executable)
@@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/causes.h"
 #include "asterisk/manager.h"
+#include "asterisk/privacy.h"
 
 static char *tdesc = "Dialing Application";
 
@@ -63,6 +64,10 @@ static char *descrip =
 "n is the priority of the dialer instance), then it will be the next\n"
 "executed extension (this allows you to setup different behavior on busy from\n"
 "no-answer).\n"
+"  For the Privacy and Screening Modes, the DIALSTATUS variable will be set to DONTCALL, \n"
+"if the called party chooses to send the calling party to the 'Go Away' script, and \n"
+"the DIALSTATUS variable will be set to TORTURE, if the called party wants to send the caller to \n"
+"the TORTURE scripts\n"
 "  This application returns -1 if the originating channel hangs up, or if the\n"
 "call is bridged and either of the parties in the bridge terminate the call.\n"
 "The option string may contain zero or more of the following characters:\n"
@@ -92,7 +97,10 @@ static char *descrip =
 "      'h' -- allow callee to hang up by hitting *.\n"
 "      'H' -- allow caller to hang up by hitting *.\n"
 "      'C' -- reset call detail record for this call.\n"
-"      'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
+"      'P[(x)]' -- privacy mode, using 'x' as database if provided, or the extension is used if not provided.\n"
+"      'p' -- screening mode.  Basically Privacy mode without memory.\n"
+"       'n' -- modifier for screen/privacy mode. No intros are to be saved in the priv-callerintros dir.\n"
+"       'N' -- modifier for screen/privacy mode. if callerID is present, do not screen the call.\n"
 "      'g' -- goes on in context if the destination channel hangs up\n"
 "      'G(context^exten^pri)' -- If the call is answered transfer both parties to the specified exten.\n"
 "      'A(x)' -- play an announcement to the called party, using x as file\n"
@@ -112,7 +120,7 @@ static char *descrip =
 "             * LIMIT_WARNING_FILE        File to play as warning if 'y' is defined.\n"
 "                        'timeleft' is a special sound macro to auto-say the time \n"
 "                        left and is the default.\n"
-"       'n' -- Do not jump to n+101 if all of the channels were busy.\n\n"
+"       'j' -- Do not jump to n+101 if all of the channels were busy.\n\n"
 "  In addition to transferring the call, a call may be parked and then picked\n"
 "up by another user.\n"
 "  The optional URL will be sent to the called party if the channel supports it.\n"
@@ -122,7 +130,7 @@ static char *descrip =
 "      DIALEDTIME    Time from dial to answer\n" 
 "      ANSWEREDTIME  Time for actual call\n"
 "      DIALSTATUS    The status of the call as a text string, one of\n"
-"             CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
+"             CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL | DONTCALL | TORTURE\n"
 "";
 
 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
@@ -610,12 +618,17 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
        struct localuser *u;
        char *info, *peers, *timeout, *tech, *number, *rest, *cur;
        char  privdb[256] = "", *s;
+       char  privcid[256] = "";
+       char privintro[1024];
        char  announcemsg[256] = "", *ann;
        struct localuser *outgoing=NULL, *tmp;
        struct ast_channel *peer;
        int to;
        int hasmacro = 0;
        int privacy=0;
+       int screen=0;
+       int no_save_intros = 0;
+       int no_screen_callerid = 0;
        int announce=0;
        int resetcdr=0;
        int numbusy = 0;
@@ -629,6 +642,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
        char *newnum;
        char *l;
        char *url=NULL; /* JDG */
+       int privdb_val=0;
        unsigned int calldurationlimit=0;
        char *cdl;
        time_t now;
@@ -814,7 +828,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                                *(ann++) = 'X';
                        if (*ann)
                                *ann = 'X';
-                       /* Now find the end of the privdb */
+                       /* Now find the end of the announce */
                        ann = strchr(announcemsg, ')');
                        if (ann)
                                *ann = '\0';
@@ -906,11 +920,19 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                } else if (strchr(transfer, 'P')) {
                        /* No specified privdb */
                        privacy = 1;
+               } else if (strchr(transfer, 'p')) {
+                       screen = 1;
                } else if (strchr(transfer, 'C')) {
                        resetcdr = 1;
-               } else if (strchr(transfer, 'n')) {
+               } else if (strchr(transfer, 'j')) {
                        nojump = 1;
                }
+               if (strchr(transfer, 'n')) {
+                       no_save_intros = 1;
+               } 
+               if (strchr(transfer, 'N')) {
+                       no_screen_callerid = 1;
+               }
        }
        if (resetcdr && chan->cdr)
                ast_cdr_reset(chan->cdr, 0);
@@ -918,11 +940,97 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                /* If privdb is not specified and we are using privacy, copy from extension */
                ast_copy_string(privdb, chan->exten, sizeof(privdb));
        }
-       if (privacy) {
+       if (privacy || screen) {
+               char callerid[60];
+
                l = chan->cid.cid_num;
-               if (!l)
-                       l = "";
-               ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
+               if (l && !ast_strlen_zero(l)) {
+                       ast_shrink_phone_number(l);
+                       if( privacy ) {
+                               if (option_verbose > 2)
+                                       ast_verbose( VERBOSE_PREFIX_3  "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
+                               privdb_val = ast_privacy_check(privdb, l);
+                       }
+                       else {
+                               if (option_verbose > 2)
+                                       ast_verbose( VERBOSE_PREFIX_3  "Privacy Screening, clid is '%s'\n", l);
+                               privdb_val = AST_PRIVACY_UNKNOWN;
+                       }
+               } else {
+                       char *tnam, *tn2;
+
+                       tnam = ast_strdupa(chan->name);
+                       /* clean the channel name so slashes don't try to end up in disk file name */
+                       for(tn2 = tnam; *tn2; tn2++) {
+                               if( *tn2=='/')
+                                       *tn2 = '=';  /* any other chars to be afraid of? */
+                       }
+                       if (option_verbose > 2)
+                               ast_verbose( VERBOSE_PREFIX_3  "Privacy-- callerid is empty\n");
+
+                       snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
+                       l = callerid;
+                       privdb_val = AST_PRIVACY_UNKNOWN;
+               }
+               
+               ast_copy_string(privcid,l,sizeof(privcid));
+
+               if( strncmp(privcid,"NOCALLERID",10) != 0 && no_screen_callerid ) { /* if callerid is set, and no_screen_callerid is set also */  
+                       if (option_verbose > 2)
+                               ast_verbose( VERBOSE_PREFIX_3  "CallerID set (%s); N option set; Screening should be off\n", privcid);
+                       privdb_val = AST_PRIVACY_ALLOW;
+               }
+               else if( no_screen_callerid && strncmp(privcid,"NOCALLERID",10) == 0 ) {
+                       if (option_verbose > 2)
+                               ast_verbose( VERBOSE_PREFIX_3  "CallerID blank; N option set; Screening should happen; dbval is %d\n", privdb_val);
+               }
+               
+               if( privdb_val == AST_PRIVACY_DENY ) {
+                       ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
+                       res=0;
+                       goto out;
+               }
+               else if( privdb_val == AST_PRIVACY_KILL ) {
+                       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 201, chan->cid.cid_num)) 
+                               chan->priority+=200;
+
+                       res = 0;
+                       goto out; /* Is this right? */
+               }
+               else if( privdb_val == AST_PRIVACY_TORTURE ) {
+                       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 301, chan->cid.cid_num)) 
+                               chan->priority+=300;
+                       res = 0;
+                       goto out; /* is this right??? */
+
+               }
+               else if( privdb_val == AST_PRIVACY_UNKNOWN ) {
+                       /* Get the user's intro, store it in priv-callerintros/$CID, 
+                          unless it is already there-- this should be done before the 
+                          call is actually dialed  */
+
+                       /* make sure the priv-callerintros dir exists? */
+
+                       snprintf(privintro,sizeof(privintro),"priv-callerintros/%s", privcid);
+                       if( ast_fileexists(privintro,NULL,NULL ) > 0 && strncmp(privcid,"NOCALLERID",10) != 0) {
+                               /* the DELUX version of this code would allow this caller the
+                                  option to hear and retape their previously recorded intro.
+                               */
+                       }
+                       else {
+                               int duration; /* for feedback from play_and_wait */
+                               /* the file doesn't exist yet. Let the caller submit his
+                                  vocal intro for posterity */
+                               /* priv-recordintro script:
+
+                                  "At the tone, please say your name:"
+
+                               */
+                               ast_play_and_record(chan, "priv-recordintro", privintro, 4, "gsm", &duration, 128, 2000, 0);  /* NOTE: I've reduced the total time to 4 sec */
+                                                                                                                       /* don't think we'll need a lock removed, we took care of
+                                                                                                                          conflicts by naming the privintro file */
+                       }
+               }
        }
 
        /* If a channel group has been specified, get it for use when we create peer channels */
@@ -1172,6 +1280,194 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                        ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
                        ast_channel_sendurl( peer, url );
                } /* /JDG */
+               if( privacy || screen ) {
+                       int res2;
+                       int loopcount = 0;
+                       if( privdb_val == AST_PRIVACY_UNKNOWN ) {
+
+                               /* Get the user's intro, store it in priv-callerintros/$CID, 
+                                  unless it is already there-- this should be done before the 
+                                  call is actually dialed  */
+
+                               /* all ring indications and moh for the caller has been halted as soon as the 
+                                  target extension was picked up. We are going to have to kill some
+                                  time and make the caller believe the peer hasn't picked up yet */
+
+                               if ( strchr(transfer, 'm') ) {
+                                       ast_indicate(chan, -1);
+                                       ast_moh_start(chan, mohclass);
+                               } else if ( strchr(transfer, 'r') ) {
+                                       ast_indicate(chan, AST_CONTROL_RINGING);
+                                       sentringing++;
+                               }
+
+                               /* Start autoservice on the other chan ?? */
+                               res2 = ast_autoservice_start(chan);
+                               /* Now Stream the File */
+                               if (!res2) {
+                                       do {
+                                               if (!res2)
+                                                       res2 = ast_play_and_wait(peer,"priv-callpending");
+                                               if( res2 < '1' || (privacy && res2>'5') || (screen && res2 > '4') ) /* uh, interrupting with a bad answer is ... ignorable! */
+                                                       res2 = 0;
+                                               
+                                               /* priv-callpending script: 
+                                                  "I have a caller waiting, who introduces themselves as:"
+                                               */
+                                               if (!res2)
+                                                       res2 = ast_play_and_wait(peer,privintro);
+                                               if( res2 < '1' || (privacy && res2>'5') || (screen && res2 > '4') ) /* uh, interrupting with a bad answer is ... ignorable! */
+                                                       res2 = 0;
+                                               /* now get input from the called party, as to their choice */
+                                               if( !res2 ) {
+                                                       if( privacy )
+                                                               res2 = ast_play_and_wait(peer,"priv-callee-options");
+                                                       if( screen )
+                                                               res2 = ast_play_and_wait(peer,"screen-callee-options");
+                                               }
+                                               /* priv-callee-options script:
+                                                       "Dial 1 if you wish this caller to reach you directly in the future,
+                                                               and immediately connect to their incoming call
+                                                        Dial 2 if you wish to send this caller to voicemail now and 
+                                                               forevermore.
+                                                        Dial 3 to send this callerr to the torture menus, now and forevermore.
+                                                        Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
+                                                        Dial 5 to allow this caller to come straight thru to you in the future,
+                                               but right now, just this once, send them to voicemail."
+                                               */
+                               
+                                               /* screen-callee-options script:
+                                                       "Dial 1 if you wish to immediately connect to the incoming call
+                                                        Dial 2 if you wish to send this caller to voicemail.
+                                                        Dial 3 to send this callerr to the torture menus.
+                                                        Dial 4 to send this caller to a simple "go away" menu.
+                                               */
+                                               if( !res2 || res2 < '1' || (privacy && res2 > '5') || (screen && res2 > '4') ) {
+                                                       /* invalid option */
+                                                       res2 = ast_play_and_wait(peer,"vm-sorry");
+                                               }
+                                               loopcount++; /* give the callee a couple chances to make a choice */
+                                       } while( (!res2 || res2 < '1' || (privacy && res2 > '5') || (screen && res2 > '4')) && loopcount < 2 );
+                               }
+
+                               switch(res2) {
+                               case '1':
+                                       if( privacy ) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n", privdb, privcid);
+                                               ast_privacy_set(privdb,privcid,AST_PRIVACY_ALLOW);
+                                       }
+                                       break;
+                               case '2':
+                                       if( privacy ) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to DENY\n", privdb, privcid);
+                                               ast_privacy_set(privdb,privcid,AST_PRIVACY_DENY);
+                                       }
+                                       if ( strchr(transfer, 'm') ) {
+                                               ast_moh_stop(chan);
+                                       } else if ( strchr(transfer, 'r') ) {
+                                               ast_indicate(chan, -1);
+                                               sentringing=0;
+                                       }
+                                       res2 = ast_autoservice_stop(chan);
+                                       ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
+                                       res=0;
+                                       goto out;
+                                       break;
+                               case '3':
+                                       if( privacy ) {
+                                               ast_privacy_set(privdb,privcid,AST_PRIVACY_TORTURE);
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to TORTURE\n", privdb, privcid);
+                                       }
+                                       ast_copy_string(status, "TORTURE", sizeof(status));
+                                       
+                                       res = 0;
+                                       if ( strchr(transfer, 'm') ) {
+                                               ast_moh_stop(chan);
+                                       } else if ( strchr(transfer, 'r') ) {
+                                               ast_indicate(chan, -1);
+                                               sentringing=0;
+                                       }
+                                       res2 = ast_autoservice_stop(chan);
+                                       ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
+                                       goto out; /* Is this right? */
+                                       break;
+                               case '4':
+                                       if( privacy ) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to KILL\n", privdb, privcid);
+                                               ast_privacy_set(privdb,privcid,AST_PRIVACY_KILL);
+                                       }
+
+                                       ast_copy_string(status, "DONTCALL", sizeof(status));
+                                       res = 0;
+                                       if ( strchr(transfer, 'm') ) {
+                                               ast_moh_stop(chan);
+                                       } else if ( strchr(transfer, 'r') ) {
+                                               ast_indicate(chan, -1);
+                                               sentringing=0;
+                                       }
+                                       res2 = ast_autoservice_stop(chan);
+                                       ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
+                                       goto out; /* Is this right? */
+                                       break;
+                               case '5':
+                                       if( privacy ) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n", privdb, privcid);
+                                               ast_privacy_set(privdb,privcid,AST_PRIVACY_ALLOW);
+                                       
+                                               if ( strchr(transfer, 'm') ) {
+                                                       ast_moh_stop(chan);
+                                               } else if ( strchr(transfer, 'r') ) {
+                                                       ast_indicate(chan, -1);
+                                                       sentringing=0;
+                                               }
+                                               res2 = ast_autoservice_stop(chan);
+                                               ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
+                                               res=0;
+                                               goto out;
+                                               break;
+                                       } /* if not privacy, then 5 is the same as "default" case */
+                               default:
+                                       /* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do?  */
+                                       /* well, there seems basically two choices. Just patch the caller thru immediately,
+                                                 or,... put 'em thru to voicemail. */
+                                       /* since the callee may have hung up, let's do the voicemail thing, no database decision */
+                                       if (option_verbose > 2)
+                                               ast_log(LOG_NOTICE,"privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
+                                       if ( strchr(transfer, 'm') ) {
+                                               ast_moh_stop(chan);
+                                       } else if ( strchr(transfer, 'r') ) {
+                                               ast_indicate(chan, -1);
+                                               sentringing=0;
+                                       }
+                                       res2 = ast_autoservice_stop(chan);
+                                       ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
+                                       res=0;
+                                       goto out;
+                                       break;
+                               }
+                               if ( strchr(transfer, 'm') ) {
+                                       ast_moh_stop(chan);
+                               } else if ( strchr(transfer, 'r') ) {
+                                       ast_indicate(chan, -1);
+                                       sentringing=0;
+                               }
+                               res2 = ast_autoservice_stop(chan);
+                               /* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll 
+                                  just clog things up, and it's not useful information, not being tied to a CID */
+                               if( strncmp(privcid,"NOCALLERID",10) == 0 || no_save_intros ) {
+                                       ast_filedelete(privintro, NULL);
+                                       if( ast_fileexists(privintro,NULL,NULL ) > 0 )
+                                               ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
+                                       else if (option_verbose > 2)
+                                               ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
+                               }
+                       }
+               }
                if (announce && announcemsg) {
                        /* Start autoservice on the other chan */
                        res = ast_autoservice_start(chan);
index 1bba5ea..af7bee6 100755 (executable)
@@ -304,6 +304,31 @@ exten => _s-.,1,Goto(s-NOANSWER,1)                         ; Treat anything else as no answer
 
 exten => a,1,VoicemailMain(${ARG1})                            ; If they press *, send the user into VoicemailMain
 
+[macro-stdPrivacyexten];
+;
+; Standard extension macro:
+;   ${ARG1} - Extension  (we could have used ${MACRO_EXTEN} here as well
+;   ${ARG2} - Device(s) to ring
+;   ${ARG3} - Optional DONTCALL context name to jump to (assumes the s,1 extension-priority)
+;   ${ARG4} - Optional TORTURE context name to jump to (assumes the s,1 extension-priority)`
+;
+exten => s,1,Dial(${ARG2},20|p)                                        ; Ring the interface, 20 seconds maximum, call screening option (or use P for databased call screening)
+exten => s,2,Goto(s-${DIALSTATUS},1)                           ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
+
+exten => s-NOANSWER,1,Voicemail(u${ARG1})              ; If unavailable, send to voicemail w/ unavail announce
+exten => s-NOANSWER,2,Goto(default,s,1)                        ; If they press #, return to start
+
+exten => s-BUSY,1,Voicemail(b${ARG1})                  ; If busy, send to voicemail w/ busy announce
+exten => s-BUSY,2,Goto(default,s,1)                            ; If they press #, return to start
+
+exten => s-DONTCALL,1,Goto(${ARG3},s,1)               ; Callee chose to send this call to a polite "Don't call again" script.
+
+exten => s-TORTURE,1,Goto(${ARG4},s,1)                ; Callee chose to send this call to a telemarketer torture script.
+
+exten => _s-.,1,Goto(s-NOANSWER,1)                             ; Treat anything else as no answer
+
+exten => a,1,VoicemailMain(${ARG1})                            ; If they press *, send the user into VoicemailMain
+
 [demo]
 ;
 ; We start with what to do when a call first comes in.
diff --git a/doc/README.privacy b/doc/README.privacy
new file mode 100755 (executable)
index 0000000..3a990fa
--- /dev/null
@@ -0,0 +1,361 @@
+Title: Everything About The Privacy Options In The Dial Command That
+You Never Wanted To Know, And Even A Little More On Zapateller and
+PrivacyManager:
+
+by Steve Murphy
+
+
+So, you want to avoid talking to pesky telemarketers/charity
+seekers/poll takers/magazine renewers/etc?
+
+=============
+First of all:
+=============
+
+Try the FTC "Don't call" database, this alone will reduce your
+telemarketing call volume considerably.  (see:
+https://www.donotcall.gov/default.aspx ) But, this list won't protect
+from the Charities, previous business relationships, etc.
+
+
+=================================
+Next, Fight against autodialers!!
+=================================
+
+Zapateller detects if callerid is present, and if not, plays the
+da-da-da tones that immediately precede messages like, "I'm sorry,
+the number you have called is no longer in service."
+
+Most humans, even those with unlisted/callerid-blocked numbers, will
+not immediately slam the handset down on the hook the moment they hear
+the three tones. But autodialers seem pretty quick to do this.
+
+I just counted 40 hangups in Zapateller over the last year in my
+CDR's.  So, that is possibly 40 different telemarketers/charities that have
+hopefully slashed my back-waters, out-of-the-way, humble home phone
+number from their lists.
+
+I highly advise Zapateller for those seeking the nirvana of "privacy".
+
+
+=======================================
+Next, Fight against the empty CALLERID!
+=======================================
+
+A considerable percentage of the calls you don't want, come from
+sites that do not provide CallerID. 
+
+Null callerid's are a fact of life, and could be a friend with an
+unlisted number, or some charity looking for a handout. The
+PrivacyManager application can help here. It will ask the caller to
+enter a 10-digit phone number. They get 3 tries(configurable), and this is
+configurable, with control being passed to priority+101 if they won't
+supply one.
+
+PrivacyManager can't guarantee that the number they supply is any
+good, tho, as there is no way to find out, short of hanging up and
+calling them back. But some answers are obviously wrong. For instance,
+it seems a common practice for telemarketers to use your own number
+instead of giving you theirs. A simple test can detect this. More
+advanced tests would be to look for -555- numbers, numbers that count
+up or down, numbers of all the same digit, etc.
+
+My logs show that 39 have hung up in the PrivacyManager script over
+the last year.
+
+(Note: Demanding all unlisted incoming callers to enter their CID may
+not always be appropriate for all users. Another option might be to
+use call screening. See below.)
+
+==========================
+Next, use a WELCOME MENU !
+==========================
+
+Experience has shown that simply presenting incoming callers with
+a set of options, no matter how simple, will deter them from calling
+you. In the vast majority of situations, a telemarketer will simply
+hang up rather than make a choice and press a key.
+
+This will also immediately foil all autodialers that simply belch a
+message in your ear and hang up.
+
+
+----------------------------------------------
+Example usage of Zapateller and PrivacyManager:
+----------------------------------------------
+
+[homeline]
+exten => s,1,Answer
+exten => s,2,SetVar,repeatcount=0
+exten => s,3,Zapateller,nocallerid
+exten => s,4,PrivacyManager
+exten => s,105,Background(tt-allbusy)       ;; do this if they don't enter a number to Privacy Manager
+exten => s,106,Background(tt-somethingwrong)
+exten => s,107,Background(tt-monkeysintro)
+exten => s,108,Background(tt-monkeys)
+exten => s,109,Background(tt-weasels)
+exten => s,110,Hangup
+exten => s,5,GotoIf($[ "${CALLERIDNUM}"  = "7773334444" &  "${CALLERIDNAME}" : "Privacy Manager" ]?callerid-liar|s|1:s|7)
+
+I suggest using Zapateller at the beginning of the context, before
+anything else, on incoming calls.This can be followed by the
+PrivacyManager App.
+
+Make sure, if you do the PrivacyManager app, that you take care of the
+error condition! or their non-compliance will be rewarded with access
+to the system. In the above, if they can't enter a 10-digit number in
+3 tries, they get the humorous "I'm sorry, but all household members
+are currently helping other telemarketers...", "something is terribly
+wrong", "monkeys have carried them away...", various loud monkey
+screechings, "weasels have...", and a hangup. There are plenty of
+other paths to my torture scripts, I wanted to have some fun.
+
+In nearly all cases now, the telemarketers/charity-seekers that
+usually get thru to my main intro, hang up. I guess they can see it's
+pointless, or the average telemarketer/charity-seeker is instructed
+not to enter options when encountering such systems. Don't know. 
+
+===================
+Next: Torture Them!
+===================
+
+I have developed an elaborate script to torture Telemarketers, and
+entertain friends. (See
+http://www.voip-info.org/wiki-Asterisk+Telemarketer+Torture )
+
+While mostly those that call in and traverse my teletorture scripts
+are those we know, and are doing so out of curiosity, there have been
+these others from Jan 1st,2004 thru June 1st, 2004:
+(the numbers may or may not be correct.)
+
+603890zzzz     hung up telemarket options.
+"Integrated Sale"  called a couple times. hung up in telemarket options
+"UNITED STATES GOV"  (-- maybe a military recruiter, trying to lure one of my sons).
+800349zzzz -- hung up in charity intro
+800349zzzz -- hung up in charity choices, intro, about the only one who actually travelled to the bitter bottom of the scripts!
+216377zzzz -- hung up the magazine section
+626757zzzz = "LIR    " (pronounced "Liar"?) hung up in telemarket intro, then choices
+757821zzzz -- hung up in new magazine subscription options.
+
+That averages out to maybe 1 a month. That puts into question whether
+the ratio of the amount of labor it took to make the scripts versus
+the benefits of lower call volumes was worth it, but, well, I had fun,
+so what the heck.
+
+but, that's about it. Not a whole lot. But I haven't had to say "NO"
+or "GO AWAY" to any of these folks for about a year now ...!
+
+========================================
+      Using Call Screening
+=======================================
+
+Another option is to use call screening in the Dial command. It has
+two main privacy modes, one that remembers the CID of the caller, and
+how the callee wants the call handled, and the other, which does not
+have a "memory".
+
+Turning on these modes in the dial command results in this sequence of
+events, when someone calls you at an extension:
+
+1. The caller calls the Asterisk system, and at some point, selects an
+option or enters an extension number that would dial your extension.
+
+2. Before ringing your extension, the caller is asked to supply an
+introduction. The application asks them: "After the tone, say your
+name". They are allowed 4 seconds of introduction.
+
+3. After that, they are told "Hang on, we will attempt to connect you
+to your party. Depending on your dial options, they will hear ringing
+indications, or get music on hold. I suggest music on hold.
+
+4. Your extension is then dialed. When (and if) you pick up, you are
+told that a caller presenting themselves as <their recorded intro is
+played> is calling, and you have options, like being connected,
+sending them to voicemail, torture, etc.
+
+5. You make your selection, and the call is handled as you chose.
+
+
+There are some variations, and these will be explained in due course.
+
+
+To use these options, set your Dial to something like:
+
+exten => 3,3,Dial(Zap/5r3&Zap/6r3|35|tmPA(beep))
+
+or 
+
+exten => 3,3,Dial(Zap/5r3&Zap/6r3|35|tmP(something)A(beep))
+
+or 
+
+exten => 3,3,Dial(Zap/5r3&Zap/6r3|35|tmpA(beep))
+
+
+The 't' allows the dialed party to transfer the call using '#'. It's
+optional.
+
+The 'm' is for music on hold. I suggest it. Otherwise, the calling
+party gets to hear all the ringing, and lack thereof. It is generally
+better to use Music On Hold. Lots of folks hang up after the 3rd or
+4th ring, and you might lose the call before you can enter an option!
+
+The 'P' option alone will database everything using the extension as a
+default 'tree'. To get multiple extensions sharing the same database, use
+P(some-shared-key). Also, if the same person has multiple extensions,
+use P(unique-id) on all their dial commands.
+
+Use little 'p' for screening. Every incoming call will include a
+prompt for the callee's choice. 
+
+the A(beep), will generate a 'beep' that the callee will hear if they
+choose to talk to the caller. It's kind of a prompt to let the callee
+know that he has to say 'hi'. It's not required, but I find it
+helpful.
+
+When there is no CallerID, P and p options will always record an intro
+for the incoming caller. This intro will be stored temporarily in the
+/var/lib/asterisk/sounds/priv-callerintros dir, under the name
+NOCALLERID_<extension><channelname> and will be erased after the
+callee decides what to do with the call.
+
+Of course, NOCALLERID is not stored in the database. All those with no
+CALLERID will be considered "Unknown".
+
+========================
+ The 'N' and 'n' options
+========================
+
+Two other options exist, that act as modifiers to the privacy options
+'P' and 'p'. They are 'N' and 'n'. You can enter them as dialing
+options, but they only affect things if P or p are also in the
+options.
+
+'N' says, "Only screen the call if no CallerID is present". So, if a
+callerID were supplied, it will come straight thru to your extension.
+
+'n' says, "Don't save any introductions". Folks will be asked to
+supply an introduction ("At the tone, say your name") every time they
+call. Their introductions will be removed after the callee makes a
+choice on how to handle the call. Whether the P option or the p option
+is used, the incoming caller will have to supply their intro every
+time they call.
+
+=======================
+Recorded Introductions
+=======================
+
+[Philosophical Side Note:
+The 'P' option stores the CALLERID in the database, along with the
+callee's choice of actions, as a convenience to the CALLEE, whereas
+introductions are stored and re-used for the convenience of the CALLER.]
+
+Unless instructed to not save introductions (see the 'n' option above),
+the screening modes will save the recordings of the caller's names in
+the directory /var/lib/asterisk/sounds/priv-callerintros, if they have
+a CallerID.  Just the 10-digit callerid numbers are used as filenames,
+with a ".gsm" at the end.
+
+Having these recordings around can be very useful, however...
+
+First of all, if a callerid is supplied, and a recorded intro for that
+number is already present, the caller is spared the inconvenience of
+having to supply their name, which shortens their call a bit.
+
+Next of all, these intros can be used in voicemail, played over
+loudspeakers, and perhaps other nifty things. For instance:
+
+exten => s,7,System(/usr/bin/play /var/lib/asterisk/sounds/priv-callerintros/${CALLERIDNUM}.gsm&|0) 
+
+When a call comes in at the house, the above priority gets executed,
+and the callers intro is played over the phone systems speakers. This
+gives us a hint who is calling.
+
+(Note: the |0 option at the end of the System command above, is a
+local mod I made to the System command. It forces a 0 result code to
+be returned, whether the play command successfully completed or
+not. Therefore, I don't have to ensure that the file exists or
+not. While I've turned this mod into the developers, it hasn't been
+incorporated yet. You might want to write an AGI or shell script to
+handle it a little more intelligently)
+
+And one other thing. You can easily supply your callers with an option
+to listen to, and re-record their introductions. Here's what I did in
+the home system's extensions.conf. (assume that a
+Goto(home-introduction|s|1) exists somewhere in your main menu as an
+option):
+
+[home-introduction]
+exten => s,1,Background,intro-options   ;; Script: To hear your Introduction, dial 1.
+                                        ;;         to record a new introduction, dial 2.
+                                        ;;         to return to the main menu, dial 3.
+                                        ;;         to hear what this is all about, dial 4.
+exten => 1,1,Playback,priv-callerintros/${CALLERIDNUM}
+exten => 1,2,Goto(s,1)
+exten => 2,1,Goto(home-introduction-record,s,1)
+exten => 3,1,Goto(homeline,s,7)
+exten => 4,1,Playback,intro-intro     ;; Script:
+                                ;; This may seem a little strange, but it really is a neat
+                                ;; thing, both for you and for us. I've taped a short introduction
+                                ;; for many of the folks who normally call us. Using the Caller ID
+                                ;; from each incoming call, the system plays the introduction
+                                ;; for that phone number over a speaker, just as the call comes in.
+                                ;; This helps the folks
+                                ;; here in the house more quickly determine who is calling.
+                                ;; and gets the right ones to gravitate to the phone.
+                                ;; You can listen to, and record a new intro for your phone number
+                                ;; using this menu.
+exten => 4,2,Goto(s,1)
+exten => t,1,Goto(s,1)
+exten => i,1,Background,invalid
+exten => i,2,Goto(s,1)
+exten => o,1,Goto(s,1)
+
+[home-introduction-record]
+exten => s,1,Background,intro-record-choices    ;; Script:
+                                ;;      If you want some advice about recording your
+                                ;;      introduction, dial 1. 
+                                ;;      otherwise, dial 2, and introduce yourself after
+                                ;;      the beep.
+exten => 1,1,Playback,intro-record
+                                ;;      Your introduction should be short and sweet and crisp.
+                                ;;      Your introduction will be limited to 4 seconds.
+                                ;;      This is NOT meant to be a voice mail message, so
+                                ;;      please, don't say anything about why you are calling.
+                                ;;      After we are done making the recording, your introduction
+                                ;;      will be saved for playback. 
+                                ;;      If you are the only person that would call from this number, 
+                                ;;      please state your name.  Otherwise, state your business
+                                ;;      or residence name instead. For instance, if you are 
+                                ;;      friend of the family, say, Olie McPherson, and both
+                                ;;      you and your kids might call here a lot, you might
+                                ;;      say: "This is the distinguished Olie McPherson Residence!"
+                                ;;      If you are the only person calling, you might say this:
+                                ;;      "This is the illustrious Kermit McFrog! Pick up the Phone, someone!!"
+                                ;;      If you are calling from a business, you might pronounce a more sedate introduction,like,
+                                ;;      "Fritz from McDonalds calling.", or perhaps the more original introduction:
+                                ;;      "John, from the Park County Morgue. You stab 'em, we slab 'em!".
+                                ;;      Just one caution: the kids will hear what you record every time
+                                ;;      you call. So watch your language!
+                                ;;      I will begin recording after the tone. 
+                                ;;      When you are done, hit the # key. Gather your thoughts and get 
+                                ;;      ready. Remember, the # key will end the recording, and play back
+                                ;;      your intro. Good Luck, and Thank you!"
+exten => 1,2,Goto(2,1)
+exten => 2,1,Background,intro-start
+                                ;;  OK, here we go! After the beep, please give your introduction.
+exten => 2,2,Background,beep
+exten => 2,3,Record,priv-callerintros/${CALLERIDNUM}:gsm|4
+exten => 2,4,Background,priv-callerintros/${CALLERIDNUM}
+exten => 2,5,Goto(home-introduction,s,1)
+exten => t,1,Goto(s,1)
+exten => i,1,Background,invalid
+exten => i,2,Goto(s,1)
+exten => o,1,Goto(s,1)
+
+
+In the above, you'd most likely reword the messages to your liking,
+and maybe do more advanced things with the 'error' conditions (i,o,t priorities),
+but I hope it conveys the idea...
+
+
index 5194570..a0ece60 100755 (executable)
 
 %priv-instruct.gsm%Press 1 to accept this call.  Press 2 to not accept this call.  Press 3 to always accept calls from this number.  Press 4 to never accept calls from this number.  Press 5 to reject calls from this number and request that they add you to their do not call list.
 
+%priv-callee-options.gsm%Dial 1 if you wish this caller to reach you directly now, and in the future.  Dial 2 if you wish to send this caller to voicemail now and forevermore.  Dial 3 to send this caller to the torture menus, now and forevermore.  Dial 4 to send this caller to a polite "don't call" menu, now and forevermore.  Dial 5 to allow this caller to come straight thru to you in the future, but just this once, send them to voicemail.
+
+%screen-callee-options.gsm%You have these options: Dial 1 if you wish to immediately connect to the incoming call.  Dial 2 if you wish to send this caller to voicemail.  Dial 3 to send this callerr to the torture menus.  Dial 4 to send this caller to a polite "don't call" menu.
+
+%priv-introsaved.gsm%Thank you. Please hold, while I attempt to connect you with your party!
+
+%priv-recordintro.gsm%At the tone, please say your name.
+
+%priv-callpending.gsm%I have a caller waiting, who introduces themselves as:
+
 %privacy-unident.gsm%The party you are trying to reach does not accept unidentified calls.
 
 %privacy-prompt.gsm%Please enter your phone number, starting with the area code.
diff --git a/sounds/priv-callee-options.gsm b/sounds/priv-callee-options.gsm
new file mode 100755 (executable)
index 0000000..8f6d8d9
Binary files /dev/null and b/sounds/priv-callee-options.gsm differ
diff --git a/sounds/priv-callpending.gsm b/sounds/priv-callpending.gsm
new file mode 100755 (executable)
index 0000000..bf44fa6
Binary files /dev/null and b/sounds/priv-callpending.gsm differ
diff --git a/sounds/priv-introsaved.gsm b/sounds/priv-introsaved.gsm
new file mode 100755 (executable)
index 0000000..a86b9d1
Binary files /dev/null and b/sounds/priv-introsaved.gsm differ
diff --git a/sounds/priv-recordintro.gsm b/sounds/priv-recordintro.gsm
new file mode 100755 (executable)
index 0000000..a287f54
Binary files /dev/null and b/sounds/priv-recordintro.gsm differ
diff --git a/sounds/screen-callee-options.gsm b/sounds/screen-callee-options.gsm
new file mode 100755 (executable)
index 0000000..52b8b57
Binary files /dev/null and b/sounds/screen-callee-options.gsm differ