aboutsummaryrefslogtreecommitdiffstats
path: root/apps/app_qcall.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-12-10 21:47:23 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-12-10 21:47:23 +0000
commit21b6f9e94726a70c03a09b7fe6f4e79c7e2f61db (patch)
tree3f789956a574ba69e3000fb06cb00331b8ee823a /apps/app_qcall.c
parenta7b345c3fd2de4767b1494d33fcba264ed7ffdfc (diff)
Version 0.1.10 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@394 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps/app_qcall.c')
-rwxr-xr-xapps/app_qcall.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/apps/app_qcall.c b/apps/app_qcall.c
new file mode 100755
index 000000000..87672e5ff
--- /dev/null
+++ b/apps/app_qcall.c
@@ -0,0 +1,370 @@
+/** @file app_qcall.c
+ *
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Call back a party and connect them to a running pbx thread
+ *
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ * Call a user from a file contained within a queue (/var/spool/asterisk/qcall)
+ *
+ * The queue is a directory containing files with the call request information
+ * as a single line of text as follows:
+ *
+ * Dialstring Caller-ID Extension Maxsecs Identifier [Required-response]
+ *
+ * Dialstring -- A Dial String (The number to be called) in the
+ * format Technology/Number, such IAX/mysys/1234 or Zap/g1/1234
+ *
+ * Caller-ID -- A Standard nomalized representation of the Caller-ID of
+ * the number being dialed (generally 10 digits in the US).
+ *
+ * Extension -- The Extension (optionally Extension@context) that the
+ * user should be "transferred" to after acceptance of the call.
+ *
+ * Maxsecs -- The Maximum time of the call in seconds. Specify 0 for infinite.
+ *
+ * Identifier -- The "Identifier" of the request. This is used to determine
+ * the names of the audio prompt files played. The first prompt, the one that
+ * asks for the input, is just the exact string specified as the identifier.
+ * The second prompt, the one that is played after the correct input is given,
+ * (generally a "thank you" recording), is the specified string with "-ok"
+ * added to the end. So, if you specify "foo" as the identifier, your first
+ * prompt file that will be played will be "foo" and the second one will be
+ * "foo-ok".
+ *
+ * Required-Response (Optional) -- Specify a digit string to be used as the
+ * acceptance "code" if you desire it to be something other then "1". This
+ * can be used to implement some sort of PIN or security system. It may be
+ * more then a single character.
+ *
+ * NOTE: It is important to remember that the process that creates these
+ * files needs keep and maintain a write lock (using flock with the LOCK_EX
+ * option) when writing these files.
+ *
+ */
+
+#include <asterisk/file.h>
+#include <asterisk/logger.h>
+#include <asterisk/channel.h>
+#include <asterisk/pbx.h>
+#include <asterisk/module.h>
+#include <asterisk/translate.h>
+#include <asterisk/options.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+
+const char *qdir="/var/spool/asterisk/qcall";
+static char *tdesc = "Call from Queue";
+static pthread_t qcall_thread;
+static int debug = 0;
+STANDARD_LOCAL_USER;
+LOCAL_USER_DECL;
+
+#define OLDESTOK 14400 /* not any more then this number of secs old */
+#define INITIALONE 20 /* initial wait before the first one in secs */
+#define NEXTONE 600 /* wait before trying it again in secs */
+#define MAXWAITFORANSWER 45000 /* max call time before answer */
+/* define either one or both of these two if your application requires it */
+#if 0
+#define ACCTCODE "SOMETHING" /* Account code */
+#define AMAFLAGS AST_CDR_BILLING /* AMA flags */
+#endif
+/* define this if you want to have a particular CLID display on the user's
+ phone when they receive the call */
+#if 0
+#define OURCLID "2564286275" /* The callerid to be displayed when calling */
+#endif
+
+static void *qcall_do(void *arg);
+
+static void *qcall(void *ignore)
+{
+pthread_t dialer_thread;
+DIR *dirp;
+FILE *fp;
+struct dirent *dp;
+char fname[80];
+struct stat mystat;
+time_t t;
+void *arg;
+pthread_attr_t attr;
+
+ time(&t);
+ if (debug) printf("@@@@ qcall starting at %s",ctime(&t));
+ for(;;)
+ {
+ time(&t);
+ dirp = opendir(qdir);
+ if (!dirp)
+ {
+ perror("app_qcall:Cannot open queue directory");
+ break;
+ }
+ while((dp = readdir(dirp)) != NULL)
+ {
+ if (dp->d_name[0] == '.') continue;
+ sprintf(fname,"%s/%s",qdir,dp->d_name);
+ if (stat(fname,&mystat) == -1)
+ {
+ perror("app_qcall:stat");
+ fprintf(stderr,"%s\n",fname);
+ continue;
+ }
+ /* if not a regular file, skip it */
+ if ((mystat.st_mode & S_IFMT) != S_IFREG) continue;
+ /* if not yet .... */
+ if (mystat.st_atime == mystat.st_ctime)
+ { /* first time */
+ if ((mystat.st_atime + INITIALONE) > t) continue;
+ }
+ else
+ { /* already looked at once */
+ if ((mystat.st_atime + NEXTONE) > t) continue;
+ }
+ /* if too old */
+ if (mystat.st_mtime < (t - OLDESTOK))
+ {
+ /* kill it, its too old */
+ unlink(fname);
+ continue;
+ }
+ /* "touch" file's access time */
+ fp = fopen(fname,"r");
+ if (fp) fclose(fp);
+ /* make a copy of the filename string, so that we
+ may go on and use the buffer */
+ arg = (void *) strdup(fname);
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (pthread_create(&dialer_thread,&attr,qcall_do,arg) == -1)
+ {
+ perror("qcall: Cannot create thread");
+ continue;
+ }
+ }
+ closedir(dirp);
+ sleep(1);
+ }
+ pthread_exit(NULL);
+}
+
+/* single thread with one file (request) to dial */
+static void *qcall_do(void *arg)
+{
+char fname[300],dialstr[300],extstr[300],ident[300],reqinp[300],buf[300];
+char clid[300],*tele,*context;
+FILE *fp;
+int ms = MAXWAITFORANSWER,maxsecs;
+struct ast_channel *channel;
+time_t t;
+
+ /* get the filename from the arg */
+ strcpy(fname,(char *)arg);
+ free(arg);
+ time(&t);
+ fp = fopen(fname,"r");
+ if (!fp) /* if cannot open request file */
+ {
+ perror("qcall_do:fopen");
+ fprintf(stderr,"%s\n",fname);
+ unlink(fname);
+ pthread_exit(NULL);
+ }
+ /* lock the file */
+ if (flock(fileno(fp),LOCK_EX) == -1)
+ {
+ perror("qcall_do:flock");
+ fprintf(stderr,"%s\n",fname);
+ pthread_exit(NULL);
+ }
+ strcpy(reqinp,"1"); /* default required input for acknowledgement */
+ if (fscanf(fp,"%s %s %s %d %s %s",dialstr,clid,
+ extstr,&maxsecs,ident,reqinp) < 5)
+ {
+ fprintf(stderr,"qcall_do:file line invalid in file %s:\n",fname);
+ pthread_exit(NULL);
+ }
+ flock(fileno(fp),LOCK_UN);
+ fclose(fp);
+ tele = strchr(dialstr,'/');
+ if (!tele)
+ {
+ fprintf(stderr,"qcall_do:Dial number must be in format tech/number\n");
+ unlink(fname);
+ pthread_exit(NULL);
+ }
+ *tele++ = 0;
+ channel = ast_request(dialstr,AST_FORMAT_SLINEAR,tele);
+ if (channel)
+ {
+ ast_set_read_format(channel,AST_FORMAT_SLINEAR);
+ ast_set_write_format(channel,AST_FORMAT_SLINEAR);
+ channel->callerid = NULL;
+ channel->hidden_callerid = NULL;
+#ifdef OURCLID
+ channel->callerid = strdup(OURCLID);
+ channel->hidden_callerid = strdup(OURCLID);
+#endif
+ channel->whentohangup = 0;
+ channel->appl = "AppQcall";
+ channel->data = "(Outgoing Line)";
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Qcall initiating call to %s/%s on %s (%s)\n",
+ dialstr,tele,channel->name,fname);
+ ast_call(channel,tele,MAXWAITFORANSWER);
+ }
+ else
+ {
+ fprintf(stderr,"qcall_do:Sorry unable to obtain channel\n");
+ pthread_exit(NULL);
+ }
+ if (channel->callerid) free(channel->callerid);
+ channel->callerid = NULL;
+ if (channel->hidden_callerid) free(channel->hidden_callerid);
+ channel->hidden_callerid = NULL;
+ if (channel->state == AST_STATE_UP)
+ if (debug) printf("@@@@ Autodial:Line is Up\n");
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Qcall waiting for answer on %s\n",
+ channel->name);
+ while(ms > 0){
+ struct ast_frame *f;
+ ms = ast_waitfor(channel,ms);
+ f = ast_read(channel);
+ if (!f)
+ {
+ if (debug) printf("@@@@ qcall_do:Hung Up\n");
+ ast_frfree(f);
+ unlink(fname);
+ break;
+ }
+ if (f->frametype == AST_FRAME_CONTROL)
+ {
+ if (f->subclass == AST_CONTROL_HANGUP)
+ {
+ if (debug) printf("@@@@ qcall_do:Hung Up\n");
+ unlink(fname);
+ ast_frfree(f);
+ break;
+ }
+ if (f->subclass == AST_CONTROL_ANSWER)
+ {
+ if (debug) printf("@@@@ qcall_do:Phone Answered\n");
+ if (channel->state == AST_STATE_UP)
+ {
+ unlink(fname);
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Qcall got answer on %s\n",
+ channel->name);
+ usleep(1500000);
+ ast_streamfile(channel,ident,0);
+ if (ast_readstring(channel,buf,strlen(reqinp),10000,5000,"#"))
+ {
+ ast_stopstream(channel);
+ if (debug) printf("@@@@ qcall_do: timeout or hangup in dtmf read\n");
+ ast_frfree(f);
+ break;
+ }
+ ast_stopstream(channel);
+ if (strcmp(buf,reqinp)) /* if not match */
+ {
+ if (debug) printf("@@@@ qcall_do: response (%s) does not match required (%s)\n",buf,reqinp);
+ ast_frfree(f);
+ break;
+ }
+ ast_frfree(f);
+ /* okay, now we go for it */
+ context = strchr(extstr,'@');
+ if (!context) context = "default";
+ else *context++ = 0;
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Qcall got accept, now putting through to %s@%s on %s\n",
+ extstr,context,channel->name);
+ strcat(ident,"-ok");
+ /* if file existant, play it */
+ if (!ast_streamfile(channel,ident,0))
+ {
+ ast_waitstream(channel,"");
+ ast_stopstream(channel);
+ }
+ channel->callerid = strdup(clid);
+ channel->hidden_callerid = strdup(clid);
+ channel->language[0] = 0;
+ channel->dnid = strdup(extstr);
+#ifdef AMAFLAGS
+ channel->amaflags = AMAFLAGS;
+#endif
+#ifdef ACCTCODE
+ strcpy(channel->accountcode,ACCTCODE);
+#else
+ channel->accountcode[0] = 0;
+#endif
+ if (maxsecs) /* if finite length call */
+ {
+ time(&channel->whentohangup);
+ channel->whentohangup += maxsecs;
+ }
+ strcpy(channel->exten,extstr);
+ strcpy(channel->context,context);
+ channel->priority = 1;
+ ast_pbx_run(channel);
+ pthread_exit(NULL);
+ }
+ }
+ else if(f->subclass==AST_CONTROL_RINGING)
+ if (debug) printf("@@@@ qcall_do:Phone Ringing end\n");
+ }
+ ast_frfree(f);
+ }
+ ast_hangup(channel);
+ if (debug) printf("@@@@ qcall_do:Hung up channel\n");
+ pthread_exit(NULL);
+ return NULL;
+}
+
+int unload_module(void)
+{
+ STANDARD_HANGUP_LOCALUSERS;
+ return 0;
+}
+
+int load_module(void)
+{
+ mkdir(qdir,0660);
+ pthread_create(&qcall_thread,NULL,qcall,NULL);
+ return 0;
+}
+
+char *description(void)
+{
+ return tdesc;
+}
+
+int usecount(void)
+{
+ int res;
+ STANDARD_USECOUNT(res);
+ return res;
+}
+
+char *key()
+{
+ return ASTERISK_GPL_KEY;
+}