From 63ff35280893f84fca60ea5944659edadb21334f Mon Sep 17 00:00:00 2001 From: Mark Spencer <markster@digium.com> Date: Thu, 30 Jan 2003 15:03:20 +0000 Subject: [PATCH] Version 0.3.0 from FTP git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@593 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- app.c | 104 +++++++++++++ apps/app_directory.c | 11 +- apps/app_qcall.c | 6 +- apps/app_voicemail.c | 322 +++++++++++++++++++++++++++------------ astconf.h | 32 ++++ asterisk.h | 26 ++-- astman/Makefile | 10 +- cdr/cdr_csv.c | 31 ++-- cli.c | 132 +++++++++++++++- config.c | 5 +- db.c | 355 +++++++++++++++++++++++++++++++++++++++++++ image.c | 11 +- loader.c | 7 +- logger.c | 26 ++-- pbx/pbx_config.c | 71 +++++---- pbx/pbx_gtkconsole.c | 11 +- pbx/pbx_wilcalu.c | 4 +- 17 files changed, 969 insertions(+), 195 deletions(-) create mode 100755 astconf.h create mode 100755 db.c diff --git a/app.c b/app.c index 2d2af6de9c..482c2ee3ae 100755 --- a/app.c +++ b/app.c @@ -19,9 +19,15 @@ #include <signal.h> #include <errno.h> #include <unistd.h> +#include <dirent.h> #include <asterisk/channel.h> #include <asterisk/file.h> #include <asterisk/app.h> +#include <asterisk/dsp.h> +#include <asterisk/logger.h> +#include <asterisk/options.h> +#include "asterisk.h" +#include "astconf.h" /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for "ludicrous time" (essentially never times out) */ @@ -41,3 +47,101 @@ int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, in return res; } +int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec) +{ + int res; + struct ast_filestream *writer; + int rfmt; + int totalms, total; + + struct ast_frame *f; + struct ast_dsp *sildet; + /* Play prompt if requested */ + if (prompt) { + res = ast_streamfile(c, prompt, c->language); + if (res < 0) + return res; + res = ast_waitstream(c,""); + if (res < 0) + return res; + } + rfmt = c->readformat; + res = ast_set_read_format(c, AST_FORMAT_SLINEAR); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); + return -1; + } + sildet = ast_dsp_new(); + if (!sildet) { + ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); + return -1; + } + writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666); + if (!writer) { + ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt); + ast_dsp_free(sildet); + return -1; + } + for(;;) { + if ((res = ast_waitfor(c, 2000)) < 0) { + ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt); + break; + } + if (res) { + f = ast_read(c); + if (!f) { + ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt); + break; + } + if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { + /* Ended happily with DTMF */ + ast_frfree(f); + break; + } else if (f->frametype == AST_FRAME_VOICE) { + ast_dsp_silence(sildet, f, &total); + if (total > silence) { + /* Ended happily with silence */ + ast_frfree(f); + break; + } + totalms += f->samples / 8; + if (totalms > maxsec * 1000) { + /* Ended happily with too much stuff */ + ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec); + ast_frfree(f); + break; + } + } + ast_frfree(f); + } + } + res = ast_set_read_format(c, rfmt); + if (res) + ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name); + ast_dsp_free(sildet); + ast_closestream(writer); + return 0; +} + +int ast_app_has_voicemail(char *mailbox) +{ + DIR *dir; + struct dirent *de; + char fn[256]; + + /* If no mailbox, return immediately */ + if (!strlen(mailbox)) + return 0; + snprintf(fn, sizeof(fn), "%s/vm/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, mailbox); + dir = opendir(fn); + if (!dir) + return 0; + while ((de = readdir(dir))) { + if (!strncasecmp(de->d_name, "msg", 3)) + break; + } + closedir(dir); + if (de) + return 1; + return 0; +} diff --git a/apps/app_directory.c b/apps/app_directory.c index 8618030fce..868badb020 100755 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -25,6 +25,7 @@ #include <pthread.h> #include <stdio.h> #include "../asterisk.h" +#include "../astconf.h" static char *tdesc = "Extension Directory"; static char *app = "Directory"; @@ -127,13 +128,12 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char * struct ast_variable *v; int res; int found=0; - char *start, *pos, *conv; + char *start, *pos, *conv,*stringp=NULL; char fn[256]; memset(ext, 0, sizeof(ext)); ext[0] = digit; res = 0; if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; - printf("Res: %d, ext: %s\n", res, ext); if (!res) { /* Search for all names which start with those digits */ v = ast_variable_browse(cfg, context); @@ -143,8 +143,9 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char * /* Find a candidate extension */ start = strdup(v->value); if (start) { - strtok(start, ","); - pos = strtok(NULL, ","); + stringp=start; + strsep(&stringp, ","); + pos = strsep(&stringp, ","); if (pos) { /* Grab the last name */ if (strrchr(pos, ' ')) @@ -167,7 +168,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char * } if (v) { /* We have a match -- play a greeting if they have it */ - snprintf(fn, sizeof(fn), "%s/vm/%s/greet", AST_SPOOL_DIR, v->name); + snprintf(fn, sizeof(fn), "%s/vm/%s/greet", (char *)ast_config_AST_SPOOL_DIR, v->name); if (ast_fileexists(fn, NULL, chan->language) > 0) { res = ast_streamfile(chan, fn, chan->language); if (!res) diff --git a/apps/app_qcall.c b/apps/app_qcall.c index 5a1df97262..a68239abc0 100755 --- a/apps/app_qcall.c +++ b/apps/app_qcall.c @@ -71,8 +71,9 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/file.h> +#include "../astconf.h" -const char *qdir="/var/spool/asterisk/qcall"; +char qdir[255]; static char *tdesc = "Call from Queue"; static pthread_t qcall_thread; static int debug = 0; @@ -132,7 +133,7 @@ pthread_attr_t attr; /* 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) + if (mystat.st_atime == mystat.st_mtime) { /* first time */ if ((mystat.st_atime + INITIALONE) > t) continue; @@ -361,6 +362,7 @@ int unload_module(void) int load_module(void) { + snprintf((char *)qdir,sizeof(qdir)-1,"%s/%s",(char *)ast_config_AST_SPOOL_DIR,"qcall"); mkdir(qdir,0660); pthread_create(&qcall_thread,NULL,qcall,NULL); return 0; diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 2d77f891bb..0646b0601f 100755 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -21,6 +21,7 @@ #include <asterisk/say.h> #include <asterisk/module.h> #include <asterisk/adsi.h> +#include <asterisk/app.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> @@ -33,6 +34,7 @@ #include <pthread.h> #include "../asterisk.h" +#include "../astconf.h" #define COMMAND_TIMEOUT 5000 @@ -95,8 +97,10 @@ static char *synopsis_vmain = "Enter voicemail system"; static char *descrip_vmain = -" VoiceMailMain(): Enters the main voicemail system for the checking of voicemail. Returns\n" -" -1 if the user hangs up or 0 otherwise.\n"; +" VoiceMailMain(): Enters the main voicemail system for the checking of voicemail. The mailbox\n" +"can be passed as the option, which will stop the voicemail system from prompting the user\n" +"for the mailbox. If the mailbox is preceeded by 's' then the passsword check will be skipped.\n" +"Returns -1 if the user hangs up or 0 otherwise.\n"; /* Leave a message */ static char *app = "VoiceMail"; @@ -110,7 +114,7 @@ LOCAL_USER_DECL; static int make_dir(char *dest, int len, char *ext, char *mailbox) { - return snprintf(dest, len, "%s/%s/%s", VM_SPOOL_DIR, ext, mailbox); + return snprintf(dest, len, "%s/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", ext, mailbox); } static int make_file(char *dest, int len, char *dir, int num) @@ -127,9 +131,13 @@ static int vm_change_password(char *username, char *password, char *newpassword) FILE *configout; char inbuf[256]; char orig[256]; + char tmpin[AST_CONFIG_MAX_PATH]; + char tmpout[AST_CONFIG_MAX_PATH]; char *user, *pass, *rest, *trim; - configin = fopen("/etc/asterisk/voicemail.conf","r"); - configout = fopen("/etc/asterisk/voicemail.conf.new","w+"); + snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR); + snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR); + configin = fopen((char *)tmpin,"r"); + configout = fopen((char *)tmpout,"w+"); while (!feof(configin)) { /* Read in the line */ @@ -185,38 +193,11 @@ static int vm_change_password(char *username, char *password, char *newpassword) fclose(configin); fclose(configout); - unlink("/etc/asterisk/voicemail.conf"); - rename("/etc/asterisk/voicemail.conf.new","/etc/asterisk/voicemail.conf"); + unlink((char *)tmpin); + rename((char *)tmpout,(char *)tmpin); return(1); } -#if 0 - -static int announce_message(struct ast_channel *chan, char *dir, int msgcnt) -{ - char *fn; - int res; - - res = ast_streamfile(chan, "vm-message", chan->language); - if (!res) { - res = ast_waitstream(chan, AST_DIGIT_ANY); - if (!res) { - res = ast_say_number(chan, msgcnt+1, chan->language); - if (!res) { - fn = get_fn(dir, msgcnt); - if (fn) { - res = ast_streamfile(chan, fn, chan->language); - free(fn); - } - } - } - } - if (res < 0) - ast_log(LOG_WARNING, "Unable to announce message\n"); - return res; -} -#endif - static int inbuf(FILE *fi) { @@ -351,13 +332,17 @@ static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *m char dur[256]; time_t t; struct tm *tm; + char *astattach; + struct ast_config *cfg; p = popen(SENDMAIL, "w"); - + cfg = ast_load(VOICEMAIL_CONFIG); + if (!(astattach = ast_variable_retrieve(cfg, "general", "attach"))) + astattach = "yes"; if (p) { + gethostname(host, sizeof(host)); if (strchr(srcemail, '@')) strncpy(who, srcemail, sizeof(who)-1); else { - gethostname(host, sizeof(host)); snprintf(who, sizeof(who), "%s@%s", srcemail, host); } snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60); @@ -370,30 +355,32 @@ static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *m fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox); fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host); fprintf(p, "MIME-Version: 1.0\n"); + if (ast_true(astattach)) { + // Something unique. + snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid()); - // Something unique. - snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid()); + fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound); - fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound); - - fprintf(p, "--%s\n", bound); - fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n"); - strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm); - fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n" + fprintf(p, "--%s\n", bound); + } + fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n"); + strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm); + fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n" "in mailbox %s from %s, on %s so you might\n" "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name, - dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date); - - fprintf(p, "--%s\n", bound); - fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d\"\n", msgnum); - fprintf(p, "Content-Transfer-Encoding: BASE64\n"); - fprintf(p, "Content-Description: Voicemail sound attachment.\n"); - fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format); - - snprintf(fname, sizeof(fname), "%s.%s", attach, format); - base_encode(fname, p); - fprintf(p, "\n\n--%s--\n.\n", bound); + dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date); + if (ast_true(astattach)) { + fprintf(p, "--%s\n", bound); + fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format); + fprintf(p, "Content-Transfer-Encoding: BASE64\n"); + fprintf(p, "Content-Description: Voicemail sound attachment.\n"); + fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format); + + snprintf(fname, sizeof(fname), "%s.%s", attach, format); + base_encode(fname, p); + fprintf(p, "\n\n--%s--\n.\n", bound); + } pclose(p); } else { ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL); @@ -411,7 +398,7 @@ static int get_date(char *s, int len) return strftime(s, len, "%a %b %e %r %Z %Y", tm); } -static int invent_message(struct ast_channel *chan, char *ext, int busy) +static int invent_message(struct ast_channel *chan, char *ext, int busy, char *ecodes) { int res; char fn[256]; @@ -420,17 +407,17 @@ static int invent_message(struct ast_channel *chan, char *ext, int busy) res = ast_streamfile(chan, fn, chan->language); if (res) return -1; - res = ast_waitstream(chan, "#"); + res = ast_waitstream(chan, ecodes); if (res) return res; } else { res = ast_streamfile(chan, "vm-theperson", chan->language); if (res) return -1; - res = ast_waitstream(chan, "#"); + res = ast_waitstream(chan, ecodes); if (res) return res; - res = ast_say_digit_str(chan, ext, "#", chan->language); + res = ast_say_digit_str(chan, ext, ecodes, chan->language); if (res) return res; } @@ -440,7 +427,7 @@ static int invent_message(struct ast_channel *chan, char *ext, int busy) res = ast_streamfile(chan, "vm-isunavail", chan->language); if (res) return -1; - res = ast_waitstream(chan, "#"); + res = ast_waitstream(chan, ecodes); return res; } @@ -457,12 +444,15 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int int msgnum; int outmsg=0; int wavother=0; + int maxmessage=0; struct ast_frame *f; char date[256]; char dir[256]; char fn[256]; char prefile[256]=""; char *astemail; + char *ecodes = "#"; + char *s; time_t start; time_t end; @@ -473,7 +463,15 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int } if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) astemail = ASTERISK_USERNAME; + if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) { + if (sscanf(s, "%d", &x) == 1) { + maxmessage = x; + } else { + ast_log(LOG_WARNING, "Invalid max message time length\n"); + } + } if ((copy = ast_variable_retrieve(cfg, NULL, ext))) { + char *stringp=NULL; /* Setup pre-file if appropriate */ if (busy) snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext); @@ -481,9 +479,10 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext); /* Make sure they have an entry in the config */ copy = strdup(copy); - passwd = strtok(copy, ","); - name = strtok(NULL, ","); - email = strtok(NULL, ","); + stringp=copy; + passwd = strsep(&stringp, ","); + name = strsep(&stringp, ","); + email = strsep(&stringp, ","); make_dir(dir, sizeof(dir), ext, ""); /* It's easier just to try to make it than to check for its existence */ if (mkdir(dir, 0700) && (errno != EEXIST)) @@ -491,14 +490,16 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int make_dir(dir, sizeof(dir), ext, "INBOX"); if (mkdir(dir, 0700) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + if (ast_exists_extension(chan, chan->context, "o", 1, chan->callerid)) + ecodes = "#0"; /* Play the beginning intro if desired */ if (strlen(prefile)) { if (ast_fileexists(prefile, NULL, NULL) > 0) { if (ast_streamfile(chan, prefile, chan->language) > -1) - silent = ast_waitstream(chan, "#"); + silent = ast_waitstream(chan, "#0"); } else { ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile); - silent = invent_message(chan, ext, busy); + silent = invent_message(chan, ext, busy, ecodes); } if (silent < 0) { ast_log(LOG_DEBUG, "Hang up during prefile playback\n"); @@ -515,15 +516,29 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int free(copy); return -1; } + } else if (silent == '0') { + strncpy(chan->exten, "0", sizeof(chan->exten) - 1); + chan->priority = 0; + free(copy); + return 0; } /* Stream an info message */ if (silent || !ast_streamfile(chan, INTRO, chan->language)) { /* Wait for the message to finish */ if (silent || !ast_waitstream(chan, "")) { + if (!ast_streamfile(chan, "beep", chan->language) < 0) + silent = 1; + if (ast_waitstream(chan, "") <0) { + ast_log(LOG_DEBUG, "Hangup during beep\n"); + free(copy); + return -1; + } fmt = ast_variable_retrieve(cfg, "general", "format"); if (fmt) { + char *stringp=NULL; fmts = strdup(fmt); - fmt = strtok(fmts, "|"); + stringp=fmts; + fmt = strsep(&stringp, "|"); msgnum = 0; do { make_file(fn, sizeof(fn), dir, msgnum); @@ -540,6 +555,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int msgnum++; } while(!writer && (msgnum < MAXMSG)); if (writer) { + char *stringp=NULL; /* Store information */ snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); txt = fopen(txtfile, "w+"); @@ -573,8 +589,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int free(fmts); fmt = ast_variable_retrieve(cfg, "general", "format"); fmts = strdup(fmt); - strtok(fmts, "|"); - while((fmt = strtok(NULL, "|"))) { + stringp=fmts; + strsep(&stringp, "|"); + while((fmt = strsep(&stringp, "|"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; @@ -604,8 +621,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int for(;;) { res = ast_waitfor(chan, 2000); if (!res) { - ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); - res = -1; + ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); + /* Try one more time in case of masq */ + res = ast_waitfor(chan, 2000); + if (!res) { + ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); + res = -1; + } } if (res < 0) { @@ -639,10 +661,19 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); outmsg=2; ast_frfree(f); + res = 0; break; } } ast_frfree(f); + time(&end); + if (maxmessage && (end - start > maxmessage)) { + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n"); + outmsg = 2; + res = 0; + break; + } } if (!f) { if (option_verbose > 2) @@ -674,6 +705,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int fclose(txt); } /* Send e-mail if applicable */ + if (email) sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start); } } else { @@ -1069,8 +1101,10 @@ static void adsi_message(struct ast_channel *chan, char *folder, int msg, int la while(!feof(f)) { fgets(buf, sizeof(buf), f); if (!feof(f)) { - strtok(buf, "="); - val = strtok(NULL, "="); + char *stringp=NULL; + stringp=buf; + strsep(&stringp, "="); + val = strsep(&stringp, "="); if (val && strlen(val)) { if (!strcmp(buf, "callerid")) strncpy(cid, val, sizeof(cid) - 1); @@ -1326,7 +1360,7 @@ forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int if (play_and_wait(chan, "vm-savedto")) break; - snprintf(todir, sizeof(todir), "%s/%s/INBOX", VM_SPOOL_DIR, username); + snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR,"vm", username); snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir); puts(sys); system(sys); @@ -1434,7 +1468,7 @@ forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \ } while (0) -static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile) +static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime) { char d, *fmt, *fmts; char comment[256]; @@ -1443,6 +1477,9 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor struct ast_config *cfg; struct ast_filestream *others[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; + char *stringp=NULL; + time_t start, end; + ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile); snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name); @@ -1461,11 +1498,12 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor ast_destroy(cfg); - strtok(fmts, "|"); + stringp=fmts; + strsep(&stringp, "|"); ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = strdup(fmts); - while((fmt = strtok(NULL, "|"))) { + while((fmt = strsep(&stringp, "|"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; @@ -1473,6 +1511,8 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor sfmt[fmtcnt++] = strdup(fmt); } + if (maxtime) + time(&start); for (x=0;x<fmtcnt;x++) { others[x] = ast_writefile(recordfile, sfmt[x], comment, 0, 0, 0700); ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s\n", x, recordfile, sfmt[x]); @@ -1496,14 +1536,19 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor for(;;) { res = ast_waitfor(chan, 2000); if (!res) { - ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); - res = -1; + ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); + /* Try one more time in case of masq */ + res = ast_waitfor(chan, 2000); + if (!res) { + ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); + res = -1; } + } if (res < 0) { f = NULL; break; - } + } f = ast_read(chan); if (!f) @@ -1527,6 +1572,15 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor break; } } + if (maxtime) { + time(&end); + if (maxtime < (end - start)) { + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); + outmsg=2; + break; + } + } ast_frfree(f); } if (!f) { @@ -1567,9 +1621,12 @@ static int vm_execmain(struct ast_channel *chan, void *data) like I'm back in my GWBASIC days. XXX */ int res=-1; int valid = 0; + int prefix = 0; char d; struct localuser *u; char username[80] =""; + char prefixstr[80] =""; + char empty[80] = ""; char password[80] = "", *copy; char newpassword[80] = ""; char newpassword2[80] = ""; @@ -1592,6 +1649,10 @@ static int vm_execmain(struct ast_channel *chan, void *data) int starting = 1; int box; int useadsi = 0; + int skipuser = 0; + char *s; + int maxgreet = 0; + char tmp[256], *ext; struct ast_config *cfg; LOCAL_USER_ADD(u); @@ -1600,26 +1661,63 @@ static int vm_execmain(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "No voicemail configuration\n"); goto out; } + if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) { + if (sscanf(s, "%d", &x) == 1) { + maxgreet = x; + } else { + ast_log(LOG_WARNING, "Invalid max message greeting length\n"); + } + } if (chan->_state != AST_STATE_UP) ast_answer(chan); + if (strlen(data)) { + strncpy(tmp, data, sizeof(tmp) - 1); + ext = tmp; + + switch (*ext) { + case 's': + /* We should skip the user's password */ + valid++; + ext++; + break; + case 'p': + /* We should prefix the mailbox with the supplied data */ + prefix++; + ext++; + break; + } + + + if (prefix) + strncpy(prefixstr, ext, sizeof(prefixstr) - 1); + else + strncpy(username, ext, sizeof(username) - 1); + /* make sure username passed as an option is valid */ + if (ast_variable_retrieve(cfg, NULL, username)) + skipuser++; + else + valid = 0; + + } + /* If ADSI is supported, setup login screen */ adsi_begin(chan, &useadsi); - if (useadsi) + if (!skipuser && useadsi) adsi_login(chan); - if (ast_streamfile(chan, "vm-login", chan->language)) { + if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) { ast_log(LOG_WARNING, "Couldn't stream login file\n"); goto out; } /* Authenticate them and get their mailbox/password */ - do { + while (!valid) { /* Prompt for, and read in the username */ - if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) { + if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) { ast_log(LOG_WARNING, "Couldn't read username\n"); goto out; - } + } if (!strlen(username)) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n"); @@ -1636,17 +1734,32 @@ static int vm_execmain(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Unable to read password\n"); goto out; } + if (prefix) { + char fullusername[80] = ""; + strncpy(fullusername, prefixstr, sizeof(fullusername) - 1); + strncat(fullusername, username, sizeof(fullusername) - 1); + strncpy(username, fullusername, sizeof(username) - 1); + } copy = ast_variable_retrieve(cfg, NULL, username); if (copy) { + char *stringp=NULL; copy = strdup(copy); - strtok(copy, ","); + stringp=copy; + strsep(&stringp, ","); if (!strcmp(password,copy)) valid++; - else if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username); + else { + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username); + if (prefix) + strncpy(username, empty, sizeof(username) -1); + } free(copy); - } else if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username); + } else { + skipuser = 0; + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username); + } if (!valid) { if (useadsi) adsi_login(chan); @@ -1657,9 +1770,11 @@ static int vm_execmain(struct ast_channel *chan, void *data) break; #endif } - } while (!valid); + } if (valid) { + snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username); + mkdir(curdir, 0700); OPEN_MAILBOX(1); oldmessages = lastmsg + 1; /* Start in INBOX */ @@ -1879,15 +1994,15 @@ vm_options: case '1': snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username); - play_and_record(chan,"vm-rec-unv",prefile); + play_and_record(chan,"vm-rec-unv",prefile, maxgreet); break; case '2': snprintf(prefile,sizeof(prefile),"vm/%s/busy",username); - play_and_record(chan,"vm-rec-busy",prefile); + play_and_record(chan,"vm-rec-busy",prefile, maxgreet); break; case '3': snprintf(prefile,sizeof(prefile),"vm/%s/greet",username); - play_and_record(chan,"vm-rec-name",prefile); + play_and_record(chan,"vm-rec-name",prefile, maxgreet); break; case '4': newpassword[1] = '\0'; @@ -1930,14 +2045,21 @@ static int vm_exec(struct ast_channel *chan, void *data) { int res=0, silent=0, busy=0, unavail=0; struct localuser *u; - char *ext = (char *)data; + char tmp[256], *ext; - - if (!data) { - ast_log(LOG_WARNING, "vm requires an argument (extension)\n"); - return -1; - } LOCAL_USER_ADD(u); + if (chan->_state != AST_STATE_UP) + ast_answer(chan); + if (data) + strncpy(tmp, data, sizeof(tmp) - 1); + else { + res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0); + if (res < 0) + return res; + if (!strlen(tmp)) + return 0; + } + ext = tmp; if (*ext == 's') { silent++; ext++; @@ -1948,8 +2070,6 @@ static int vm_exec(struct ast_channel *chan, void *data) unavail++; ext++; } - if (chan->_state != AST_STATE_UP) - ast_answer(chan); res = leave_voicemail(chan, ext, silent, busy, unavail); LOCAL_USER_REMOVE(u); return res; diff --git a/astconf.h b/astconf.h new file mode 100755 index 0000000000..da3301f6de --- /dev/null +++ b/astconf.h @@ -0,0 +1,32 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * General Definitions for Asterisk top level program + * + * 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 + */ + +#ifndef _ASTCONF_H +#define _ASTCONF_H + +#define AST_CONFIG_MAX_PATH 255 + +extern char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_DB[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_PID[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH]; +extern char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH]; + +#endif diff --git a/asterisk.h b/asterisk.h index eafb1597dc..ea3a9a7f2d 100755 --- a/asterisk.h +++ b/asterisk.h @@ -16,17 +16,20 @@ #define DEFAULT_LANGUAGE "en" -#define AST_CONFIG_DIR "/etc/asterisk" -#define AST_SOCKET "/var/run/asterisk.ctl" -#define AST_PID "/var/run/asterisk.pid" -#define AST_MODULE_DIR "/usr/lib/asterisk/modules" -#define AST_SPOOL_DIR "/var/spool/asterisk" -#define AST_VAR_DIR "/var/lib/asterisk" -#define AST_LOG_DIR "/var/log/asterisk" -#define AST_AGI_DIR "/var/lib/asterisk/agi-bin" -#define AST_KEY_DIR "/var/lib/asterisk/keys" +#define AST_CONFIG_MAX_PATH 255 +#define AST_CONFIG_DIR ASTETCDIR +#define AST_RUN_DIR ASTVARRUNDIR +#define AST_SOCKET ASTVARRUNDIR "/asterisk.ctl" +#define AST_PID ASTVARRUNDIR "/asterisk.pid" +#define AST_MODULE_DIR ASTMODDIR +#define AST_SPOOL_DIR ASTSPOOLDIR +#define AST_VAR_DIR ASTVARLIBDIR +#define AST_LOG_DIR ASTLOGDIR +#define AST_AGI_DIR ASTAGIDIR +#define AST_KEY_DIR ASTVARLIBDIR "/keys" +#define AST_DB ASTVARLIBDIR "/astdb" -#define AST_CONFIG_FILE "asterisk.conf" +#define AST_CONFIG_FILE ASTCONFPATH #define AST_SOUNDS AST_VAR_DIR "/sounds" #define AST_IMAGES AST_VAR_DIR "/images" @@ -43,4 +46,7 @@ extern int init_framer(void); extern int reload_logger(void); /* Provided by term.c */ extern int term_init(void); +/* Provided by db.c */ +extern int astdb_init(void); + #endif diff --git a/astman/Makefile b/astman/Makefile index f932ffb9ff..106affcd83 100755 --- a/astman/Makefile +++ b/astman/Makefile @@ -1,15 +1,17 @@ -TARGET=$(shell if [ -f /usr/include/newt.h ]; then echo "astman"; fi) +TARGET=$(shell if [ -f /usr/include/newt.h ]; then echo "astman"; else echo "none" ; fi) all: $(TARGET) install: - mkdir -p /usr/sbin - if [ "$(TARGET)" != "" ]; then \ + if [ "$(TARGET)" != "none" ]; then \ for x in $(TARGET); do \ - install -m 755 $$x /usr/sbin/astman; \ + install -m 755 $$x $(ASTSBINDIR)/astman; \ done ; \ fi +none: + @echo Not building the Asterisk Manager "astman" + clean: rm -f *.o astman diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c index a46c9bfbbf..da7b07edc3 100755 --- a/cdr/cdr_csv.c +++ b/cdr/cdr_csv.c @@ -19,9 +19,10 @@ #include <asterisk/module.h> #include <asterisk/logger.h> #include "../asterisk.h" +#include "../astconf.h" -#define CSV_LOG_DIR AST_LOG_DIR "/cdr-csv" -#define CSV_MASTER CSV_LOG_DIR "/Master.csv" +#define CSV_LOG_DIR "/cdr-csv" +#define CSV_MASTER "/Master.csv" #define DATE_FORMAT "%Y-%m-%d %T" @@ -35,22 +36,26 @@ /* The values are as follows: - "accountcode", + "accountcode", // accountcode is the account name of detail records, Master.csv contains all records + // Detail records are configured on a channel basis, IAX and SIP are determined by user + // Zap is determined by channel in zaptel.conf "source", "destination", "destination context", "callerid", "channel", "destination channel", (if applicable) - "last application", - "last app argument", + "last application", // Last application run on the channel + "last app argument", // argument to the last channel "start time", "answer time", "end time", - duration, - billable seconds, - "disposition", - "amaflags", + duration, // Duration is the whole length that the entire call lasted. ie. call rx'd to hangup + // "end time" minus "start time" + billable seconds, // the duration that a call was up after other end answered which will be <= to duration + // "end time" minus "answer time" + "disposition", // ANSWERED, NO ANSWER, BUSY + "amaflags", // DOCUMENTATION, BILL, IGNORE etc, specified on a per channel basis like accountcode. */ @@ -170,7 +175,7 @@ static int writefile(char *s, char *acc) ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); return -1; } - snprintf(tmp, sizeof(tmp), "%s/%s.csv", CSV_LOG_DIR, acc); + snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", (char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); f = fopen(tmp, "a"); if (!f) return -1; @@ -184,6 +189,8 @@ static int csv_log(struct ast_cdr *cdr) { /* Make sure we have a big enough buf */ char buf[1024]; + char csvmaster[AST_CONFIG_MAX_PATH]; + snprintf((char *)csvmaster,sizeof(csvmaster)-1,"%s/%s/%s",(char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR,CSV_MASTER); #if 0 printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode); #endif @@ -193,9 +200,9 @@ static int csv_log(struct ast_cdr *cdr) /* because of the absolutely unconditional need for the highest reliability possible in writing billing records, we open write and close the log file each time */ - mf = fopen(CSV_MASTER, "a"); + mf = fopen(csvmaster, "a"); if (!mf) { - ast_log(LOG_ERROR, "Unable to re-open master file %s\n", CSV_MASTER); + ast_log(LOG_ERROR, "Unable to re-open master file %s\n", csvmaster); } if (mf) { fputs(buf, mf); diff --git a/cli.c b/cli.c index 5cc39bddc4..14cf3956ca 100755 --- a/cli.c +++ b/cli.c @@ -25,15 +25,15 @@ #include <string.h> #include <pthread.h> /* For rl_filename_completion */ -#include <readline/readline.h> +#include "editline/readline/readline.h" /* For module directory */ #include "asterisk.h" #include "build.h" +#include "astconf.h" #define VERSION_INFO "Asterisk " ASTERISK_VERSION " built by " BUILD_USER "@" BUILD_HOSTNAME \ " on a " BUILD_MACHINE " running " BUILD_OS - void ast_cli(int fd, char *fmt, ...) { char stuff[4096]; @@ -219,6 +219,16 @@ static char commandcomplete_help[] = " This function is used internally to help with command completion and should.\n" " never be called by the user directly.\n"; +static char commandnummatches_help[] = +"Usage: _command nummatches \"<line>\" text \n" +" This function is used internally to help with command completion and should.\n" +" never be called by the user directly.\n"; + +static char commandmatchesarray_help[] = +"Usage: _command matchesarray \"<line>\" text \n" +" This function is used internally to help with command completion and should.\n" +" never be called by the user directly.\n"; + static int handle_softhangup(int fd, int argc, char *argv[]) { struct ast_channel *c=NULL; @@ -240,6 +250,56 @@ static int handle_softhangup(int fd, int argc, char *argv[]) static char *__ast_cli_generator(char *text, char *word, int state, int lock); +static int handle_commandmatchesarray(int fd, int argc, char *argv[]) +{ + char buf[2048]; + int len = 0; + char **matches; + int x; + + if (argc != 4) + return RESULT_SHOWUSAGE; + buf[len] = '\0'; + matches = ast_cli_completion_matches(argv[2], argv[3]); + if (matches) { + for (x=0; matches[x]; x++) { +#if 0 + printf("command matchesarray for '%s' %s got '%s'\n", argv[2], argv[3], matches[x]); +#endif + len += sprintf( buf + len, "%s ", matches[x]); + } + } +#if 0 + printf("array for '%s' %s got '%s'\n", argv[2], argv[3], buf); +#endif + + if (buf) { + ast_cli(fd, buf); + } else + ast_cli(fd, "NULL\n"); + + return RESULT_SUCCESS; +} + + + +static int handle_commandnummatches(int fd, int argc, char *argv[]) +{ + int matches = 0; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + matches = ast_cli_generatornummatches(argv[2], argv[3]); + +#if 0 + printf("Search for '%s' %s got '%d'\n", argv[2], argv[3], matches); +#endif + ast_cli(fd, "%d", matches); + + return RESULT_SUCCESS; +} + static int handle_commandcomplete(int fd, int argc, char *argv[]) { char *buf; @@ -276,10 +336,12 @@ static int handle_showchan(int fd, int argc, char *argv[]) " DNID Digits: %s\n" " State: %s (%d)\n" " Rings: %d\n" + " NativeFormat: %d\n" " WriteFormat: %d\n" " ReadFormat: %d\n" - " NativeFormat: %d\n" "1st File Descriptor: %d\n" + " Frames in: %d\n" + " Frames out: %d\n" " -- PBX --\n" " Context: %s\n" " Extension: %s\n" @@ -291,7 +353,7 @@ static int handle_showchan(int fd, int argc, char *argv[]) c->name, c->type, (c->callerid ? c->callerid : "(N/A)"), (c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat, - c->fds[0], c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), + c->fds[0], c->fin, c->fout, c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), ( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"), c->stack, (c->blocking ? c->blockproc : "(Not Blocking)")); @@ -328,10 +390,10 @@ static char *complete_fn(char *line, char *word, int pos, int state) if (word[0] == '/') strncpy(filename, word, sizeof(filename)-1); else - snprintf(filename, sizeof(filename), "%s/%s", AST_MODULE_DIR, word); + snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_MODULE_DIR, word); c = (char*)filename_completion_function(filename, state); if (c && word[0] != '/') - c += (strlen(AST_MODULE_DIR) + 1); + c += (strlen((char*)ast_config_AST_MODULE_DIR) + 1); return c ? strdup(c) : c; } @@ -341,6 +403,8 @@ static struct ast_cli_entry builtins[] = { /* Keep alphabetized */ { { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help }, { { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help }, + { { "_command", "nummatches", NULL }, handle_commandnummatches, "Returns number of command matches", commandnummatches_help }, + { { "_command", "matchesarray", NULL }, handle_commandmatchesarray, "Returns command matches array", commandmatchesarray_help }, { { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn }, { { "reload", NULL }, handle_reload, "Reload configuration", reload_help }, { { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help }, @@ -637,6 +701,62 @@ normal: return dup; } +/* This returns the number of unique matches for the generator */ +int ast_cli_generatornummatches(char *text, char *word) +{ + int matches = 0, i = 0; + char *buf, *oldbuf; + + + while ( (buf = ast_cli_generator(text, word, i)) ) { + if (++i > 1 && strcmp(buf,oldbuf) == 0) + continue; + oldbuf = buf; + matches++; + } + + return matches; +} + +char **ast_cli_completion_matches(char *text, char *word) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + int matches = 0; + + match_list_len = 1; + while ((retstr = ast_cli_generator(text, word, matches)) != NULL) { + if (matches + 1 >= match_list_len) { + match_list_len <<= 1; + match_list = realloc(match_list, match_list_len * sizeof(char *)); + } + match_list[++matches] = retstr; + } + + if (!match_list) + return (char **) NULL; + + which = 2; + prevstr = match_list[1]; + max_equal = strlen(prevstr); + for (; which <= matches; which++) { + for (i = 0; i < max_equal && prevstr[i] == match_list[which][i]; i++) + continue; + max_equal = i; + } + + retstr = malloc(max_equal + 1); + (void) strncpy(retstr, match_list[1], max_equal); + retstr[max_equal] = '\0'; + match_list[0] = retstr; + + if (matches + 1 >= match_list_len) + match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *)); + match_list[matches + 1] = (char *) NULL; + + return (match_list); +} + static char *__ast_cli_generator(char *text, char *word, int state, int lock) { char *argv[AST_MAX_ARGS]; diff --git a/config.c b/config.c index d758d7fac1..114d6584aa 100755 --- a/config.c +++ b/config.c @@ -20,6 +20,7 @@ #include <asterisk/options.h> #include <asterisk/logger.h> #include "asterisk.h" +#include "astconf.h" #define MAX_INCLUDE_LEVEL 10 @@ -228,6 +229,8 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru if (!*_tmpc) { ast_log(LOG_WARNING, "parse error: No category context for line %d of %s\n", lineno, configfile); + ast_destroy(tmp); + return -1; } c = strchr(cur, '='); if (c) { @@ -272,7 +275,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s if (configfile[0] == '/') { strncpy(fn, configfile, sizeof(fn)-1); } else { - snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile); + snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, configfile); } if ((option_verbose > 1) && !option_debug) { ast_verbose( VERBOSE_PREFIX_2 "Parsing '%s': ", fn); diff --git a/db.c b/db.c new file mode 100755 index 0000000000..cbecc4d505 --- /dev/null +++ b/db.c @@ -0,0 +1,355 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * Channel Management + * + * 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 + */ + +/* DB3 is licensed under Sleepycat Public License and is thus incompatible + with GPL. To avoid having to make another exception (and complicate + licensing even further) we elect to use DB1 which is BSD licensed */ + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <sys/time.h> +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <dirent.h> +#include <asterisk/channel.h> +#include <asterisk/file.h> +#include <asterisk/app.h> +#include <asterisk/dsp.h> +#include <asterisk/logger.h> +#include <asterisk/options.h> +#include <asterisk/astdb.h> +#include <asterisk/cli.h> +#include "db1-ast/include/db.h" +#include "asterisk.h" +#include "astconf.h" + +static DB *astdb; +static pthread_mutex_t dblock = AST_MUTEX_INITIALIZER; + +static int dbinit(void) +{ + if (!astdb) { + if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) { + ast_log(LOG_WARNING, "Unable to open Asterisk database\n"); + } + } + if (astdb) + return 0; + return -1; +} + + +static inline int keymatch(const char *key, const char *prefix) +{ + if (!strlen(prefix)) + return 1; + if (!strcasecmp(key, prefix)) + return 1; + if ((strlen(key) > strlen(prefix)) && + !strncasecmp(key, prefix, strlen(prefix))) { + if (key[strlen(prefix)] == '/') + return 1; + } + return 0; +} + +int ast_db_deltree(const char *family, const char *keytree) +{ + char prefix[256]; + DBT key, data; + char *keys; + int res; + int pass; + + if (family) { + if (keytree) + snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree); + else + snprintf(prefix, sizeof(prefix), "/%s", family); + } else if (keytree) + return -1; + else + strcpy(prefix, ""); + + ast_pthread_mutex_lock(&dblock); + if (dbinit()) + return -1; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + pass = 0; + while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { + if (key.size) { + keys = key.data; + keys[key.size - 1] = '\0'; + } else + keys = "<bad key>"; + if (keymatch(keys, prefix)) { + astdb->del(astdb, &key, 0); + } + } + astdb->sync(astdb, 0); + ast_pthread_mutex_unlock(&dblock); + return 0; +} + +int ast_db_put(const char *family, const char *keys, char *value) +{ + char fullkey[256]; + DBT key, data; + int res; + + ast_pthread_mutex_lock(&dblock); + if (dbinit()) { + ast_pthread_mutex_unlock(&dblock); + return -1; + } + + snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys); + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fullkey; + key.size = strlen(fullkey) + 1; + data.data = value; + data.size = strlen(value) + 1; + res = astdb->put(astdb, &key, &data, 0); + astdb->sync(astdb, 0); + ast_pthread_mutex_unlock(&dblock); + if (res) + ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family); + return res; +} + +int ast_db_get(const char *family, const char *keys, char *value, int valuelen) +{ + char fullkey[256]; + DBT key, data; + int res; + + ast_pthread_mutex_lock(&dblock); + if (dbinit()) { + ast_pthread_mutex_unlock(&dblock); + return -1; + } + + snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys); + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fullkey; + key.size = strlen(fullkey) + 1; + + res = astdb->get(astdb, &key, &data, 0); + + ast_pthread_mutex_unlock(&dblock); + + /* Be sure to NULL terminate our data either way */ + if (res) { + value[0] = 0; + ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family); + } else { + printf("Got value of size %d\n", data.size); + if (data.size) { + ((char *)data.data)[data.size - 1] = '\0'; + strncpy(value, data.data, valuelen - 1); + value[valuelen - 1] = '\0'; + } else { + ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys); + value[0] = '\0'; + } + } + return res; +} + +int ast_db_del(const char *family, const char *keys) +{ + char fullkey[256]; + DBT key; + int res; + + ast_pthread_mutex_lock(&dblock); + if (dbinit()) { + ast_pthread_mutex_unlock(&dblock); + return -1; + } + + snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys); + memset(&key, 0, sizeof(key)); + key.data = fullkey; + key.size = strlen(fullkey) + 1; + + res = astdb->del(astdb, &key, 0); + astdb->sync(astdb, 0); + + ast_pthread_mutex_unlock(&dblock); + + if (res) + ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family); + return res; +} + +static int database_put(int fd, int argc, char *argv[]) +{ + int res; + if (argc != 5) + return RESULT_SHOWUSAGE; + res = ast_db_put(argv[2], argv[3], argv[4]); + if (res) + ast_cli(fd, "Failed to update entry\n"); + else + ast_cli(fd, "Updated database successfully\n"); + return RESULT_SUCCESS; +} + +static int database_get(int fd, int argc, char *argv[]) +{ + int res; + char tmp[256]; + if (argc != 4) + return RESULT_SHOWUSAGE; + res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp)); + if (res) + ast_cli(fd, "Database entry not found.\n"); + else + ast_cli(fd, "Value: %s\n", tmp); + return RESULT_SUCCESS; +} + +static int database_del(int fd, int argc, char *argv[]) +{ + int res; + if (argc != 4) + return RESULT_SHOWUSAGE; + res = ast_db_del(argv[2], argv[3]); + if (res) + ast_cli(fd, "Database entry does not exist.\n"); + else + ast_cli(fd, "Database entry removed.\n"); + return RESULT_SUCCESS; +} + +static int database_deltree(int fd, int argc, char *argv[]) +{ + int res; + if ((argc < 3) || (argc > 4)) + return RESULT_SHOWUSAGE; + if (argc == 4) + res = ast_db_deltree(argv[2], argv[3]); + else + res = ast_db_deltree(argv[2], NULL); + if (res) + ast_cli(fd, "Database entries do not exist.\n"); + else + ast_cli(fd, "Database entries removed.\n"); + return RESULT_SUCCESS; +} + +static int database_show(int fd, int argc, char *argv[]) +{ + char prefix[256]; + DBT key, data; + char *keys, *values; + int res; + int pass; + + if (argc == 4) { + /* Family and key tree */ + snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]); + } else if (argc == 3) { + /* Family only */ + snprintf(prefix, sizeof(prefix), "/%s", argv[2]); + } else if (argc == 2) { + /* Neither */ + strcpy(prefix, ""); + } else + return RESULT_SHOWUSAGE; + ast_pthread_mutex_lock(&dblock); + if (dbinit()) { + ast_pthread_mutex_unlock(&dblock); + ast_cli(fd, "Database unavailable\n"); + return RESULT_SUCCESS; + } + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + pass = 0; + while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { + if (key.size) { + keys = key.data; + keys[key.size - 1] = '\0'; + } else + keys = "<bad key>"; + if (data.size) { + values = data.data; + values[data.size - 1]='\0'; + } else + values = "<vad value>"; + if (keymatch(keys, prefix)) { + ast_cli(fd, "%-50s: %-25s\n", keys, values); + } + } + ast_pthread_mutex_unlock(&dblock); + return RESULT_SUCCESS; +} + +static char database_show_usage[] = +"Usage: database show [family [keytree]]\n" +" Shows Asterisk database contents, optionally restricted\n" +"to a given family, or family and keytree.\n"; + +static char database_put_usage[] = +"Usage: database put <family> <key> <value>\n" +" Adds or updates an entry in the Asterisk database for\n" +"a given family, key, and value.\n"; + +static char database_get_usage[] = +"Usage: database get <family> <key>\n" +" Retrieves an entry in the Asterisk database for a given\n" +"family and key.\n"; + +static char database_del_usage[] = +"Usage: database del <family> <key>\n" +" Deletes an entry in the Asterisk database for a given\n" +"family and key.\n"; + +static char database_deltree_usage[] = +"Usage: database deltree <family> [keytree]\n" +" Deletes a family or specific keytree within a family\n" +"in the Asterisk database.\n"; + +struct ast_cli_entry cli_database_show = +{ { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage }; + +struct ast_cli_entry cli_database_get = +{ { "database", "get", NULL }, database_get, "Gets database value", database_get_usage }; + +struct ast_cli_entry cli_database_put = +{ { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage }; + +struct ast_cli_entry cli_database_del = +{ { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage }; + +struct ast_cli_entry cli_database_deltree = +{ { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage }; + +int astdb_init(void) +{ + dbinit(); + ast_cli_register(&cli_database_show); + ast_cli_register(&cli_database_get); + ast_cli_register(&cli_database_put); + ast_cli_register(&cli_database_del); + ast_cli_register(&cli_database_deltree); + return 0; +} diff --git a/image.c b/image.c index 785e8ddfd0..7ee2b080ac 100755 --- a/image.c +++ b/image.c @@ -30,6 +30,7 @@ #include <asterisk/translate.h> #include <asterisk/cli.h> #include "asterisk.h" +#include "astconf.h" static struct ast_imager *list; static pthread_mutex_t listlock = AST_MUTEX_INITIALIZER; @@ -94,9 +95,9 @@ static void make_filename(char *buf, int len, char *filename, char *preflang, ch snprintf(buf, len, "%s.%s", filename, ext); } else { if (preflang && strlen(preflang)) - snprintf(buf, len, "%s/%s-%s.%s", AST_IMAGES, filename, preflang, ext); + snprintf(buf, len, "%s/%s/%s-%s.%s", ast_config_AST_VAR_DIR, "images", filename, preflang, ext); else - snprintf(buf, len, "%s/%s.%s", AST_IMAGES, filename, ext); + snprintf(buf, len, "%s/%s/%s.%s", ast_config_AST_VAR_DIR, "images", filename, ext); } } @@ -116,8 +117,10 @@ struct ast_frame *ast_read_image(char *filename, char *preflang, int format) i = list; while(!found && i) { if (i->format & format) { + char *stringp=NULL; strncpy(tmp, i->exts, sizeof(tmp)-1); - e = strtok(tmp, "|"); + stringp=tmp; + e = strsep(&stringp, "|"); while(e) { make_filename(buf, sizeof(buf), filename, preflang, e); if ((len = file_exists(buf))) { @@ -129,7 +132,7 @@ struct ast_frame *ast_read_image(char *filename, char *preflang, int format) found = i; break; } - e = strtok(NULL, "|"); + e = strsep(&stringp, "|"); } } i = i->next; diff --git a/loader.c b/loader.c index 6835fd8d0a..cd18b353e5 100755 --- a/loader.c +++ b/loader.c @@ -28,6 +28,7 @@ #define __USE_GNU #include <pthread.h> #include "asterisk.h" +#include "astconf.h" static char expected_key[] = { 0x8e, 0x93, 0x22, 0x83, 0xf5, 0xc3, 0xc0, 0x75, @@ -204,7 +205,7 @@ int ast_load_resource(char *resource_name) if (resource_name[0] == '/') { strncpy(fn, resource_name, sizeof(fn)-1); } else { - snprintf(fn, sizeof(fn), "%s/%s", AST_MODULE_DIR, resource_name); + snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name); } m->lib = dlopen(fn, flags); if (!m->lib) { @@ -331,7 +332,7 @@ int load_modules() int x; /* Make two passes. First, load any resource modules, then load the others. */ for (x=0;x<2;x++) { - mods = opendir(AST_MODULE_DIR); + mods = opendir((char *)ast_config_AST_MODULE_DIR); if (mods) { while((d = readdir(mods))) { /* Must end in .so to load it. */ @@ -374,7 +375,7 @@ int load_modules() closedir(mods); } else { if (!option_quiet) - ast_log(LOG_WARNING, "Unable to open modules directory " AST_MODULE_DIR ".\n"); + ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR); } } } diff --git a/logger.c b/logger.c index f48296130c..c7089d3188 100755 --- a/logger.c +++ b/logger.c @@ -27,8 +27,7 @@ #include <pthread.h> #include <sys/stat.h> #include "asterisk.h" - -#define AST_EVENT_LOG AST_LOG_DIR "/" EVENTLOG +#include "astconf.h" #define MAX_MSG_QUEUE 200 @@ -73,7 +72,9 @@ static int make_components(char *s, int lineno) { char *w; int res = 0; - w = strtok(s, ","); + char *stringp=NULL; + stringp=s; + w = strsep(&stringp, ","); while(w) { while(*w && (*w < 33)) w++; @@ -88,7 +89,7 @@ static int make_components(char *s, int lineno) else { fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno); } - w = strtok(NULL, ","); + w = strsep(&stringp, ","); } return res; } @@ -111,7 +112,7 @@ static struct logfile *make_logfile(char *fn, char *components, int lineno) if (fn[0] == '/') strncpy(tmp, fn, sizeof(tmp) - 1); else - snprintf(tmp, sizeof(tmp), "%s/%s", AST_LOG_DIR, fn); + snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, fn); f->f = fopen(tmp, "a"); if (!f->f) { /* Can't log here, since we're called with a lock */ @@ -179,14 +180,15 @@ static struct verb { int init_logger(void) { - - mkdir(AST_LOG_DIR, 0755); - eventlog = fopen(AST_EVENT_LOG, "a"); + char tmp[AST_CONFIG_MAX_PATH]; + mkdir((char *)ast_config_AST_LOG_DIR, 0755); + snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG); + eventlog = fopen((char *)tmp, "a"); if (eventlog) { init_logger_chain(); ast_log(LOG_EVENT, "Started Asterisk Event Logger\n"); if (option_verbose) - ast_verbose("Asterisk Event Logger Started\n"); + ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp); return 0; } else ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno)); @@ -196,11 +198,13 @@ int init_logger(void) int reload_logger(void) { + char tmp[AST_CONFIG_MAX_PATH]; ast_pthread_mutex_lock(&loglock); if (eventlog) fclose(eventlog); - mkdir(AST_LOG_DIR, 0755); - eventlog = fopen(AST_EVENT_LOG, "a"); + mkdir((char *)ast_config_AST_LOG_DIR, 0755); + snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG); + eventlog = fopen((char *)tmp, "a"); ast_pthread_mutex_unlock(&loglock); if (eventlog) { diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index fbcb04a2e9..b37a98f629 100755 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -23,6 +23,7 @@ #include <errno.h> /* For where to put dynamic tables */ #include "../asterisk.h" +#include "../astconf.h" static char *dtext = "Text Extension Configuration"; static char *config = "extensions.conf"; @@ -919,7 +920,7 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) } else /* no config file, default one */ snprintf(filename, sizeof(filename), "%s/%s", - AST_CONFIG_DIR, config); + (char *)ast_config_AST_CONFIG_DIR, config); /* try to lock contexts list */ if (ast_lock_contexts()) { @@ -1463,7 +1464,6 @@ static int pbx_load_module(void) { struct ast_config *cfg; struct ast_variable *v; - char *ptrptr; char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch; struct ast_context *con; @@ -1485,36 +1485,41 @@ static int pbx_load_module(void) v = ast_variable_browse(cfg, cxt); while(v) { if (!strcasecmp(v->name, "exten")) { + char *stringp=NULL; tc = strdup(v->value); - ext = strtok_r(tc, ",",&ptrptr); - if (!ext) - ext=""; - pri = strtok_r(NULL, ",",&ptrptr); - if (!pri) - pri=""; - appl = strtok_r(NULL, ",",&ptrptr); - if (!appl) - appl=""; - if (*ptrptr=='"') { - ptrptr++; - data = strtok_r(NULL, "\"",&ptrptr); - ptrptr++; - } else { - data = strtok_r(NULL, ",",&ptrptr); - } - cidmatch = strchr(ext, '/'); - if (cidmatch) { - *cidmatch = '\0'; - cidmatch++; - } - strtok(ext, "/"); + if(tc!=NULL){ + stringp=tc; + ext = strsep(&stringp, ","); + if (!ext) + ext=""; + pri = strsep(&stringp, ","); + if (!pri) + pri=""; + appl = strsep(&stringp, ","); + if (!appl) + appl=""; + if (stringp!=NULL && *stringp=='"') { + stringp++; + data = strsep(&stringp, "\""); + stringp++; + } else { + data = strsep(&stringp, ","); + } + cidmatch = strchr(ext, '/'); + if (cidmatch) { + *cidmatch = '\0'; + cidmatch++; + } + stringp=ext; + strsep(&stringp, "/"); - if (!data) - data=""; - if (ast_add_extension2(con, 0, ext, atoi(pri), cidmatch, appl, strdup(data), free, registrar)) { - ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); - } - free(tc); + if (!data) + data=""; + if (ast_add_extension2(con, 0, ext, atoi(pri), cidmatch, appl, strdup(data), free, registrar)) { + ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); + } + free(tc); + } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__); } else if(!strcasecmp(v->name, "include")) { if (ast_context_add_include2(con, v->value, registrar)) ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt); @@ -1522,9 +1527,11 @@ static int pbx_load_module(void) if (ast_context_add_ignorepat2(con, v->value, registrar)) ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt); } else if (!strcasecmp(v->name, "switch")) { + char *stringp=NULL; tc = strdup(v->value); - appl = strtok(tc, "/"); - data = strtok(NULL, ""); + stringp=tc; + appl = strsep(&stringp, "/"); + data = strsep(&stringp, ""); if (!data) data = ""; if (ast_context_add_switch2(con, appl, data, registrar)) diff --git a/pbx/pbx_gtkconsole.c b/pbx/pbx_gtkconsole.c index d93ef6fa98..727fe38f38 100755 --- a/pbx/pbx_gtkconsole.c +++ b/pbx/pbx_gtkconsole.c @@ -39,6 +39,7 @@ #include <glib.h> /* For where to put dynamic tables */ #include "../asterisk.h" +#include "../astconf.h" static pthread_mutex_t verb_lock = AST_MUTEX_INITIALIZER; @@ -228,10 +229,12 @@ static void reload_module() static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs) { + char tmp[AST_CONFIG_MAX_PATH]; char *module = gtk_file_selection_get_filename(fs); char buf[256]; - if (!strncmp(module, AST_MODULE_DIR "/", strlen(AST_MODULE_DIR "/"))) - module += strlen(AST_MODULE_DIR "/"); + snprintf((char *)tmp,sizeof(tmp)-1,"%s/",(char *)ast_config_AST_MODULE_DIR); + if (!strncmp(module, (char *)tmp, strlen(tmp))) + module += strlen(tmp); gdk_threads_leave(); if (ast_load_resource(module)) { snprintf(buf, sizeof(buf), "Error loading module '%s'.", module); @@ -246,13 +249,15 @@ static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs) static void add_module() { + char tmp[AST_CONFIG_MAX_PATH]; GtkWidget *filew; + snprintf((char *)tmp,sizeof(tmp)-1,"%s/*.so",(char *)ast_config_AST_MODULE_DIR); filew = gtk_file_selection_new("Load Module"); gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button), "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew); gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew)); - gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), AST_MODULE_DIR "/*.so"); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), (char *)tmp); gtk_widget_show(filew); } diff --git a/pbx/pbx_wilcalu.c b/pbx/pbx_wilcalu.c index a125bd1020..56270733b8 100755 --- a/pbx/pbx_wilcalu.c +++ b/pbx/pbx_wilcalu.c @@ -31,10 +31,11 @@ #include <sys/types.h> #include <sys/stat.h> #include <errno.h> +#include "../astconf.h" // Globals -const char *dialfile="/var/run/autodial.ctl"; +const char dialfile[255]; static char *tdesc = "Wil Cal U (Auto Dialer)"; static pthread_t autodialer_thread; static char buf[257]; @@ -245,6 +246,7 @@ int unload_module(void) int load_module(void) { int val; + snprintf((char *)dialfile,sizeof(dialfile)-1,"%s/%s",(char *)ast_config_AST_RUN_DIR,"autodial.ctl"); if((val=mkfifo(dialfile, 0700))){ if(errno!=EEXIST){ printf("Error:%d Creating Autodial FIFO\n",errno); -- GitLab