aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2009-01-16 15:51:43 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2009-01-16 15:51:43 +0000
commit52acc4c45786fc04da9536c2801eb2b483cc2009 (patch)
tree3e0b68760b7b6d49c72de4fd5b747ed4d5726ad3 /utils
parent5d9d64e584ec5220835eb10a124b555d449fa3d3 (diff)
parentcaebf8461f9849f484eb5bbd649880e457c20e31 (diff)
Creating tag for the release of asterisk-1.4.23-rc4
git-svn-id: http://svn.digium.com/svn/asterisk/tags/1.4.23-rc4@168755 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile132
-rw-r--r--utils/ael_main.c564
-rw-r--r--utils/astman.1102
-rw-r--r--utils/astman.c755
-rw-r--r--utils/check_expr.c355
-rw-r--r--utils/expr2.testinput92
-rw-r--r--utils/frame.c1092
-rw-r--r--utils/frame.h300
-rw-r--r--utils/muted.c709
-rw-r--r--utils/smsq.c768
-rw-r--r--utils/stereorize.c159
-rw-r--r--utils/streamplayer.c124
12 files changed, 5152 insertions, 0 deletions
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644
index 000000000..b52bba7af
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,132 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Various utilities
+#
+# Copyright (C) 1999-2006, Digium
+#
+# Mark Spencer <markster@digium.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+-include ../menuselect.makeopts
+
+.PHONY: clean all uninstall
+
+# to get check_expr, add it to the ALL_UTILS list
+ALL_UTILS:=astman smsq stereorize streamplayer aelparse muted
+UTILS:=$(ALL_UTILS)
+
+include $(ASTTOPDIR)/Makefile.rules
+
+ifeq ($(OSARCH),SunOS)
+ LIBS+=-lsocket -lnsl
+ UTILS:=$(filter-out muted,$(UTILS))
+endif
+
+ifeq ($(OSARCH),OpenBSD)
+ UTILS:=$(filter-out muted,$(UTILS))
+endif
+
+ifeq ($(POPT_LIB),)
+ UTILS:=$(filter-out smsq,$(UTILS))
+endif
+
+ifeq ($(NEWT_LIB),)
+ UTILS:=$(filter-out astman,$(UTILS))
+endif
+
+ifneq ($(filter pbx_ael,$(MENUSELECT_PBX)),)
+ UTILS:=$(filter-out aelparse,$(UTILS))
+endif
+
+all: $(UTILS)
+
+install:
+ for x in $(UTILS); do \
+ if [ "$$x" != "none" ]; then \
+ $(INSTALL) -m 755 $$x $(DESTDIR)$(ASTSBINDIR)/$$x; \
+ fi; \
+ done
+
+uninstall:
+ for x in $(ALL_UTILS); do rm -f $$x $(DESTDIR)$(ASTSBINDIR)/$$x; done
+
+clean:
+ rm -f *.o $(ALL_UTILS) check_expr *.s *.i
+ rm -f .*.d
+ rm -f md5.c strcompat.c ast_expr2.c ast_expr2f.c pbx_ael.c
+ rm -f aelparse.c aelbison.c
+
+md5.c: ../main/md5.c
+ @cp $< $@
+
+astman: astman.o md5.o
+astman: LIBS+=$(NEWT_LIB)
+astman.o: ASTCFLAGS+=-DNO_MALLOC_DEBUG
+
+stereorize: stereorize.o frame.o
+stereorize: LIBS+=-lm
+
+strcompat.c: ../main/strcompat.c
+ @cp $< $@
+
+../main/ast_expr2.c:
+ @echo " [BISON] ../main/ast_expr2.y -> $@"
+ @bison -o $@ -d --name-prefix=ast_yy ../main/ast_expr2.y
+
+../main/ast_expr2f.c:
+ @echo " [FLEX] ../main/ast_expr2.fl -> $@"
+ @flex -o $@ --full ../main/ast_expr2.fl
+
+ast_expr2.c: ../main/ast_expr2.c
+ @cp $< $@
+
+ast_expr2.o: ASTCFLAGS+=-DSTANDALONE_AEL
+
+ast_expr2f.c: ../main/ast_expr2f.c
+ @cp $< $@
+
+ast_expr2f.o: ASTCFLAGS+=-DSTANDALONE_AEL -I../main -Wno-unused
+
+check_expr: check_expr.o ast_expr2.o ast_expr2f.o
+
+aelbison.c: ../pbx/ael/ael.tab.c
+ @cp $< $@
+aelbison.o: aelbison.c ../pbx/ael/ael.tab.h ../include/asterisk/ael_structs.h
+aelbison.o: ASTCFLAGS+=-I../pbx -DSTANDALONE_AEL
+
+pbx_ael.c: ../pbx/pbx_ael.c
+ @cp $< $@
+pbx_ael.o: ASTCFLAGS+=-DSTANDALONE_AEL
+
+ael_main.o: ael_main.c ../include/asterisk/ael_structs.h
+ael_main.o: ASTCFLAGS+=-DSTANDALONE_AEL
+
+aelparse.c: ../pbx/ael/ael_lex.c
+ @cp $< $@
+aelparse.o: aelparse.c ../include/asterisk/ael_structs.h ../pbx/ael/ael.tab.h
+aelparse.o: ASTCFLAGS+=-I../pbx -DSTANDALONE_AEL -Wno-unused
+
+aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o
+
+testexpr2s: ../main/ast_expr2f.c ../main/ast_expr2.c ../main/ast_expr2.h
+ $(CC) -g -c -I../include -DSTANDALONE_AEL ../main/ast_expr2f.c -o ast_expr2f.o
+ $(CC) -g -c -I../include -DSTANDALONE_AEL ../main/ast_expr2.c -o ast_expr2.o
+ $(CC) -g -o testexpr2s ast_expr2f.o ast_expr2.o
+ rm ast_expr2.o ast_expr2f.o
+ ./testexpr2s expr2.testinput
+
+smsq: smsq.o strcompat.o
+smsq: LIBS+=$(POPT_LIB)
+
+streamplayer: streamplayer.o
+
+muted: muted.o
+muted: LIBS+=$(AUDIO_LIBS)
+
+ifneq ($(wildcard .*.d),)
+ include .*.d
+endif
diff --git a/utils/ael_main.c b/utils/ael_main.c
new file mode 100644
index 000000000..85a2cc835
--- /dev/null
+++ b/utils/ael_main.c
@@ -0,0 +1,564 @@
+#include "asterisk.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#include <errno.h>
+#include <regex.h>
+#include <limits.h>
+
+#include "asterisk/ast_expr.h"
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/app.h"
+#include "asterisk/ael_structs.h"
+
+/*** MODULEINFO
+ <depend>pbx_ael</depend>
+ ***/
+
+struct namelist
+{
+ char name[100];
+ char name2[100];
+ struct namelist *next;
+};
+
+struct ast_context
+{
+ int extension_count;
+ char name[100];
+ char registrar[100];
+ struct namelist *includes;
+ struct namelist *ignorepats;
+ struct namelist *switches;
+ struct namelist *eswitches;
+
+ struct namelist *includes_last;
+ struct namelist *ignorepats_last;
+ struct namelist *switches_last;
+ struct namelist *eswitches_last;
+
+ struct ast_context *next;
+};
+
+#define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
+
+void destroy_namelist(struct namelist *x);
+void destroy_namelist(struct namelist *x)
+{
+ struct namelist *z,*z2;
+ for(z=x; z; z = z2)
+ {
+ z2 = z->next;
+ z->next = 0;
+ free(z);
+ }
+}
+
+struct namelist *create_name(const char *name);
+struct namelist *create_name(const char *name)
+{
+ struct namelist *x = calloc(1, sizeof(*x));
+ if (!x)
+ return NULL;
+ strncpy(x->name, name, sizeof(x->name) - 1);
+ return x;
+}
+
+struct ast_context *context_list;
+struct ast_context *last_context;
+struct namelist *globalvars;
+struct namelist *globalvars_last;
+
+int conts=0, extens=0, priors=0;
+char last_exten[18000];
+char ast_config_AST_CONFIG_DIR[PATH_MAX];
+char ast_config_AST_VAR_DIR[PATH_MAX];
+
+void ast_cli_register_multiple(void);
+int ast_add_extension2(struct ast_context *con,
+ int replace, const char *extension, int priority, const char *label, const char *callerid,
+ const char *application, void *data, void (*datad)(void *),
+ const char *registrar);
+void pbx_builtin_setvar(void *chan, void *data);
+struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar);
+struct ast_context * ast_context_find_or_create(void **extcontexts, const char *name, const char *registrar);
+void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
+void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar);
+void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar);
+void ast_merge_contexts_and_delete(void);
+void ast_context_verify_includes(void);
+struct ast_context * ast_walk_contexts(void);
+void ast_cli_unregister_multiple(void);
+void ast_context_destroy(void);
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...);
+char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
+void ast_verbose(const char *fmt, ...);
+struct ast_app *pbx_findapp(const char *app);
+void filter_leading_space_from_exprs(char *str);
+void filter_newlines(char *str);
+static int quiet = 0;
+static int no_comp = 0;
+static int use_curr_dir = 0;
+static int dump_extensions = 0;
+static int FIRST_TIME = 0;
+static FILE *dumpfile;
+
+struct ast_app *pbx_findapp(const char *app)
+{
+ return (struct ast_app*)1; /* so as not to trigger an error */
+}
+
+int ast_loader_register(int (*updater)(void))
+{
+ return 1;
+}
+
+int ast_loader_unregister(int (*updater)(void))
+{
+ return 1;
+}
+void ast_module_register(const struct ast_module_info *x)
+{
+}
+
+void ast_module_unregister(const struct ast_module_info *x)
+{
+}
+
+
+void ast_cli_register_multiple(void)
+{
+ if(!no_comp)
+ printf("Executed ast_cli_register_multiple();\n");
+}
+
+void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
+void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
+{
+ if (cp1 && *cp1)
+ strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for
+ a possible var substitution on extension names,
+ so....! */
+ else
+ *cp2 = 0;
+}
+
+int ast_add_extension2(struct ast_context *con,
+ int replace, const char *extension, int priority, const char *label, const char *callerid,
+ const char *application, void *data, void (*datad)(void *),
+ const char *registrar)
+{
+ priors++;
+ con->extension_count++;
+ if (strcmp(extension,last_exten) != 0) {
+ extens++;
+ strcpy(last_exten, extension);
+ }
+ if (!label) {
+ label = "(null)";
+ }
+ if (!callerid) {
+ callerid = "(null)";
+ }
+ if (!application) {
+ application = "(null)";
+ }
+
+ if(!no_comp)
+ printf("Executed ast_add_extension2(context=%s, rep=%d, exten=%s, priority=%d, label=%s, callerid=%s, appl=%s, data=%s, FREE, registrar=%s);\n",
+ con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
+
+ if( dump_extensions && dumpfile ) {
+ struct namelist *n;
+ char *data2,*data3=0;
+ int commacount = 0;
+
+ if( FIRST_TIME ) {
+ FIRST_TIME = 0;
+
+ if( globalvars )
+ fprintf(dumpfile,"[globals]\n");
+
+ for(n=globalvars;n;n=n->next) {
+ fprintf(dumpfile, "%s\n", n->name);
+ }
+ }
+
+ /* print out each extension , possibly the context header also */
+ if( con != last_context ) {
+ fprintf(dumpfile,"\n\n[%s]\n", con->name);
+ last_context = con;
+ for(n=con->ignorepats;n;n=n->next) {
+ fprintf(dumpfile, "ignorepat => %s\n", n->name);
+ }
+ for(n=con->includes;n;n=n->next) {
+ fprintf(dumpfile, "include => %s\n", n->name);
+ }
+ for(n=con->switches;n;n=n->next) {
+ fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
+ }
+ for(n=con->eswitches;n;n=n->next) {
+ fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
+ }
+
+ }
+ if( data ) {
+ filter_newlines((char*)data);
+ filter_leading_space_from_exprs((char*)data);
+
+ /* compiling turns commas into vertical bars in the app data, and also removes the backslash from before escaped commas;
+ we have to restore the escaping backslash in front of any commas; the vertical bars are OK to leave as-is */
+ for (data2 = data; *data2; data2++) {
+ if (*data2 == ',')
+ commacount++; /* we need to know how much bigger the string will grow-- one backslash for each comma */
+ }
+ if (commacount)
+ {
+ char *d3,*d4;
+
+ data2 = (char*)malloc(strlen(data)+commacount+1);
+ data3 = data;
+ d3 = data;
+ d4 = data2;
+ while (*d3) {
+ if (*d3 == ',') {
+ *d4++ = '\\'; /* put a backslash in front of each comma */
+ *d4++ = *d3++;
+ } else
+ *d4++ = *d3++; /* or just copy the char */
+ }
+ *d4++ = 0; /* cap off the new string */
+ data = data2;
+ } else
+ data2 = 0;
+
+ if( strcmp(label,"(null)") != 0 )
+ fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
+ else
+ fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
+
+ if (data2) {
+ free(data2);
+ data2 = 0;
+ data = data3; /* restore data to pre-messedup state */
+ }
+
+ } else {
+
+ if( strcmp(label,"(null)") != 0 )
+ fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
+ else
+ fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
+ }
+ }
+
+ /* since add_extension2 is responsible for the malloc'd data stuff */
+ if( data )
+ free(data);
+ return 0;
+}
+
+void pbx_builtin_setvar(void *chan, void *data)
+{
+ struct namelist *x = create_name(data);
+ if(!no_comp)
+ printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
+
+ if( dump_extensions ) {
+ x = create_name(data);
+ ADD_LAST(globalvars,x);
+ }
+}
+
+
+struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
+{
+ struct ast_context *x = calloc(1, sizeof(*x));
+ if (!x)
+ return NULL;
+ x->next = context_list;
+ context_list = x;
+ if (!no_comp)
+ printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
+ conts++;
+ strncpy(x->name, name, sizeof(x->name) - 1);
+ strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
+ return x;
+}
+
+struct ast_context * ast_context_find_or_create(void **extcontexts, const char *name, const char *registrar)
+{
+ struct ast_context *x = calloc(1, sizeof(*x));
+ if (!x)
+ return NULL;
+ x->next = context_list;
+ context_list = x;
+ if (!no_comp)
+ printf("Executed ast_context_find_or_create(conts, name=%s, registrar=%s);\n", name, registrar);
+ conts++;
+ strncpy(x->name, name, sizeof(x->name) - 1);
+ strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
+ return x;
+}
+
+void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
+{
+ if(!no_comp)
+ printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
+ if( dump_extensions ) {
+ struct namelist *x;
+ x = create_name(value);
+ ADD_LAST(con->ignorepats,x);
+ }
+}
+
+void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
+{
+ if(!no_comp)
+ printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
+ if( dump_extensions ) {
+ struct namelist *x;
+ x = create_name((char*)value);
+ ADD_LAST(con->includes,x);
+ }
+}
+
+void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
+{
+ if(!no_comp)
+ printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
+ if( dump_extensions ) {
+ struct namelist *x;
+ x = create_name((char*)value);
+ strncpy(x->name2,data,100);
+ if( eval ) {
+
+ ADD_LAST(con->switches,x);
+
+ } else {
+
+ ADD_LAST(con->eswitches,x);
+ }
+ }
+}
+
+void ast_merge_contexts_and_delete(void)
+{
+ if(!no_comp)
+ printf("Executed ast_merge_contexts_and_delete();\n");
+}
+
+void ast_context_verify_includes(void)
+{
+ if(!no_comp)
+ printf("Executed ast_context_verify_includes();\n");
+}
+
+struct ast_context * ast_walk_contexts(void)
+{
+ if(!no_comp)
+ printf("Executed ast_walk_contexts();\n");
+ return 0;
+}
+
+void ast_cli_unregister_multiple(void)
+{
+ if(!no_comp)
+ printf("Executed ast_cli_unregister_multiple();\n");
+}
+
+void ast_context_destroy(void)
+{
+ if( !no_comp)
+ printf("Executed ast_context_destroy();\n");
+}
+
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+ va_list vars;
+ va_start(vars,fmt);
+ if( !quiet || level > 2 ) {
+ printf("LOG: lev:%d file:%s line:%d func: %s ",
+ level, file, line, function);
+ vprintf(fmt, vars);
+ fflush(stdout);
+ va_end(vars);
+ }
+}
+
+void ast_verbose(const char *fmt, ...)
+{
+ va_list vars;
+ va_start(vars,fmt);
+
+ printf("VERBOSE: ");
+ vprintf(fmt, vars);
+ fflush(stdout);
+ va_end(vars);
+}
+
+char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
+{
+ char *dataPut = start;
+ int inEscape = 0;
+ int inQuotes = 0;
+
+ for (; *start; start++) {
+ if (inEscape) {
+ *dataPut++ = *start; /* Always goes verbatim */
+ inEscape = 0;
+ } else {
+ if (*start == '\\') {
+ inEscape = 1; /* Do not copy \ into the data */
+ } else if (*start == '\'') {
+ inQuotes = 1-inQuotes; /* Do not copy ' into the data */
+ } else {
+ /* Replace , with |, unless in quotes */
+ *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
+ }
+ }
+ }
+ if (start != dataPut)
+ *dataPut = 0;
+ return dataPut;
+}
+
+void filter_leading_space_from_exprs(char *str)
+{
+ /* Mainly for aesthetics */
+ char *t, *v, *u = str;
+
+ while ( u && *u ) {
+
+ if( *u == '$' && *(u+1) == '[' ) {
+ t = u+2;
+ while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
+ v = t;
+ while ( *v ) {
+ *v = *(v+1);
+ v++;
+ }
+ }
+ }
+
+ u++;
+ }
+}
+
+void filter_newlines(char *str)
+{
+ /* remove all newlines, returns */
+ char *t=str;
+ while( t && *t ) {
+ if( *t == '\n' || *t == '\r' ) {
+ *t = ' '; /* just replace newlines and returns with spaces; they act as
+ token separators, and just blindly removing them could be
+ harmful. */
+ }
+ t++;
+ }
+}
+
+
+extern struct module_symbols mod_data;
+extern int ael_external_load_module(void);
+
+int main(int argc, char **argv)
+{
+ int i;
+ struct namelist *n;
+ struct ast_context *lp,*lp2;
+
+ for(i=1;i<argc;i++) {
+ if( argv[i][0] == '-' && argv[i][1] == 'n' )
+ no_comp =1;
+ if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
+ quiet = 1;
+ no_comp =1;
+ }
+ if( argv[i][0] == '-' && argv[i][1] == 'd' )
+ use_curr_dir =1;
+ if( argv[i][0] == '-' && argv[i][1] == 'w' )
+ dump_extensions =1;
+ }
+
+ if( !quiet ) {
+ printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
+ if( !no_comp )
+ printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
+ if( !use_curr_dir )
+ printf("\n(You can use the -d option if you want to use the current working directory as the CONFIG_DIR. I will look in this dir for extensions.ael* and its included files)\n\n");
+ if( !dump_extensions )
+ printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
+ }
+
+ if( use_curr_dir ) {
+ strcpy(ast_config_AST_CONFIG_DIR, ".");
+ }
+ else {
+ strcpy(ast_config_AST_CONFIG_DIR, "/etc/asterisk");
+ }
+ strcpy(ast_config_AST_VAR_DIR, "/var/lib/asterisk");
+
+ if( dump_extensions ) {
+ dumpfile = fopen("extensions.conf.aeldump","w");
+ if( !dumpfile ) {
+ printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
+ exit(10);
+ }
+
+ }
+
+ FIRST_TIME = 1;
+
+ ael_external_load_module();
+
+ ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
+
+ if( dump_extensions && dumpfile ) {
+
+ for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
+ extensions in them */
+ if( lp->extension_count == 0 ) {
+
+ fprintf(dumpfile,"\n\n[%s]\n", lp->name);
+
+ for(n=lp->ignorepats;n;n=n->next) {
+ fprintf(dumpfile, "ignorepat => %s\n", n->name);
+ }
+ for(n=lp->includes;n;n=n->next) {
+ fprintf(dumpfile, "include => %s\n", n->name);
+ }
+ for(n=lp->switches;n;n=n->next) {
+ fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
+ }
+ for(n=lp->eswitches;n;n=n->next) {
+ fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
+ }
+ }
+ }
+ }
+
+ if( dump_extensions && dumpfile )
+ fclose(dumpfile);
+
+ for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
+ lp2 = lp->next;
+ lp->next = 0;
+
+ destroy_namelist(lp->includes);
+ destroy_namelist(lp->ignorepats);
+ destroy_namelist(lp->switches);
+ destroy_namelist(lp->eswitches);
+
+ free(lp);
+ }
+
+ return 0;
+}
diff --git a/utils/astman.1 b/utils/astman.1
new file mode 100644
index 000000000..6a36ca4da
--- /dev/null
+++ b/utils/astman.1
@@ -0,0 +1,102 @@
+.\" $Header$
+.\"
+.\" transcript compatibility for postscript use.
+.\"
+.\" synopsis: .P! <file.ps>
+.\"
+.de P!
+.fl
+\!!1 setgray
+.fl
+\\&.\"
+.fl
+\!!0 setgray
+.fl \" force out current output buffer
+\!!save /psv exch def currentpoint translate 0 0 moveto
+\!!/showpage{}def
+.fl \" prolog
+.sy sed \-e 's/^/!/' \\$1\" bring in postscript file
+\!!psv restore
+.
+.de pF
+.ie \\*(f1 .ds f1 \\n(.f
+.el .ie \\*(f2 .ds f2 \\n(.f
+.el .ie \\*(f3 .ds f3 \\n(.f
+.el .ie \\*(f4 .ds f4 \\n(.f
+.el .tm ? font overflow
+.ft \\$1
+..
+.de fP
+.ie !\\*(f4 \{\
+. ft \\*(f4
+. ds f4\"
+' br \}
+.el .ie !\\*(f3 \{\
+. ft \\*(f3
+. ds f3\"
+' br \}
+.el .ie !\\*(f2 \{\
+. ft \\*(f2
+. ds f2\"
+' br \}
+.el .ie !\\*(f1 \{\
+. ft \\*(f1
+. ds f1\"
+' br \}
+.el .tm ? font underflow
+..
+.ds f1\"
+.ds f2\"
+.ds f3\"
+.ds f4\"
+'\" t
+.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+.TH ASTMAN 1 "Jun 12th, 2005" "astman" "Linux Programmer's Manual"
+.SH NAME
+.B astman
+-- a client to asterisk's manager interface
+.SH SYNOPSIS
+.PP
+.B astman
+.I hostname
+
+.SH DESCRIPTION
+.B astman
+This program is a full-screen (terminal) client for Asterisk's manager
+interface.
+
+.SH OPTIONS
+.B hostname
+
+The host name or IP address to connect to (TCP port 5038). If astman
+fails to connect it will exit immidiately.
+
+.SH USAGE
+If \fBastman\fR has successfully cunnected to the manager port it will
+prompt the user for a username and a secret (password) for the manager
+interface on the remote Asterisk manager interface. It will then be able
+to report existing channels (calls). You will then be able to redirect
+calls to or terminate them.
+
+.SH "SEE ALSO"
+asterisk(8)
+
+http://www.voip-info.org/wiki-Asterisk+astman
+
+.SH BUGS
+The hostname does not default to localhost.
+
+Impossible to use a port other than 5038.
+
+The username and password cannot be defined from the command-line.
+
+I mean, what's the point in a man page if the syntax is so simple?
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/utils/astman.c b/utils/astman.c
new file mode 100644
index 000000000..ae2444ae7
--- /dev/null
+++ b/utils/astman.c
@@ -0,0 +1,755 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*
+ *
+ * ASTerisk MANager
+ *
+ */
+
+#include "asterisk.h"
+
+#include <newt.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "asterisk/md5.h"
+#include "asterisk/linkedlists.h"
+
+#undef gethostbyname
+
+#define MAX_HEADERS 80
+#define MAX_LEN 256
+
+/*
+ * 2005.05.27 - different versions of newt define the type of the buffer
+ * for the 5th argument to newtEntry() as char ** or const char ** . To
+ * let the code compile cleanly with -Werror, we cast it to void * through
+ * _NEWT_CAST.
+ */
+#define _NEWT_CAST (void *)
+
+#define DEFAULT_MANAGER_PORT 5038
+
+struct message {
+ unsigned int hdrcount;
+ char headers[MAX_HEADERS][MAX_LEN];
+};
+
+static struct ast_mansession {
+ struct sockaddr_in sin;
+ int fd;
+ char inbuf[MAX_LEN];
+ int inlen;
+} session;
+
+struct ast_chan {
+ char name[80];
+ char exten[20];
+ char context[20];
+ char priority[20];
+ char callerid[40];
+ char state[10];
+ AST_LIST_ENTRY(ast_chan) list;
+};
+
+static AST_LIST_HEAD_NOLOCK_STATIC(chans, ast_chan);
+
+/* dummy functions to be compatible with the Asterisk core for md5.c */
+void ast_register_file_version(const char *file, const char *version);
+void ast_register_file_version(const char *file, const char *version)
+{
+}
+
+void ast_unregister_file_version(const char *file);
+void ast_unregister_file_version(const char *file)
+{
+}
+
+int ast_add_profile(const char *, uint64_t scale);
+int ast_add_profile(const char *s, uint64_t scale)
+{
+ return -1;
+}
+
+int64_t ast_profile(int, int64_t);
+int64_t ast_profile(int key, int64_t val)
+{
+ return 0;
+}
+int64_t ast_mark(int, int start1_stop0);
+int64_t ast_mark(int key, int start1_stop0)
+{
+ return 0;
+}
+
+/* end of dummy functions */
+
+static struct ast_chan *find_chan(char *name)
+{
+ struct ast_chan *chan;
+ AST_LIST_TRAVERSE(&chans, chan, list) {
+ if (!strcmp(name, chan->name))
+ return chan;
+ }
+ chan = malloc(sizeof(struct ast_chan));
+ if (chan) {
+ memset(chan, 0, sizeof(struct ast_chan));
+ strncpy(chan->name, name, sizeof(chan->name) - 1);
+ AST_LIST_INSERT_TAIL(&chans, chan, list);
+ }
+ return chan;
+}
+
+static void del_chan(char *name)
+{
+ struct ast_chan *chan;
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&chans, chan, list) {
+ if (!strcmp(name, chan->name)) {
+ AST_LIST_REMOVE_CURRENT(&chans, list);
+ free(chan);
+ return;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+}
+
+static void __attribute__((format(printf, 2, 3))) fdprintf(int fd, char *fmt, ...)
+{
+ char stuff[4096];
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ vsnprintf(stuff, sizeof(stuff), fmt, ap);
+ va_end(ap);
+ if ((res = write(fd, stuff, strlen(stuff))) < 0) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ }
+}
+
+static char *get_header(struct message *m, char *var)
+{
+ char cmp[80];
+ int x;
+ snprintf(cmp, sizeof(cmp), "%s: ", var);
+ for (x=0;x<m->hdrcount;x++)
+ if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
+ return m->headers[x] + strlen(cmp);
+ return "";
+}
+
+static int event_newstate(struct ast_mansession *s, struct message *m)
+{
+ struct ast_chan *chan;
+ chan = find_chan(get_header(m, "Channel"));
+ strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
+ return 0;
+}
+
+static int event_newexten(struct ast_mansession *s, struct message *m)
+{
+ struct ast_chan *chan;
+ chan = find_chan(get_header(m, "Channel"));
+ strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
+ strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
+ strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
+ return 0;
+}
+
+static int event_newchannel(struct ast_mansession *s, struct message *m)
+{
+ struct ast_chan *chan;
+ chan = find_chan(get_header(m, "Channel"));
+ strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
+ strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
+ return 0;
+}
+
+static int event_status(struct ast_mansession *s, struct message *m)
+{
+ struct ast_chan *chan;
+ chan = find_chan(get_header(m, "Channel"));
+ strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
+ strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
+ strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
+ strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
+ strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
+ return 0;
+}
+
+static int event_hangup(struct ast_mansession *s, struct message *m)
+{
+ del_chan(get_header(m, "Channel"));
+ return 0;
+}
+
+static int event_ignore(struct ast_mansession *s, struct message *m)
+{
+ return 0;
+}
+
+static int event_rename(struct ast_mansession *s, struct message *m)
+{
+ struct ast_chan *chan;
+ chan = find_chan(get_header(m, "Oldname"));
+ strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
+ return 0;
+}
+static struct event {
+ char *event;
+ int (*func)(struct ast_mansession *s, struct message *m);
+} events[] = {
+ { "Newstate", event_newstate },
+ { "Newchannel", event_newchannel },
+ { "Newexten", event_newexten },
+ { "Hangup", event_hangup },
+ { "Rename", event_rename },
+ { "Status", event_status },
+ { "Link", event_ignore },
+ { "Unlink", event_ignore },
+ { "StatusComplete", event_ignore }
+};
+
+static int process_message(struct ast_mansession *s, struct message *m)
+{
+ int x;
+ char event[80] = "";
+ strncpy(event, get_header(m, "Event"), sizeof(event) - 1);
+ if (!strlen(event)) {
+ fprintf(stderr, "Missing event in request");
+ return 0;
+ }
+ for (x=0;x<sizeof(events) / sizeof(events[0]);x++) {
+ if (!strcasecmp(event, events[x].event)) {
+ if (events[x].func(s, m))
+ return -1;
+ break;
+ }
+ }
+ if (x >= sizeof(events) / sizeof(events[0]))
+ fprintf(stderr, "Ignoring unknown event '%s'", event);
+#if 0
+ for (x=0;x<m->hdrcount;x++) {
+ printf("Header: %s\n", m->headers[x]);
+ }
+#endif
+ return 0;
+}
+
+static void rebuild_channels(newtComponent c)
+{
+ void *prev = NULL;
+ struct ast_chan *chan;
+ char tmpn[42];
+ char tmp[256];
+ int x=0;
+ prev = newtListboxGetCurrent(c);
+ newtListboxClear(c);
+ AST_LIST_TRAVERSE(&chans, chan, list) {
+ snprintf(tmpn, sizeof(tmpn), "%s (%s)", chan->name, chan->callerid);
+ if (strlen(chan->exten))
+ snprintf(tmp, sizeof(tmp), "%-30s %8s -> %s@%s:%s",
+ tmpn, chan->state,
+ chan->exten, chan->context, chan->priority);
+ else
+ snprintf(tmp, sizeof(tmp), "%-30s %8s",
+ tmpn, chan->state);
+ newtListboxAppendEntry(c, tmp, chan);
+ x++;
+ }
+ if (!x)
+ newtListboxAppendEntry(c, " << No Active Channels >> ", NULL);
+ newtListboxSetCurrentByKey(c, prev);
+}
+
+static int has_input(struct ast_mansession *s)
+{
+ int x;
+ for (x=1;x<s->inlen;x++)
+ if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r'))
+ return 1;
+ return 0;
+}
+
+static int get_input(struct ast_mansession *s, char *output)
+{
+ /* output must have at least sizeof(s->inbuf) space */
+ int res;
+ int x;
+ struct timeval tv = {0, 0};
+ fd_set fds;
+ for (x=1;x<s->inlen;x++) {
+ if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
+ /* Copy output data up to and including \r\n */
+ memcpy(output, s->inbuf, x + 1);
+ /* Add trailing \0 */
+ output[x+1] = '\0';
+ /* Move remaining data back to the front */
+ memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
+ s->inlen -= (x + 1);
+ return 1;
+ }
+ }
+ if (s->inlen >= sizeof(s->inbuf) - 1) {
+ fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
+ s->inlen = 0;
+ }
+ FD_ZERO(&fds);
+ FD_SET(s->fd, &fds);
+ res = select(s->fd + 1, &fds, NULL, NULL, &tv);
+ if (res < 0) {
+ fprintf(stderr, "Select returned error: %s\n", strerror(errno));
+ } else if (res > 0) {
+ res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
+ if (res < 1)
+ return -1;
+ s->inlen += res;
+ s->inbuf[s->inlen] = '\0';
+ } else {
+ return 2;
+ }
+ return 0;
+}
+
+static int input_check(struct ast_mansession *s, struct message **mout)
+{
+ static struct message m;
+ int res;
+
+ if (mout)
+ *mout = NULL;
+
+ for(;;) {
+ res = get_input(s, m.headers[m.hdrcount]);
+ if (res == 1) {
+#if 0
+ fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
+ fgetc(stdin);
+#endif
+ /* Strip trailing \r\n */
+ if (strlen(m.headers[m.hdrcount]) < 2)
+ continue;
+ m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
+ if (!strlen(m.headers[m.hdrcount])) {
+ if (mout && strlen(get_header(&m, "Response"))) {
+ *mout = &m;
+ return 0;
+ }
+ if (process_message(s, &m))
+ break;
+ memset(&m, 0, sizeof(&m));
+ } else if (m.hdrcount < MAX_HEADERS - 1)
+ m.hdrcount++;
+ } else if (res < 0) {
+ return -1;
+ } else if (res == 2)
+ return 0;
+ }
+ return -1;
+}
+
+static struct message *wait_for_response(int timeout)
+{
+ struct message *m;
+ struct timeval tv;
+ int res;
+ fd_set fds;
+ for (;;) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ FD_SET(session.fd, &fds);
+ res = select(session.fd + 1, &fds, NULL, NULL, &tv);
+ if (res < 1)
+ break;
+ if (input_check(&session, &m) < 0) {
+ return NULL;
+ }
+ if (m)
+ return m;
+ }
+ return NULL;
+}
+
+static int __attribute__((format(printf, 2, 3))) manager_action(char *action, char *fmt, ...)
+{
+ struct ast_mansession *s;
+ char tmp[4096];
+ va_list ap;
+ int res;
+
+ s = &session;
+ fdprintf(s->fd, "Action: %s\r\n", action);
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+ if ((res = write(s->fd, tmp, strlen(tmp))) < 0) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ }
+ fdprintf(s->fd, "\r\n");
+ return 0;
+}
+
+static int show_message(char *title, char *msg)
+{
+ newtComponent form;
+ newtComponent label;
+ newtComponent ok;
+ struct newtExitStruct es;
+
+ newtCenteredWindow(60,7, title);
+
+ label = newtLabel(4,1,msg);
+ ok = newtButton(27, 3, "OK");
+ form = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(form, label, ok, NULL);
+ newtFormRun(form, &es);
+ newtPopWindow();
+ newtFormDestroy(form);
+ return 0;
+}
+
+static newtComponent showform;
+static int show_doing(char *title, char *tmp)
+{
+ struct newtExitStruct es;
+ newtComponent label;
+ showform = newtForm(NULL, NULL, 0);
+ newtCenteredWindow(70,4, title);
+ label = newtLabel(3,1,tmp);
+ newtFormAddComponents(showform,label, NULL);
+ newtFormSetTimer(showform, 200);
+ newtFormRun(showform, &es);
+ return 0;
+}
+
+static int hide_doing(void)
+{
+ newtPopWindow();
+ newtFormDestroy(showform);
+ return 0;
+}
+
+static void try_status(void)
+{
+ struct message *m;
+ manager_action("Status", "%s", "");
+ m = wait_for_response(10000);
+ if (!m) {
+ show_message("Status Failed", "Timeout waiting for response");
+ } else if (strcasecmp(get_header(m, "Response"), "Success")) {
+ show_message("Status Failed Failed", get_header(m, "Message"));
+ }
+}
+
+
+static void try_hangup(newtComponent c)
+{
+ struct ast_chan *chan;
+ struct message *m;
+
+ chan = newtListboxGetCurrent(c);
+ if (chan) {
+ manager_action("Hangup", "Channel: %s\r\n", chan->name);
+ m = wait_for_response(10000);
+ if (!m) {
+ show_message("Hangup Failed", "Timeout waiting for response");
+ } else if (strcasecmp(get_header(m, "Response"), "Success")) {
+ show_message("Hangup Failed", get_header(m, "Message"));
+ }
+ }
+
+}
+
+static int get_user_input(char *msg, char *buf, int buflen)
+{
+ newtComponent form;
+ newtComponent ok;
+ newtComponent cancel;
+ newtComponent inpfield;
+ const char *input;
+ int res = -1;
+ struct newtExitStruct es;
+
+ newtCenteredWindow(60,7, msg);
+
+ inpfield = newtEntry(5, 2, "", 50, _NEWT_CAST &input, 0);
+ ok = newtButton(22, 3, "OK");
+ cancel = newtButton(32, 3, "Cancel");
+ form = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(form, inpfield, ok, cancel, NULL);
+ newtFormRun(form, &es);
+ strncpy(buf, input, buflen - 1);
+ if (es.u.co == ok)
+ res = 0;
+ else
+ res = -1;
+ newtPopWindow();
+ newtFormDestroy(form);
+ return res;
+}
+
+static void try_redirect(newtComponent c)
+{
+ struct ast_chan *chan;
+ char dest[256];
+ struct message *m;
+ char channame[256];
+ char tmp[80];
+ char *context;
+
+ chan = newtListboxGetCurrent(c);
+ if (chan) {
+ strncpy(channame, chan->name, sizeof(channame) - 1);
+ snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
+ if (get_user_input(tmp, dest, sizeof(dest)))
+ return;
+ if ((context = strchr(dest, '@'))) {
+ *context = '\0';
+ context++;
+ manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest);
+ } else {
+ manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest);
+ }
+ m = wait_for_response(10000);
+ if (!m) {
+ show_message("Hangup Failed", "Timeout waiting for response");
+ } else if (strcasecmp(get_header(m, "Response"), "Success")) {
+ show_message("Hangup Failed", get_header(m, "Message"));
+ }
+ }
+
+}
+
+static int manage_calls(char *host)
+{
+ newtComponent form;
+ newtComponent quit;
+ newtComponent hangup;
+ newtComponent redirect;
+ newtComponent channels;
+ struct newtExitStruct es;
+ char tmp[80];
+
+ /* Mark: If there's one thing you learn from this code, it is this...
+ Never, ever fly Air France. Their customer service is absolutely
+ the worst. I've never heard the words "That's not my problem" as
+ many times as I have from their staff -- It should, without doubt
+ be their corporate motto if it isn't already. Don't bother giving
+ them business because you're just a pain in their side and they
+ will be sure to let you know the first time you speak to them.
+
+ If you ever want to make me happy just tell me that you, too, will
+ never fly Air France again either (in spite of their excellent
+ cuisine).
+
+ Update by oej: The merger with KLM has transferred this
+ behaviour to KLM as well.
+ Don't bother giving them business either...
+
+ Only if you want to travel randomly without luggage, you
+ might pick either of them.
+
+ */
+ snprintf(tmp, sizeof(tmp), "Asterisk Manager at %s", host);
+ newtCenteredWindow(74, 20, tmp);
+ form = newtForm(NULL, NULL, 0);
+ newtFormWatchFd(form, session.fd, NEWT_FD_READ);
+ newtFormSetTimer(form, 100);
+ quit = newtButton(62, 16, "Quit");
+ redirect = newtButton(35, 16, "Redirect");
+ hangup = newtButton(50, 16, "Hangup");
+ channels = newtListbox(1,1,14, NEWT_FLAG_SCROLL);
+ newtFormAddComponents(form, channels, redirect, hangup, quit, NULL);
+ newtListboxSetWidth(channels, 72);
+
+ show_doing("Getting Status", "Retrieving system status...");
+ try_status();
+ hide_doing();
+
+ for(;;) {
+ newtFormRun(form, &es);
+ if (has_input(&session) || (es.reason == NEWT_EXIT_FDREADY)) {
+ if (input_check(&session, NULL)) {
+ show_message("Disconnected", "Disconnected from remote host");
+ break;
+ }
+ } else if (es.reason == NEWT_EXIT_COMPONENT) {
+ if (es.u.co == quit)
+ break;
+ if (es.u.co == hangup) {
+ try_hangup(channels);
+ } else if (es.u.co == redirect) {
+ try_redirect(channels);
+ }
+ }
+ rebuild_channels(channels);
+ }
+ newtFormDestroy(form);
+ return 0;
+}
+
+static int login(char *hostname)
+{
+ newtComponent form;
+ newtComponent cancel;
+ newtComponent login;
+ newtComponent username;
+ newtComponent password;
+ newtComponent label;
+ newtComponent ulabel;
+ newtComponent plabel;
+ const char *user;
+ const char *pass;
+ struct message *m;
+ struct newtExitStruct es;
+ char tmp[55];
+ struct hostent *hp;
+ int res = -1;
+
+ session.fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (session.fd < 0) {
+ snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
+ show_message("Socket failed", tmp);
+ return -1;
+ }
+
+ snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
+ show_doing("Connecting....", tmp);
+
+
+ hp = gethostbyname(hostname);
+ if (!hp) {
+ snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
+ show_message("Host lookup failed", tmp);
+ return -1;
+ }
+ hide_doing();
+ snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
+ show_doing("Connecting...", tmp);
+
+ session.sin.sin_family = AF_INET;
+ session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
+ memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
+
+ if (connect(session.fd,(struct sockaddr*)&session.sin, sizeof(session.sin))) {
+ snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
+ show_message("Connect Failed", tmp);
+ return -1;
+ }
+
+ hide_doing();
+
+ login = newtButton(5, 6, "Login");
+ cancel = newtButton(25, 6, "Cancel");
+ newtCenteredWindow(40, 10, "Asterisk Manager Login");
+ snprintf(tmp, sizeof(tmp), "Host: %s", hostname);
+ label = newtLabel(4,1, tmp);
+
+ ulabel = newtLabel(4,2,"Username:");
+ plabel = newtLabel(4,3,"Password:");
+
+ username = newtEntry(14, 2, "", 20, _NEWT_CAST &user, 0);
+ password = newtEntry(14, 3, "", 20, _NEWT_CAST &pass, NEWT_FLAG_HIDDEN);
+
+ form = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
+ newtFormRun(form, &es);
+ if (es.reason == NEWT_EXIT_COMPONENT) {
+ if (es.u.co == login) {
+ snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user);
+ show_doing("Logging in", tmp);
+ /* Check to see if the remote host supports MD5 Authentication */
+ manager_action("Challenge", "AuthType: MD5\r\n");
+ m = wait_for_response(10000);
+ if (m && !strcasecmp(get_header(m, "Response"), "Success")) {
+ char *challenge = get_header(m, "Challenge");
+ int x;
+ int len = 0;
+ char md5key[256] = "";
+ struct MD5Context md5;
+ unsigned char digest[16];
+ MD5Init(&md5);
+ MD5Update(&md5, (unsigned char *)challenge, strlen(challenge));
+ MD5Update(&md5, (unsigned char *)pass, strlen(pass));
+ MD5Final(digest, &md5);
+ for (x=0; x<16; x++)
+ len += sprintf(md5key + len, "%2.2x", digest[x]);
+ manager_action("Login",
+ "AuthType: MD5\r\n"
+ "Username: %s\r\n"
+ "Key: %s\r\n",
+ user, md5key);
+ m = wait_for_response(10000);
+ hide_doing();
+ if (!strcasecmp(get_header(m, "Response"), "Success")) {
+ res = 0;
+ } else {
+ show_message("Login Failed", get_header(m, "Message"));
+ }
+ } else {
+ memset(m, 0, sizeof(m));
+ manager_action("Login",
+ "Username: %s\r\n"
+ "Secret: %s\r\n",
+ user, pass);
+ m = wait_for_response(10000);
+ hide_doing();
+ if (m) {
+ if (!strcasecmp(get_header(m, "Response"), "Success")) {
+ res = 0;
+ } else {
+ show_message("Login Failed", get_header(m, "Message"));
+ }
+ }
+ }
+ }
+ }
+ newtFormDestroy(form);
+ return res;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: astman <host>\n");
+ exit(1);
+ }
+ newtInit();
+ newtCls();
+ newtDrawRootText(0, 0, "Asterisk Manager (C)2002, Linux Support Services, Inc.");
+ newtPushHelpLine("Welcome to the Asterisk Manager!");
+ if (login(argv[1])) {
+ newtFinished();
+ exit(1);
+ }
+ manage_calls(argv[1]);
+ newtFinished();
+ return 0;
+}
diff --git a/utils/check_expr.c b/utils/check_expr.c
new file mode 100644
index 000000000..d3dcc5d19
--- /dev/null
+++ b/utils/check_expr.c
@@ -0,0 +1,355 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <../include/asterisk/ast_expr.h>
+
+static int global_lineno = 1;
+static int global_expr_count=0;
+static int global_expr_max_size=0;
+static int global_expr_tot_size=0;
+static int global_warn_count=0;
+static int global_OK_count=0;
+
+struct varz
+{
+ char varname[100]; /* a really ultra-simple, space-wasting linked list of var=val data */
+ char varval[1000]; /* if any varname is bigger than 100 chars, or val greater than 1000, then **CRASH** */
+ struct varz *next;
+};
+
+struct varz *global_varlist;
+
+/* Our own version of ast_log, since the expr parser uses it. */
+
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6)));
+
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+ va_list vars;
+ va_start(vars,fmt);
+
+ printf("LOG: lev:%d file:%s line:%d func: %s ",
+ level, file, line, function);
+ vprintf(fmt, vars);
+ fflush(stdout);
+ va_end(vars);
+}
+void ast_register_file_version(const char *file, const char *version);
+void ast_unregister_file_version(const char *file);
+
+char *find_var(const char *varname);
+void set_var(const char *varname, const char *varval);
+unsigned int check_expr(char* buffer, char* error_report);
+int check_eval(char *buffer, char *error_report);
+void parse_file(const char *fname);
+
+void ast_register_file_version(const char *file, const char *version)
+{
+}
+
+void ast_unregister_file_version(const char *file)
+{
+}
+
+char *find_var(const char *varname) /* the list should be pretty short, if there's any list at all */
+{
+ struct varz *t;
+ for (t= global_varlist; t; t = t->next) {
+ if (!strcmp(t->varname, varname)) {
+ return t->varval;
+ }
+ }
+ return 0;
+}
+
+void set_var(const char *varname, const char *varval)
+{
+ struct varz *t = (struct varz*)calloc(1,sizeof(struct varz));
+ strcpy(t->varname, varname);
+ strcpy(t->varval, varval);
+ t->next = global_varlist;
+ global_varlist = t;
+}
+
+unsigned int check_expr(char* buffer, char* error_report)
+{
+ char* cp;
+ unsigned int warn_found = 0;
+
+ error_report[0] = 0;
+
+ for (cp = buffer; *cp; ++cp)
+ {
+ switch (*cp)
+ {
+ case '"':
+ /* skip to the other end */
+ while (*(++cp) && *cp != '"') ;
+
+ if (*cp == 0)
+ {
+ fprintf(stderr,
+ "Trouble? Unterminated double quote found at line %d\n",
+ global_lineno);
+ }
+ break;
+
+ case '>':
+ case '<':
+ case '!':
+ if ( (*(cp + 1) == '=')
+ && ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 2) != ' ') ) )
+ {
+ char msg[200];
+ snprintf(msg,
+ sizeof(msg),
+ "WARNING: line %d: '%c%c' operator not separated by spaces. This may lead to confusion. You may wish to use double quotes to quote the grouping it is in. Please check!\n",
+ global_lineno, *cp, *(cp + 1));
+ strcat(error_report, msg);
+ ++global_warn_count;
+ ++warn_found;
+ }
+ break;
+
+ case '|':
+ case '&':
+ case '=':
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '?':
+ case ':':
+ if ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 1) != ' ') )
+ {
+ char msg[200];
+ snprintf(msg,
+ sizeof(msg),
+ "WARNING: line %d: '%c' operator not separated by spaces. This may lead to confusion. You may wish to use double quotes to quote the grouping it is in. Please check!\n",
+ global_lineno, *cp );
+ strcat(error_report, msg);
+ ++global_warn_count;
+ ++warn_found;
+ }
+ break;
+ }
+ }
+
+ return warn_found;
+}
+
+int check_eval(char *buffer, char *error_report)
+{
+ char *cp, *ep;
+ char s[4096];
+ char evalbuf[80000];
+ int result;
+
+ error_report[0] = 0;
+ ep = evalbuf;
+
+ for (cp=buffer;*cp;cp++) {
+ if (*cp == '$' && *(cp+1) == '{') {
+ int brack_lev = 1;
+ char *xp= cp+2;
+
+ while (*xp) {
+ if (*xp == '{')
+ brack_lev++;
+ else if (*xp == '}')
+ brack_lev--;
+
+ if (brack_lev == 0)
+ break;
+ xp++;
+ }
+ if (*xp == '}') {
+ char varname[200];
+ char *val;
+
+ strncpy(varname,cp+2, xp-cp-2);
+ varname[xp-cp-2] = 0;
+ cp = xp;
+ val = find_var(varname);
+ if (val) {
+ char *z = val;
+ while (*z)
+ *ep++ = *z++;
+ }
+ else {
+ *ep++ = '5'; /* why not */
+ *ep++ = '5';
+ *ep++ = '5';
+ }
+ }
+ else {
+ printf("Unterminated variable reference at line %d\n", global_lineno);
+ *ep++ = *cp;
+ }
+ }
+ else if (*cp == '\\') {
+ /* braindead simple elim of backslash */
+ cp++;
+ *ep++ = *cp;
+ }
+ else
+ *ep++ = *cp;
+ }
+ *ep++ = 0;
+
+ /* now, run the test */
+ result = ast_expr(evalbuf, s, sizeof(s));
+ if (result) {
+ sprintf(error_report,"line %d, evaluation of $[ %s ] result: %s\n", global_lineno, evalbuf, s);
+ return 1;
+ } else {
+ sprintf(error_report,"line %d, evaluation of $[ %s ] result: ****SYNTAX ERROR****\n", global_lineno, evalbuf);
+ return 1;
+ }
+}
+
+
+void parse_file(const char *fname)
+{
+ FILE *f = fopen(fname,"r");
+ FILE *l = fopen("expr2_log","w");
+ int c1;
+ char last_char= 0;
+ char buffer[30000]; /* I sure hope no expr gets this big! */
+
+ if (!f) {
+ fprintf(stderr,"Couldn't open %s for reading... need an extensions.conf file to parse!\n",fname);
+ exit(20);
+ }
+ if (!l) {
+ fprintf(stderr,"Couldn't open 'expr2_log' file for writing... please fix and re-run!\n");
+ exit(21);
+ }
+
+ global_lineno = 1;
+
+ while ((c1 = fgetc(f)) != EOF) {
+ if (c1 == '\n')
+ global_lineno++;
+ else if (c1 == '[') {
+ if (last_char == '$') {
+ /* bingo, an expr */
+ int bracklev = 1;
+ int bufcount = 0;
+ int retval;
+ char error_report[30000];
+
+ while ((c1 = fgetc(f)) != EOF) {
+ if (c1 == '[')
+ bracklev++;
+ else if (c1 == ']')
+ bracklev--;
+ if (c1 == '\n') {
+ fprintf(l, "ERROR-- A newline in an expression? Weird! ...at line %d\n", global_lineno);
+ fclose(f);
+ fclose(l);
+ printf("--- ERROR --- A newline in the middle of an expression at line %d!\n", global_lineno);
+ }
+
+ if (bracklev == 0)
+ break;
+ buffer[bufcount++] = c1;
+ }
+ if (c1 == EOF) {
+ fprintf(l, "ERROR-- End of File Reached in the middle of an Expr at line %d\n", global_lineno);
+ fclose(f);
+ fclose(l);
+ printf("--- ERROR --- EOF reached in middle of an expression at line %d!\n", global_lineno);
+ exit(22);
+ }
+
+ buffer[bufcount] = 0;
+ /* update stats */
+ global_expr_tot_size += bufcount;
+ global_expr_count++;
+ if (bufcount > global_expr_max_size)
+ global_expr_max_size = bufcount;
+
+ retval = check_expr(buffer, error_report); /* check_expr should bump the warning counter */
+ if (retval != 0) {
+ /* print error report */
+ printf("Warning(s) at line %d, expression: $[%s]; see expr2_log file for details\n",
+ global_lineno, buffer);
+ fprintf(l, "%s", error_report);
+ }
+ else {
+ printf("OK -- $[%s] at line %d\n", buffer, global_lineno);
+ global_OK_count++;
+ }
+ error_report[0] = 0;
+ retval = check_eval(buffer, error_report);
+ fprintf(l, "%s", error_report);
+ }
+ }
+ last_char = c1;
+ }
+ printf("Summary:\n Expressions detected: %d\n Expressions OK: %d\n Total # Warnings: %d\n Longest Expr: %d chars\n Ave expr len: %d chars\n",
+ global_expr_count,
+ global_OK_count,
+ global_warn_count,
+ global_expr_max_size,
+ (global_expr_count) ? global_expr_tot_size/global_expr_count : 0);
+
+ fclose(f);
+ fclose(l);
+}
+
+
+int main(int argc,char **argv)
+{
+ int argc1;
+ char *eq;
+
+ if (argc < 2) {
+ printf("check_expr -- a program to look thru extensions.conf files for $[...] expressions,\n");
+ printf(" and run them thru the parser, looking for problems\n");
+ printf("Hey-- give me a path to an extensions.conf file!\n");
+ printf(" You can also follow the file path with a series of variable decls,\n");
+ printf(" of the form, varname=value, each separated from the next by spaces.\n");
+ printf(" (this might allow you to avoid division by zero messages, check that math\n");
+ printf(" is being done correctly, etc.)\n");
+ printf(" Note that messages about operators not being surrounded by spaces is merely to alert\n");
+ printf(" you to possible problems where you might be expecting those operators as part of a string.\n");
+ printf(" (to include operators in a string, wrap with double quotes!)\n");
+
+ exit(19);
+ }
+ global_varlist = 0;
+ for (argc1=2;argc1 < argc; argc1++) {
+ if ((eq = strchr(argv[argc1],'='))) {
+ *eq = 0;
+ set_var(argv[argc1],eq+1);
+ }
+ }
+
+ /* parse command args for x=y and set varz */
+
+ parse_file(argv[1]);
+ return 0;
+}
diff --git a/utils/expr2.testinput b/utils/expr2.testinput
new file mode 100644
index 000000000..948baaf94
--- /dev/null
+++ b/utils/expr2.testinput
@@ -0,0 +1,92 @@
+2 + 2
+ 2 + 2
+
+2 - 4
+4 - 2
+-4 - -2
+4 + 2 * 8
+(4 + 2) * 8
+4 + (2 * 8)
+4 + (2 * 8) ? 3 :: 6
+4 + 8 / 2
+4 + 8 / 3
+(4+8) / 3
+4 + 8 % 3
+4 + 9 % 3
+(4+9) %3
+(4+8) %3
+(4+9) %3
+(4+8) %3
+(4+9) % 3
+(4+8) % 3
+(4+9) % 3
+(4+8) % 3
+(4+9)% 3
+(4+8)% 3
+(4+9)% 3
+(4+8)% 3
+4 & 4
+0 & 4
+0 & 0
+2 | 0
+2 | 4
+0 | 0
+!0 | 0
+!4 | 0
+4 | !0
+!4 | !0
+3 < 4
+4 < 3
+3 > 4
+4 > 3
+3 = 3
+3 = 4
+3 != 3
+3 != 4
+3 >= 4
+3 >= 3
+4 >= 3
+3 <= 4
+4 <= 3
+4 <= 4
+3 > 4 & 4 < 3
+4 > 3 & 3 < 4
+x = x
+y = x
+x != y
+x != x
+"Something interesting" =~ interesting
+"Something interesting" =~ Something
+"Something interesting" : Something
+"Something interesting" : interesting
+"Something interesting" =~ "interesting"
+"Something interesting" =~ "Something"
+"Something interesting" : "Something"
+"Something interesting" : "interesting"
+"Something interesting" =~ (interesting)
+"Something interesting" =~ (Something)
+"Something interesting" : (Something)
+"Something interesting" : (interesting)
+"Something interesting" =~ "\(interesting\)"
+"Something interesting" =~ "\(Something\)"
+"Something interesting" : "\(Something\)"
+"Something interesting" : "\(interesting\)"
+"011043567857575" : "011\(..\)"
+"9011043567857575" : "011\(..\)"
+"011043567857575" =~ "011\(..\)"
+"9011043567857575" =~ "011\(..\)"
+"Something interesting" =~ (interesting)
+"Something interesting" =~ (Something)
+"Something interesting" : (Something)
+"Something interesting" : (interesting)
+"Something interesting" =~ "(interesting)"
+"Something interesting" =~ "(Something)"
+"Something interesting" : "(Something)"
+"Something interesting" : "(interesting)"
+"011043567857575" : "011(..)"
+"9011043567857575" : "011(..)"
+"011043567857575" =~ "011(..)"
+"9011043567857575" =~ "011(..)"
+3
+something
+043
diff --git a/utils/frame.c b/utils/frame.c
new file mode 100644
index 000000000..bdc65e12f
--- /dev/null
+++ b/utils/frame.c
@@ -0,0 +1,1092 @@
+/****************************************************************************
+ *
+ * Programs for processing sound files in raw- or WAV-format.
+ * -- Useful functions for parsing command line options and
+ * issuing errors, warnings, and chit chat.
+ *
+ * Name: frame.c
+ * Version: see static char *standardversion, below.
+ * Author: Mark Roberts <mark@manumark.de>
+ * Michael Labuschke <michael@labuschke.de> sys_errlist fixes
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * These are useful functions that all DSP programs might find handy
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h> /* for exit and malloc */
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include "frame.h"
+
+time_t stopwatch; /* will hold time at start of calculation */
+int samplefrequency;
+unsigned short samplewidth;
+unsigned short channels;
+int wavout; /* TRUE iff out file should be a .WAV file */
+int iswav; /* TRUE iff in file was found to be a .WAV file */
+FILE *in, *out;
+char *infilename, *outfilename;
+int verboselevel;
+char *version = "";
+char *usage = "";
+static int test_usage;
+
+static char *standardversion = "frame version 1.3, June 13th 2001";
+static char *standardusage =
+"\nOptions common to all mark-dsp programs:\n"
+
+"-h \t\t create a WAV-header on output files.\n"
+"-c#\t\t set number of channels to # (1 or 2). Default: like input.\n"
+"-w#\t\t set number of bits per sample (width) to # (only 16)\n"
+"-f#\t\t set sample frequency to #. Default: like input.\n"
+"-V \t\t verbose: talk a lot.\n"
+"-Q \t\t quiet: talk as little as possible.\n\n"
+"In most cases, a filename of '-' means stdin or stdout.\n\n"
+"Bug-reports: mark@manumark.de\n"
+;
+
+/* -----------------------------------------------------------------------
+ Writes the number of samples to result that are yet to be read from anyin.
+ Return values are TRUE on success, FALSE on failure.
+ -----------------------------------------------------------------------*/
+int getremainingfilelength( FILE *anyin, long *result)
+{
+ long i;
+
+ i = ftell(anyin);
+ if (i == -1) return FALSE;
+ if (fseek(anyin, 0, SEEK_END) == -1) return FALSE;
+ *result = ftell(anyin);
+ if (*result == -1) return FALSE;
+ (*result) -= i;
+ (*result) /= samplewidth;
+ if (fseek(anyin, i, SEEK_SET) == -1) return FALSE;
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------
+ Read a .pk-header from 'anyin'.
+ -----------------------------------------------------------------------*/
+void readpkheader( FILE *anyin)
+{
+ unsigned short tempushort;
+ int tempint, i, x;
+ unsigned char blood[8];
+
+ for (i = 0; i < 11; i++)
+ {
+ if (!fread( &tempint, 4, 1, anyin)) {
+ return;
+ }
+ printf( "%d: %d, ", i, tempint);
+ }
+ printf( "\n");
+ if (!fread( blood, 1, 8, anyin)) {
+ return;
+ }
+ for (i = 0; i < 8; i++)
+ printf( "%d ", blood[i]);
+ printf( "\n");
+ for (i = 0; i < 8; i++)
+ {
+ for (x = 128; x > 0; x /= 2)
+ printf((blood[i] & x) == 0? "0 ":"1 ");
+ printf(i%4==3? "\n":"| ");
+ }
+ printf( "\n");
+ for (i = 0; i < 2; i++)
+ {
+ if (!fread( &tempint, 4, 1, anyin)) {
+ return;
+ }
+ printf( "%d: %d, ", i, tempint);
+ }
+ printf( "\n");
+ for (i = 0; i < 2; i++)
+ {
+ if (!fread( &tempushort, 2, 1, anyin)) {
+ return;
+ }
+ printf( "%d: %d, ", i, tempushort);
+ }
+ printf( "\n");
+}
+
+
+
+/* -----------------------------------------------------------------------
+ Read a .WAV header from 'anyin'. See header for details.
+ -----------------------------------------------------------------------*/
+void readwavheader( FILE *anyin)
+{
+ unsigned int tempuint, sf;
+ unsigned short tempushort, cn;
+ char str[9];
+ int nowav = FALSE;
+
+ iswav = FALSE;
+
+ if (ftell(anyin) == -1) /* If we cannot seek this file */
+ {
+ nowav = TRUE; /* -> Pretend this is no wav-file */
+ chat("File not seekable: not checking for WAV-header.\n");
+ }
+ else
+ {
+ /* Expect four bytes "RIFF" and four bytes filelength */
+ if (!fread(str, 1, 8, anyin)) { /* 0 */
+ return;
+ }
+ str[4] = '\0';
+ if (strcmp(str, "RIFF") != 0) nowav = TRUE;
+ /* Expect eight bytes "WAVEfmt " */
+ if (!fread(str, 1, 8, anyin)) { /* 8 */
+ return;
+ }
+ str[8] = '\0';
+ if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE;
+ /* Expect length of fmt data, which should be 16 */
+ if (!fread(&tempuint, 4, 1, anyin)) { /* 16 */
+ return;
+ }
+ if (tempuint != 16) nowav = TRUE;
+ /* Expect format tag, which should be 1 for pcm */
+ if (!fread(&tempushort, 2, 1, anyin)) { /* 20 */
+ return;
+ }
+ if (tempushort != 1)
+ nowav = TRUE;
+ /* Expect number of channels */
+ if (!fread(&cn, 2, 1, anyin)) { /* 20 */
+ return;
+ }
+ if (cn != 1 && cn != 2) nowav = TRUE;
+ /* Read samplefrequency */
+ if (!fread(&sf, 4, 1, anyin)) { /* 24 */
+ return;
+ }
+ /* Read bytes per second: Should be samplefreq * channels * 2 */
+ if (!fread(&tempuint, 4, 1, anyin)) { /* 28 */
+ return;
+ }
+ if (tempuint != sf * cn * 2) nowav = TRUE;
+ /* read bytes per frame: Should be channels * 2 */
+ if (!fread(&tempushort, 2, 1, anyin)) { /* 32 */
+ return;
+ }
+ if (tempushort != cn * 2) nowav = TRUE;
+ /* Read bits per sample: Should be 16 */
+ if (!fread(&tempushort, 2, 1, anyin)) { /* 34 */
+ return;
+ }
+ if (tempushort != 16) nowav = TRUE;
+ if (!fread(str, 4, 1, anyin)) { /* 36 */
+ return;
+ }
+ str[4] = '\0';
+ if (strcmp(str, "data") != 0) nowav = TRUE;
+ if (!fread(&tempuint, 4, 1, anyin)) { /* 40 */
+ return;
+ }
+ if (nowav)
+ {
+ fseek(anyin, 0, SEEK_SET); /* Back to beginning of file */
+ chat("File has no WAV header.\n");
+ }
+ else
+ {
+ samplefrequency = sf;
+ channels = cn;
+ chat("Read WAV header: %d channels, samplefrequency %d.\n",
+ channels, samplefrequency);
+ iswav = TRUE;
+ }
+ }
+ return;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ Write a .WAV header to 'out'. See header for details.
+ -----------------------------------------------------------------------*/
+void makewavheader( void)
+{
+ unsigned int tempuint, filelength;
+ unsigned short tempushort;
+
+ /* If fseek fails, don't create the header. */
+ if (fseek(out, 0, SEEK_END) != -1)
+ {
+ filelength = ftell(out);
+ chat("filelength %d, ", filelength);
+ fseek(out, 0, SEEK_SET);
+ if (!fwrite("RIFF", 1, 4, out)) { /* 0 */
+ return;
+ }
+ tempuint = filelength - 8;
+ if (!fwrite(&tempuint, 4, 1, out)) { /* 4 */
+ return;
+ }
+ if (!fwrite("WAVEfmt ", 1, 8, out)) { /* 8 */
+ return;
+ }
+ /* length of fmt data 16 bytes */
+ tempuint = 16;
+ if (!fwrite(&tempuint, 4, 1, out)) { /* 16 */
+ return;
+ }
+ /* Format tag: 1 for pcm */
+ tempushort = 1;
+ if (!fwrite(&tempushort, 2, 1, out)) { /* 20 */
+ return;
+ }
+ chat("%d channels\n", channels);
+ if (!fwrite(&channels, 2, 1, out)) {
+ return;
+ }
+ chat("samplefrequency %d\n", samplefrequency);
+ if (!fwrite(&samplefrequency, 4, 1, out)) { /* 24 */
+ return;
+ }
+ /* Bytes per second */
+ tempuint = channels * samplefrequency * 2;
+ if (!fwrite(&tempuint, 4, 1, out)) { /* 28 */
+ return;
+ }
+ /* Block align */
+ tempushort = 2 * channels;
+ if (!fwrite(&tempushort, 2, 1, out)) { /* 32 */
+ return;
+ }
+ /* Bits per sample */
+ tempushort = 16;
+ if (!fwrite(&tempushort, 2, 1, out)) { /* 34 */
+ return;
+ }
+ if (!fwrite("data", 4, 1, out)) { /* 36 */
+ return;
+ }
+ tempuint = filelength - 44;
+ if (!fwrite(&tempuint, 4, 1, out)) { /* 40 */
+ return;
+ }
+ }
+ return;
+}
+
+/* -----------------------------------------------------------------------
+ After all is read and done, inform the inclined user of the elapsed time
+ -----------------------------------------------------------------------*/
+static void statistics( void)
+{
+ int temp;
+
+ temp = time(NULL) - stopwatch;
+ if (temp != 1)
+ {
+ inform ("\nTime: %d seconds\n", temp);
+ }
+ else
+ {
+ inform ("\nTime: 1 second\n");
+ }
+ return;
+}
+
+
+/* -----------------------------------------------------------------------
+ Start the stopwatch and make sure the user is informed at end of program.
+ -----------------------------------------------------------------------*/
+void startstopwatch(void)
+{
+ stopwatch = time(NULL); /* Remember time 'now' */
+ atexit(statistics); /* Call function statistics() at exit. */
+
+ return;
+}
+
+/* --------------------------------------------------------------------
+ Tests the character 'coal' for being a command line option character,
+ momentarrily '-'.
+ -------------------------------------------------------------------- */
+int isoptionchar (char coal)
+{
+ return (coal =='-');
+}
+
+/* -----------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a time and passed
+ to *result, where the result is meant to mean 'number of samples' in
+ that time.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+int parsetimearg( int argcount, char *args[], char *string, int *result)
+{
+ int i;
+
+ if ((i = findoption( argcount, args, string)) > 0)
+ {
+ if (parsetime(args[i] + 1 + strlen( string), result))
+ return TRUE;
+ argerrornum(args[i]+1, ME_NOTIME);
+ }
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------
+ The string argument is read as a time and passed
+ to *result, where the result is meant to mean 'number of samples' in
+ that time.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+int parsetime(char *string, int *result)
+{
+ int k;
+ double temp;
+ char m, s, end;
+
+ k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
+ switch (k)
+ {
+ case 0: case EOF: case 4:
+ return FALSE;
+ case 1:
+ *result = temp;
+ break;
+ case 2:
+ if (m == 's')
+ *result = temp * samplefrequency;
+ else
+ return FALSE;
+ break;
+ case 3:
+ if (m == 'm' && s == 's')
+ *result = temp * samplefrequency / 1000;
+ else if (m == 'H' && s == 'z')
+ *result = samplefrequency / temp;
+ else
+ return FALSE;
+ break;
+ default:
+ argerrornum(NULL, ME_THISCANTHAPPEN);
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------
+ The string argument is read as a frequency and passed
+ to *result, where the result is meant to mean 'number of samples' in
+ one cycle of that frequency.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+int parsefreq(char *string, double *result)
+{
+ int k;
+ double temp;
+ char m, s, end;
+
+ k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
+ switch (k)
+ {
+ case 0: case EOF: case 2: case 4:
+ return FALSE;
+ case 1:
+ *result = temp;
+ break;
+ case 3:
+ if (m == 'H' && s == 'z')
+ *result = samplefrequency / temp;
+ else
+ return FALSE;
+ break;
+ default:
+ argerrornum(NULL, ME_THISCANTHAPPEN);
+ }
+ return TRUE;
+}
+
+char *parsefilearg( int argcount, char *args[])
+{
+ int i;
+ char *result = NULL;
+
+ for (i = 1; i < argcount; i++)
+ {
+ if (args[i][0] != '\0' &&
+ (!isoptionchar (args[i][0]) || args[i][1] == '\0' ))
+ {
+ /*---------------------------------------------*
+ * The argument is a filename: *
+ * it is either no dash followed by something, *
+ * or it is a dash following by nothing. *
+ *---------------------------------------------*/
+ result = malloc( strlen( args[i]) + 1);
+ if (result == NULL)
+ fatalperror( "Couldn't allocate memory for filename\n");
+ strcpy( result, args[i]);
+ args[i][0] = '\0'; /* Mark as used up */
+ break;
+ }
+ }
+ return result;
+}
+
+int parseswitch( char *found, char *wanted)
+{
+ if (strncmp( found, wanted, strlen( wanted)) == 0)
+ {
+ if (found[strlen( wanted)] == '\0')
+ return TRUE;
+ else
+ argerrornum( found, ME_NOSWITCH);
+ }
+ return FALSE;
+}
+
+int parseswitcharg( int argcount, char *args[], char *string)
+{
+ int i;
+
+ if ((i = findoption( argcount, args, string)) > 0)
+ {
+ if (args[i][strlen( string) + 1] == '\0')
+ return TRUE;
+ else
+ argerrornum( args[i] + 1, ME_NOSWITCH);
+ }
+ return FALSE;
+}
+
+int parseintarg( int argcount, char *args[], char *string, int *result)
+{
+ int i, temp;
+ char c;
+
+ if ((i = findoption( argcount, args, string)) > 0)
+ {
+ switch (sscanf(args[i] + 1 + strlen( string),
+ "%d%c", &temp, &c))
+ {
+ case 0: case EOF: case 2:
+ argerrornum(args[i]+1, ME_NOINT);
+ return FALSE;
+ case 1:
+ *result = temp;
+ break;
+ default:
+ say("frame.c: This can't happen\n");
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a double and
+ passed to *result.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+int parsedoublearg( int argcount, char *args[], char *string, double *result)
+{
+ int i;
+ double temp;
+ char end;
+
+ if ((i = findoption( argcount, args, string)) > 0)
+ {
+ switch (sscanf(args[i] + 1 + strlen( string), "%lf%c", &temp, &end))
+ {
+ case 0: case EOF: case 2:
+ argerrornum(args[i]+1, ME_NODOUBLE);
+ return FALSE;
+ case 1:
+ *result = temp;
+ break;
+ default:
+ say("frame.c: This can't happen\n");
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a volume, i.e.
+ absolute, percent or db. The result is passed to *result.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+int parsevolarg( int argcount, char *args[], char *string, double *result)
+{
+ double vol = 1.0;
+ char sbd, sbb, end;
+ int i, weird = FALSE;
+
+ if ((i = findoption( argcount, args, string)) > 0)
+ {
+ switch (sscanf(args[i] + 1 + strlen( string),
+ "%lf%c%c%c", &vol, &sbd, &sbb, &end))
+ {
+ case 0: case EOF: case 4:
+ weird = TRUE;
+ break; /* No number: error */
+ case 1:
+ *result = vol;
+ break;
+ case 2:
+ if (sbd == '%')
+ *result = vol / 100;
+ else
+ weird = TRUE; /* One char but no percent: error */
+ break;
+ case 3:
+ if (sbd =='d' && sbb == 'b')
+ *result = pow(2, vol / 6.02);
+ else
+ weird = TRUE; /* Two chars but not db: error */
+ break;
+ default:
+ say("frame.c: This can't happen.\n");
+ }
+ if (weird)
+ argerrornum( args[i] + 1, ME_NOVOL);
+ /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */
+ return !weird;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/* --------------------------------------------------------------------
+ Reads the specified string 's' and interprets it as a volume. The string
+ would be of the form 1.8 or 180% or 5db.
+ On success, the return value TRUE and *result is given result
+ (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and
+ result is given value 1.0.
+ -------------------------------------------------------------------- */
+int parsevolume(char *s, double *result)
+{
+ int k;
+ char sbd, sbb, end;
+
+ *result = 1.0;
+ k = sscanf(s, "%lf%c%c%c", result, &sbd, &sbb, &end);
+ switch (k)
+ {
+ case 0:
+ case EOF:
+ case 4:
+ return FALSE;
+ case 1:
+ break;
+ case 2:
+ if (sbd != '%')
+ return FALSE;
+ (*result) /=100;
+ break;
+ case 3:
+ if (sbd !='d' || sbb != 'b')
+ return FALSE;
+ (*result) = pow(2, (*result) / 6.02);
+ break;
+ default:
+ say("parsevolume: This can't happen (%d).\n", k);
+ }
+ return TRUE;
+}
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line.
+ -------------------------------------------------------------------- */
+void argerror(char *s)
+{
+ error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s);
+ fatalerror("\nTry --help for help.\n");
+}
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line. 'code' indicates the type of error.
+ -------------------------------------------------------------------- */
+void argerrornum(char *s, Errornum code)
+{
+ char *message;
+
+ if (code == ME_TOOMANYFILES)
+ {
+ error("Too many files on command line: '%s'.\n", s);
+ }
+ else
+ {
+ if (s != NULL)
+ error ("Error parsing option -%s:\n\t", s);
+ switch( code)
+ {
+ case ME_NOINT:
+ message = "Integer expected";
+ break;
+ case ME_NODOUBLE:
+ message = "Floating point number expected";
+ break;
+ case ME_NOTIME:
+ message = "Time argument expected";
+ break;
+ case ME_NOVOL:
+ message = "Volume argument expected";
+ break;
+ case ME_NOSWITCH:
+ message = "Garbage after switch-type option";
+ break;
+ case ME_HEADERONTEXTFILE:
+ message = "Option -h is not useful for text-output";
+ break;
+ case ME_NOINFILE:
+ message = "No input file specified";
+ break;
+ case ME_NOOUTFILE:
+ message = "No output file specified";
+ break;
+ case ME_NOIOFILE:
+ message = "No input/output file specified";
+ break;
+ case ME_NOSTDIN:
+ message = "Standard in not supported here";
+ break;
+ case ME_NOSTDOUT:
+ message = "Standard out not supported here";
+ break;
+ case ME_NOSTDIO:
+ message = "Standard in/out not supported here";
+ break;
+ case ME_NOTENOUGHFILES:
+ message = "Not enough files specified";
+ break;
+ case ME_THISCANTHAPPEN:
+ fatalerror("\nThis can't happen. Report this as a bug\n");
+ /* fatalerror does not return */
+ default:
+ error("Error code %d not implemented. Fix me!\n", code);
+ message = "Error message not implemented. Fix me!";
+ }
+ error("%s\n", message);
+ }
+ fatalerror("\nTry --help for help.\n");
+}
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line. 'message' explains the type of error.
+ -------------------------------------------------------------------- */
+void argerrortxt(char *s, char *message)
+{
+ if (s != NULL)
+ error ("Error parsing option -%s:\n\t", s);
+ else
+ error ("Error parsing command line:\n\t");
+ error ("%s\n", message);
+ fatalerror("\nTry --help for help.\n");
+}
+
+/* --------------------------------------------------------------------
+ Check for any remaining arguments and complain about their existence
+ -------------------------------------------------------------------- */
+void checknoargs( int argcount, char *args[])
+{
+ int i, errorcount = 0;
+
+ for (i = 1; i < argcount; i++)
+ {
+ if (args[i][0] != '\0') /* An unused argument! */
+ {
+ errorcount++;
+ if (errorcount == 1)
+ error("The following arguments were not recognized:\n");
+ error("\t%s\n", args[i]);
+ }
+ }
+ if (errorcount > 0) /* Errors are fatal */
+ fatalerror("\nTry --help for help.\n");
+
+ return; /* No errors? Return. */
+}
+
+/* --------------------------------------------------------------------
+ Parses the command line arguments as represented by the function
+ arguments. Sets the global variables 'in', 'out', 'samplefrequency'
+ and 'samplewidth' accordingly. Also verboselevel.
+ The files 'in' and 'out' are even opened according to 'fileswitch'.
+ See headerfile for details
+ -------------------------------------------------------------------- */
+void parseargs( int argcount, char *args[], int fileswitch)
+{
+ char *filename;
+ int tempint;
+
+ if ((fileswitch & 1) != 0) /* If getting infile */
+ in = NULL;
+ if ((fileswitch & 4) != 0) /* If getting outfile */
+ out = NULL;
+ wavout = FALSE;
+ verboselevel = 5;
+ samplefrequency = DEFAULTFREQ;
+ samplewidth = 2;
+ channels = 1;
+
+ /*-----------------------------------------------*
+ * First first check testcase, usage and version *
+ *-----------------------------------------------*/
+ test_usage = parseswitcharg( argcount, args, "-test-usage");
+ if (parseswitcharg( argcount, args, "-help"))
+ {
+ printf("%s%s", usage, standardusage);
+ exit(0);
+ }
+ if (parseswitcharg( argcount, args, "-version"))
+ {
+ printf("%s\n(%s)\n", version, standardversion);
+ exit(0);
+ }
+ /*--------------------------------------*
+ * Set verboselevel *
+ *--------------------------------------*/
+ while (parseswitcharg( argcount, args, "V"))
+ verboselevel = 10;
+ while (parseswitcharg( argcount, args, "Q"))
+ verboselevel = 1;
+ /*-------------------------------------------------*
+ * Get filenames and open files *
+ *-------------------------------------------------*/
+ if ((fileswitch & 1) != 0) /* Infile wanted */
+ {
+ infilename = parsefilearg( argcount, args);
+ if (infilename == NULL)
+ argerrornum( NULL, ME_NOINFILE);
+ if (strcmp( infilename, "-") == 0)
+ {
+ infilename = "<stdin>";
+ in = stdin;
+ if ((fileswitch & 2) != 0) /* Binfile wanted */
+ readwavheader( in);
+ }
+ else
+ {
+ if ((fileswitch & 2) == 0) /* Textfile wanted */
+ in = fopen(infilename, "rt");
+ else /* Binfile wanted */
+ if ((in = fopen(infilename, "rb")) != NULL)
+ readwavheader( in);
+ }
+ if (in == NULL)
+ fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno));
+ else
+ inform("Using file '%s' as input\n", infilename);
+ }
+ if ((fileswitch & 4) != 0) /* Outfile wanted */
+ {
+ outfilename = parsefilearg( argcount, args);
+ if (outfilename == NULL)
+ argerrornum( NULL, ME_NOOUTFILE);
+ if (strcmp( outfilename, "-") == 0)
+ {
+ outfilename = "<stdout>";
+ out = stdout;
+ }
+ else
+ {
+
+ if ((fileswitch & 8) == 0) /* Textfile wanted */
+ out = fopen(outfilename, "wt");
+ else /* Binfile wanted */
+ out = fopen(outfilename, "wb");
+ }
+ if (out == NULL)
+ fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno));
+ else
+ inform("Using file '%s' as output\n", outfilename);
+ }
+ if ((fileswitch & 32) != 0) /* In-/Outfile wanted */
+ {
+ assert (in == NULL && out == NULL);
+ infilename = outfilename = parsefilearg( argcount, args);
+ if (outfilename == NULL)
+ argerrornum( NULL, ME_NOIOFILE);
+ if (strcmp( infilename, "-") == 0)
+ argerrornum( infilename, ME_NOSTDIN);
+ inform("Using file '%s' as input/output\n", outfilename);
+ in = out = fopen(outfilename, "r+");
+ if (out == NULL)
+ fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
+
+ readwavheader( in);
+ }
+ if ((fileswitch & 16) == 0) /* No additional files wanted */
+ {
+ if ((filename = parsefilearg( argcount, args)) != NULL)
+ argerrornum( filename, ME_TOOMANYFILES);
+ }
+
+ /*-------------------------------------------------*
+ * Set samplefrequency, width, wavout,
+ *-------------------------------------------------*/
+ parseintarg( argcount, args, "f", &samplefrequency);
+ wavout = parseswitcharg( argcount, args, "h");
+ if (parseintarg( argcount, args, "w", &tempint))
+ {
+ if (tempint != 16)
+ argerrortxt(NULL, "Option -w is only valid "
+ "with value 16. Sorry.");
+ else
+ samplewidth = tempint;
+ }
+ if (parseintarg( argcount, args, "c", &tempint))
+ {
+ if (tempint != 1 && tempint != 2)
+ argerrortxt(NULL, "Option -c is only valid "
+ "with values 1 or 2. Sorry.");
+ else
+ channels = tempint;
+ }
+ /*-------------------------------------------------*
+ * Create WAV-header on output if wanted. *
+ *-------------------------------------------------*/
+ if (wavout)
+ switch (fileswitch & (12))
+ {
+ case 4: /* User wants header on textfile */
+ argerrornum( NULL, ME_HEADERONTEXTFILE);
+ case 12: /* User wants header on binfile */
+ makewavheader();
+ break;
+ case 0: /* User wants header, but there is no outfile */
+ /* Problem: what about i/o-file, 32? You might want a header
+ on that? Better ignore this case. */
+ break;
+ case 8: /* An application musn't ask for this */
+ default: /* This can't happen */
+ assert( FALSE);
+ }
+ return;
+}
+
+/* --------------------------------------------------------------------
+ Returns the index 'i' of the first argument that IS an option, and
+ which begins with the label 's'. If there is none, -1.
+ We also mark that option as done with, i.e. we cross it out.
+ -------------------------------------------------------------------- */
+int findoption( int argcount, char *args[], char *s)
+{
+ int i;
+
+ if (test_usage)
+ printf("Checking for option -%s\n", s);
+
+ for (i=1; i<argcount; i++)
+ {
+ if (isoptionchar (args[i][0]) &&
+ strncmp( args[i] + 1, s, strlen( s)) == 0)
+ {
+ args[i][0] = '\0';
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* --------------------------------------------------------------------
+ Finishes off the .WAV header (if any) and exits correctly and formerly.
+ -------------------------------------------------------------------- */
+int myexit (int value)
+{
+ switch (value)
+ {
+ case 0:
+ if (wavout)
+ makewavheader(); /* Writes a fully informed .WAV header */
+ chat("Success!\n");
+ break;
+ default:
+ chat("Failure.\n");
+ break;
+ }
+ exit (value);
+}
+
+/* --------------------------------------------------------------------
+ Reads the stated input file bufferwise, calls the function 'work'
+ with the proper values, and writes the result to the stated output file.
+ Return value: TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+int workloop( FILE *theinfile, FILE *theoutfile,
+ int (*work)( short *buffer, int length) )
+{
+ short *buffer;
+ int length, nowlength;
+
+ length = BUFFSIZE;
+ if ((buffer = malloc( sizeof(short) * length)) == NULL)
+ fatalperror ("");
+ while (TRUE)
+ {
+ nowlength = fread(buffer, sizeof(short), length, theinfile);
+ if (ferror( theinfile) != 0)
+ fatalperror("Error reading input file");
+ if (nowlength == 0) /* Reached end of input file */
+ break;
+ /* Call the routine that does the work */
+ if (!work (buffer, nowlength)) /* On error, stop. */
+ return FALSE;
+ if (!fwrite(buffer, sizeof(short), nowlength, theoutfile)) {
+ return FALSE;
+ }
+ if (ferror( theoutfile) != 0)
+ fatalperror("Error writing to output file");
+ }
+ return TRUE; /* Input file done with, no errors. */
+}
+
+int __attribute__((format(printf, 1, 2))) chat( const char *format, ...)
+{
+ va_list ap;
+ int result = 0;
+
+ if (verboselevel > 5)
+ {
+ va_start( ap, format);
+ result = vfprintf( stderr, format, ap);
+ va_end( ap);
+ }
+ return result;
+}
+
+
+int __attribute__((format(printf, 1, 2))) inform( const char *format, ...)
+{
+ va_list ap;
+ int result = 0;
+
+ if (verboselevel > 1)
+ {
+ va_start( ap, format);
+ result = vfprintf( stderr, format, ap);
+ va_end( ap);
+ }
+ return result;
+}
+
+int __attribute__((format(printf, 1, 2))) error( const char *format, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start( ap, format);
+ result = vfprintf( stderr, format, ap);
+ va_end( ap);
+ return result;
+}
+
+void __attribute__((format(printf, 1, 2))) fatalerror( const char *format, ...)
+{
+ va_list ap;
+
+ va_start( ap, format);
+ vfprintf( stderr, format, ap);
+ va_end( ap);
+ myexit(1);
+}
+
+void fatalperror( const char *string)
+{
+ perror( string);
+ myexit( 1);
+}
+
+int __attribute__((format(printf, 1, 2))) say( const char *format, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start( ap, format);
+ result = vfprintf( stdout, format, ap);
+ va_end( ap);
+ return result;
+}
+
+
+char *malloccopy( char *string)
+{
+ char *result;
+
+ result = malloc( strlen( string) + 1);
+ if (result != NULL)
+ strcpy( result, string);
+ return result;
+}
+
+
+char *mallocconcat( char *one, char *two)
+{
+ char *result;
+
+ result = malloc( strlen( one) + strlen( two) + 1);
+ if (result != NULL)
+ {
+ strcpy( result, one);
+ strcat( result, two);
+ }
+ return result;
+}
+
+double double2db( double value)
+{
+ if (value < 0)
+ value = -value;
+ return 6.0 * log( value / 32767) / log( 2);
+}
+
+void readawaysamples( FILE *in, size_t size)
+{
+ short *buffer;
+ int samplesread, count;
+
+ buffer = malloc( sizeof( *buffer) * BUFFSIZE);
+ if (buffer == NULL) fatalperror("Couldn't allocate buffer");
+
+ while (size > 0)
+ {
+ if (size > BUFFSIZE)
+ count = BUFFSIZE;
+ else
+ count = size;
+
+ samplesread = fread( buffer, sizeof(*buffer), count, in);
+ if (ferror( in) != 0)
+ fatalperror("Error reading input file");
+ size -= samplesread;
+ }
+ free( buffer);
+}
+
diff --git a/utils/frame.h b/utils/frame.h
new file mode 100644
index 000000000..a07c605ec
--- /dev/null
+++ b/utils/frame.h
@@ -0,0 +1,300 @@
+/****************************************************************************
+ *
+ * Programs for processing sound files in raw- or WAV-format.
+ * -- Useful functions for parsing command line options and
+ * issuing errors, warnings, and chit chat.
+ *
+ * Name: frame.h
+ * Version: see frame.c
+ * Author: Mark Roberts <mark@manumark.de>
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * These are useful functions that all DSP programs might find handy
+ ****************************************************************************/
+
+/* fileswitch for parseargs:
+
+ The following are masks for several different ways of opening files.
+ --------------------------------------------------------------------
+ Bit 0: Open infile?
+ Bit 1: Open infile as binary (as opposed to text)
+ Bit 2: Open outfile?
+ Bit 3: Open outfile as binary (as opposed to text)
+ Bit 4: Do not complain about too many file arguments
+ Bit 5: Open one file for input AND output, binary.
+*/
+#define INTEXT (1+0)
+#define INBIN (1+2)
+#define OUTTEXT (4)
+#define OUTBIN (4+8)
+#define NOFILES (0)
+#define NOCOMPLAIN (16)
+#define IOBIN (32)
+
+#ifndef FALSE
+ #define FALSE (0==1)
+ #define TRUE (0==0)
+#endif
+
+extern int samplefrequency;
+extern unsigned short samplewidth;
+extern unsigned short channels;
+extern int wavout; /* TRUE iff out file is .WAV file */
+extern int iswav; /* TRUE iff in file was found to be a .WAV file */
+extern FILE *in, *out;
+extern char *infilename, *outfilename;
+extern int verboselevel;
+extern char *version; /* String to be issued as version string. Should
+ be set by application. */
+extern char *usage; /* String to be issued as usage string. Should be
+ set by application. */
+
+#define DEFAULTFREQ 44100
+#define BUFFSIZE 50000 /* How many samples to read in one go (preferred) */
+#define MINBUFFSIZE 5000 /* How many samples to read in one go (minimum) */
+
+/*************************************************
+ * Types of errors handled by argerrornum() *
+ *************************************************/
+typedef enum
+{
+ ME_NOINT,
+ ME_NODOUBLE,
+ ME_NOTIME,
+ ME_NOVOL,
+ ME_NOSWITCH,
+ ME_TOOMANYFILES,
+ ME_HEADERONTEXTFILE,
+ ME_NOINFILE,
+ ME_NOOUTFILE,
+ ME_NOIOFILE,
+ ME_NOSTDIN,
+ ME_NOSTDOUT,
+ ME_NOSTDIO,
+ ME_NOTENOUGHFILES,
+ ME_THISCANTHAPPEN
+} Errornum;
+
+
+/* -----------------------------------------------------------------------
+ Create memory and copy 'string', returning a pointer to the copy.
+ NULL is returned if malloc fails.
+ -----------------------------------------------------------------------*/
+extern char *malloccopy( char *string);
+
+/* -----------------------------------------------------------------------
+ Start the stopwatch and make sure the user is informed at end of program.
+ -----------------------------------------------------------------------*/
+extern void startstopwatch(void);
+
+/* -----------------------------------------------------------------------
+ Writes the number of samples to result that are yet to be read from anyin.
+ I.e. the number of remaining bytes is divided by the number of bytes per
+ sample value, but not by the number of channels.
+ Return values are TRUE on success, FALSE on failure.
+ -----------------------------------------------------------------------*/
+extern int getremainingfilelength( FILE *anyin, long *result);
+
+/* -----------------------------------------------------------------------
+ Read a .pk-header from 'anyin' and printf the entries.
+ -----------------------------------------------------------------------*/
+void readpkheader( FILE *anyin);
+
+/* -----------------------------------------------------------------------
+ Read a .WAV header from 'anyin'.
+ If it is recognised, the data is used.
+ Otherwise, we assume it's PCM-data and ignore the header.
+ The global variable 'iswav' is set on success, otherwise cleared.
+ -----------------------------------------------------------------------*/
+extern void readwavheader( FILE *anyin);
+
+/* -----------------------------------------------------------------------
+ Write a .WAV header to 'out'.
+ The filepointer is placed at the end of 'out' before operation.
+ This should be called before any data is
+ written, and again, when ALL the data has been written.
+ First time, this positions the file pointer correctly; second time, the
+ missing data can be inserted that wasn't known the first time round.
+ -----------------------------------------------------------------------*/
+extern void makewavheader( void);
+
+/* --------------------------------------------------------------------
+ Tests the character 'coal' for being a command line option character,
+ momentarrily '/' or '-'.
+ -------------------------------------------------------------------- */
+extern int isoptionchar (char coal);
+
+/* -----------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a time and passed
+ to *result, where the result is meant to mean 'number of samples' in
+ that time.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+extern int parsetimearg( int argcount, char *args[], char *string,
+ int *result);
+
+/* -----------------------------------------------------------------------
+ The string argument is read as a time and passed to *result, where
+ the result is meant to mean 'number of samples' in that time. On
+ failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+int parsetime(char *string, int *result);
+
+/* -----------------------------------------------------------------------
+ The string argument is read as a frequency and passed
+ to *result, where the result is meant to mean 'number of samples' in
+ one cycle of that frequency.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -----------------------------------------------------------------------*/
+int parsefreq(char *string, double *result);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for a switch -'string'.
+ return value is TRUE if one exists, FALSE otherwise.
+ If characters remain after the switch, a fatal error is issued.
+ -------------------------------------------------------------------- */
+extern int parseswitcharg( int argcount, char *args[], char *string);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as an integer and
+ passed to &result.
+ On failure, &result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+extern int parseintarg( int argcount, char *args[], char *string,
+ int *result);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for a filename, i.e. anything
+ that does not start with the optionchar. The filename is copied to
+ newly allocated memory, a pointer to which is returned.
+ The argument is marked as used. Therefore repeated use of this function
+ will yield a complete list of filenames on the commandline.
+ If malloc() fails, the function does not return.
+ -------------------------------------------------------------------- */
+extern char *parsefilearg( int argcount, char *args[]);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a double and
+ passed to *result.
+ On failure, *result is unchanged.
+ return value is TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+extern int parsedoublearg( int argcount, char *args[], char *string,
+ double *result);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for an option starting
+ with 'string'. The rest of the option is read as a volume, i.e.
+ absolute, percent or db. The result is passed to *result.
+ On failure, *result is unchanged.
+ -------------------------------------------------------------------- */
+extern int parsevolarg( int argcount, char *args[], char *string,
+ double *result);
+
+/* --------------------------------------------------------------------
+ Reads the specified string and interprets it as a volume. The string
+ would be of the form 1.8 or 180% or 5db.
+ On success, the return value is the relative volume, i.e. 1.8
+ On failure, -1 is returned.
+ -------------------------------------------------------------------- */
+extern int parsevolume(char *s, double *result);
+
+/* --------------------------------------------------------------------
+ Reads through the arguments on the lookout for a switch -'string'.
+ return value is TRUE if one exists, FALSE otherwise.
+ If characters remain after the switch, a fatal error is issued.
+ -------------------------------------------------------------------- */
+extern int parseswitch( char *found, char *wanted);
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line.
+ -------------------------------------------------------------------- */
+extern void argerror(char *s);
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line. 'code' indicates the type of error.
+ -------------------------------------------------------------------- */
+extern void argerrornum(char *s, Errornum code);
+
+/* --------------------------------------------------------------------
+ Reports an error due to parsing the string 's' encountered on the
+ command line. 'message' explains the type of error.
+ -------------------------------------------------------------------- */
+extern void argerrortxt(char *s, char *message);
+
+/* --------------------------------------------------------------------
+ Check for any remaining arguments and complain about their existence.
+ If arguments are found, this function does not return.
+ -------------------------------------------------------------------- */
+extern void checknoargs( int argcount, char *args[]);
+
+/* --------------------------------------------------------------------
+ Parses the command line arguments as represented by the function
+ arguments. Sets the global variables 'in', 'out', 'samplefrequency'
+ and 'samplewidth' accordingly.
+ According to 'fileswitch', in and out files are opened or not. See
+ above for an explanation of 'fileswitch'.
+ -------------------------------------------------------------------- */
+extern void parseargs( int argcount, char *args[], int fileswitch);
+
+/* --------------------------------------------------------------------
+ Returns the index 'i' of the first argument that IS an option, and
+ which begins with the label 's'. If there is none, -1.
+ We also mark that option as done with, i.e. we cross it out.
+ -------------------------------------------------------------------- */
+extern int findoption( int argcount, char *args[], char *s);
+
+/* --------------------------------------------------------------------
+ Finishes off the .WAV header (if any) and exits correctly and formerly.
+ -------------------------------------------------------------------- */
+extern int myexit (int value);
+
+/* --------------------------------------------------------------------
+ Reads the stated input file bufferwise, calls the function 'work'
+ with the proper values, and writes the result to the stated output file.
+ Return value: TRUE on success, FALSE otherwise.
+ -------------------------------------------------------------------- */
+extern int workloop( FILE *theinfile, FILE *theoutfile,
+ int (*work)( short *buffer, int length) );
+
+/* --------------------------------------------------------------------
+ Five functions for printing to stderr. Depending on the level of verbose,
+ output may be supressed. fatalerror() is like error() but does not return.
+ fatalperror() is like the standard function perror() but does not return.
+ -------------------------------------------------------------------- */
+extern int chat( const char *format, ...);
+extern int inform( const char *format, ...);
+extern int error( const char *format, ...);
+extern void fatalerror( const char *format, ...);
+extern void fatalperror( const char *string);
+
+/* --------------------------------------------------------------------
+ And one functions for printing to stdout.
+ -------------------------------------------------------------------- */
+extern int say( const char *format, ...);
+
+/* --------------------------------------------------------------------
+ Allocate memory for it and return a pointer to a string made up of
+ the two argument strings.
+ -------------------------------------------------------------------- */
+extern char *mallocconcat( char *one, char *two);
+
+/* --------------------------------------------------------------------
+ Convert a sample value to decibel.
+ -------------------------------------------------------------------- */
+extern double double2db( double value);
+
+/* --------------------------------------------------------------------
+ Read 'size' samples from file 'in' and lose them.
+ -------------------------------------------------------------------- */
+extern void readawaysamples( FILE *in, size_t size);
diff --git a/utils/muted.c b/utils/muted.c
new file mode 100644
index 000000000..179d596a6
--- /dev/null
+++ b/utils/muted.c
@@ -0,0 +1,709 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * Updated for Mac OSX CoreAudio
+ * by Josh Roberson <josh@asteriasgi.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Mute Daemon
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * Updated for Mac OSX CoreAudio
+ * \arg Josh Roberson <josh@asteriasgi.com>
+ *
+ * \note Specially written for Malcolm Davenport, but I think I'll use it too
+ * Connects to the Asterisk Manager Interface, AMI, and listens for events
+ * on certain devices. If a phone call is connected to one of the devices (phones)
+ * the local sound is muted to a lower volume during the call.
+ *
+ */
+
+#ifdef __Darwin__
+#include <CoreAudio/AudioHardware.h>
+#elif defined(__linux__) || defined(__FreeBSD__)
+#include <sys/soundcard.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+static char *config = "/etc/asterisk/muted.conf";
+
+static char host[256] = "";
+static char user[256] = "";
+static char pass[256] = "";
+static int smoothfade = 0;
+static int mutelevel = 20;
+static int muted = 0;
+static int needfork = 1;
+static int debug = 0;
+static int stepsize = 3;
+#ifndef __Darwin__
+static int mixchan = SOUND_MIXER_VOLUME;
+#endif
+
+struct subchannel {
+ char *name;
+ struct subchannel *next;
+};
+
+static struct channel {
+ char *tech;
+ char *location;
+ struct channel *next;
+ struct subchannel *subs;
+} *channels;
+
+static void add_channel(char *tech, char *location)
+{
+ struct channel *chan;
+ chan = malloc(sizeof(struct channel));
+ if (chan) {
+ memset(chan, 0, sizeof(struct channel));
+ if (!(chan->tech = strdup(tech))) {
+ free(chan);
+ return;
+ }
+ if (!(chan->location = strdup(location))) {
+ free(chan->tech);
+ free(chan);
+ return;
+ }
+ chan->next = channels;
+ channels = chan;
+ }
+
+}
+
+static int load_config(void)
+{
+ FILE *f;
+ char buf[1024];
+ char *val;
+ char *val2;
+ int lineno=0;
+ int x;
+ f = fopen(config, "r");
+ if (!f) {
+ fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
+ return -1;
+ }
+ while(!feof(f)) {
+ if (!fgets(buf, sizeof(buf), f)) {
+ continue;
+ }
+ if (!feof(f)) {
+ lineno++;
+ val = strchr(buf, '#');
+ if (val) *val = '\0';
+ while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
+ buf[strlen(buf) - 1] = '\0';
+ if (!strlen(buf))
+ continue;
+ val = buf;
+ while(*val) {
+ if (*val < 33)
+ break;
+ val++;
+ }
+ if (*val) {
+ *val = '\0';
+ val++;
+ while(*val && (*val < 33)) val++;
+ }
+ if (!strcasecmp(buf, "host")) {
+ if (val && strlen(val))
+ strncpy(host, val, sizeof(host) - 1);
+ else
+ fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
+ } else if (!strcasecmp(buf, "user")) {
+ if (val && strlen(val))
+ strncpy(user, val, sizeof(user) - 1);
+ else
+ fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
+ } else if (!strcasecmp(buf, "pass")) {
+ if (val && strlen(val))
+ strncpy(pass, val, sizeof(pass) - 1);
+ else
+ fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
+ } else if (!strcasecmp(buf, "smoothfade")) {
+ smoothfade = 1;
+ } else if (!strcasecmp(buf, "mutelevel")) {
+ if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
+ mutelevel = x;
+ } else
+ fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
+ } else if (!strcasecmp(buf, "channel")) {
+ if (val && strlen(val)) {
+ val2 = strchr(val, '/');
+ if (val2) {
+ *val2 = '\0';
+ val2++;
+ add_channel(val, val2);
+ } else
+ fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
+ } else
+ fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
+ } else {
+ fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
+ }
+ }
+ }
+ fclose(f);
+ if (!strlen(host))
+ fprintf(stderr, "no 'host' specification in config file\n");
+ else if (!strlen(user))
+ fprintf(stderr, "no 'user' specification in config file\n");
+ else if (!channels)
+ fprintf(stderr, "no 'channel' specifications in config file\n");
+ else
+ return 0;
+ return -1;
+}
+
+static FILE *astf;
+#ifndef __Darwin__
+static int mixfd;
+
+static int open_mixer(void)
+{
+ mixfd = open("/dev/mixer", O_RDWR);
+ if (mixfd < 0) {
+ fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif /* !__Darwin */
+
+/*! Connect to the asterisk manager interface */
+static int connect_asterisk(void)
+{
+ int sock;
+ struct hostent *hp;
+ char *ports;
+ int port = 5038;
+ struct sockaddr_in sin;
+
+ ports = strchr(host, ':');
+ if (ports) {
+ *ports = '\0';
+ ports++;
+ if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
+ fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
+ return -1;
+ }
+ }
+ hp = gethostbyname(host);
+ if (!hp) {
+ fprintf(stderr, "Can't find host '%s'\n", host);
+ return -1;
+ }
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
+ return -1;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+ if (connect(sock, (struct sockaddr *)&sin, sizeof(sin))) {
+ fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
+ close(sock);
+ return -1;
+ }
+ astf = fdopen(sock, "r+");
+ if (!astf) {
+ fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+ return 0;
+}
+
+static char *get_line(void)
+{
+ static char buf[1024];
+ if (fgets(buf, sizeof(buf), astf)) {
+ while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
+ buf[strlen(buf) - 1] = '\0';
+ return buf;
+ } else
+ return NULL;
+}
+
+/*! Login to the asterisk manager interface */
+static int login_asterisk(void)
+{
+ char *welcome;
+ char *resp;
+ if (!(welcome = get_line())) {
+ fprintf(stderr, "disconnected (1)\n");
+ return -1;
+ }
+ fprintf(astf,
+ "Action: Login\r\n"
+ "Username: %s\r\n"
+ "Secret: %s\r\n\r\n", user, pass);
+ if (!(welcome = get_line())) {
+ fprintf(stderr, "disconnected (2)\n");
+ return -1;
+ }
+ if (strcasecmp(welcome, "Response: Success")) {
+ fprintf(stderr, "login failed ('%s')\n", welcome);
+ return -1;
+ }
+ /* Eat the rest of the event */
+ while((resp = get_line()) && strlen(resp));
+ if (!resp) {
+ fprintf(stderr, "disconnected (3)\n");
+ return -1;
+ }
+ fprintf(astf,
+ "Action: Status\r\n\r\n");
+ if (!(welcome = get_line())) {
+ fprintf(stderr, "disconnected (4)\n");
+ return -1;
+ }
+ if (strcasecmp(welcome, "Response: Success")) {
+ fprintf(stderr, "status failed ('%s')\n", welcome);
+ return -1;
+ }
+ /* Eat the rest of the event */
+ while((resp = get_line()) && strlen(resp));
+ if (!resp) {
+ fprintf(stderr, "disconnected (5)\n");
+ return -1;
+ }
+ return 0;
+}
+
+static struct channel *find_channel(char *channel)
+{
+ char tmp[256] = "";
+ char *s, *t;
+ struct channel *chan;
+ strncpy(tmp, channel, sizeof(tmp) - 1);
+ s = strchr(tmp, '/');
+ if (s) {
+ *s = '\0';
+ s++;
+ t = strrchr(s, '-');
+ if (t) {
+ *t = '\0';
+ }
+ if (debug)
+ printf("Searching for '%s' tech, '%s' location\n", tmp, s);
+ chan = channels;
+ while(chan) {
+ if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
+ if (debug)
+ printf("Found '%s'/'%s'\n", chan->tech, chan->location);
+ break;
+ }
+ chan = chan->next;
+ }
+ } else
+ chan = NULL;
+ return chan;
+}
+
+#ifndef __Darwin__
+static int getvol(void)
+{
+ int vol;
+
+ if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
+#else
+static float getvol(void)
+{
+ float volumeL, volumeR, vol;
+ OSStatus err;
+ AudioDeviceID device;
+ UInt32 size;
+ UInt32 channels[2];
+
+ size = sizeof(device);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
+ size = sizeof(channels);
+ if (!err)
+ err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
+ size = sizeof(vol);
+ if (!err)
+ err = AudioDeviceGetProperty(device, channels[0], false, kAudioDevicePropertyVolumeScalar, &size, &volumeL);
+ if (!err)
+ err = AudioDeviceGetProperty(device, channels[1], false, kAudioDevicePropertyVolumeScalar, &size, &volumeR);
+ if (!err)
+ vol = (volumeL < volumeR) ? volumeR : volumeL;
+ else {
+#endif
+ fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
+ return -1;
+ }
+ return vol;
+}
+
+#ifndef __Darwin__
+static int setvol(int vol)
+#else
+static int setvol(float vol)
+#endif
+{
+#ifndef __Darwin__
+ if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
+#else
+ float volumeL = vol;
+ float volumeR = vol;
+ OSStatus err;
+ AudioDeviceID device;
+ UInt32 size;
+ UInt32 channels[2];
+
+ size = sizeof(device);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
+ size = sizeof(channels);
+ err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
+ size = sizeof(vol);
+ if (!err)
+ err = AudioDeviceSetProperty(device, 0, channels[0], false, kAudioDevicePropertyVolumeScalar, size, &volumeL);
+ if (!err)
+ err = AudioDeviceSetProperty(device, 0, channels[1], false, kAudioDevicePropertyVolumeScalar, size, &volumeR);
+ if (err) {
+#endif
+
+ fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
+ return -1;
+
+ }
+ return 0;
+}
+
+#ifndef __Darwin__
+static int oldvol = 0;
+static int mutevol = 0;
+#else
+static float oldvol = 0;
+static float mutevol = 0;
+#endif
+
+#ifndef __Darwin__
+static int mutedlevel(int orig, int mutelevel)
+{
+ int l = orig >> 8;
+ int r = orig & 0xff;
+ l = (float)(mutelevel) * (float)(l) / 100.0;
+ r = (float)(mutelevel) * (float)(r) / 100.0;
+
+ return (l << 8) | r;
+#else
+static float mutedlevel(float orig, float mutelevel)
+{
+ float master = orig;
+ master = mutelevel * master / 100.0;
+ return master;
+#endif
+
+}
+
+static void mute(void)
+{
+#ifndef __Darwin__
+ int vol;
+ int start;
+ int x;
+#else
+ float vol;
+ float start = 1.0;
+ float x;
+#endif
+ vol = getvol();
+ oldvol = vol;
+ if (smoothfade)
+#ifdef __Darwin__
+ start = mutelevel;
+#else
+ start = 100;
+ else
+ start = mutelevel;
+#endif
+ for (x=start;x>=mutelevel;x-=stepsize) {
+ mutevol = mutedlevel(vol, x);
+ setvol(mutevol);
+ /* Wait 0.01 sec */
+ usleep(10000);
+ }
+ mutevol = mutedlevel(vol, mutelevel);
+ setvol(mutevol);
+ if (debug)
+#ifdef __Darwin__
+ printf("Mute from '%f' to '%f'!\n", oldvol, mutevol);
+#else
+ printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
+#endif
+ muted = 1;
+}
+
+static void unmute(void)
+{
+#ifdef __Darwin__
+ float vol;
+ float start;
+ float x;
+#else
+ int vol;
+ int start;
+ int x;
+#endif
+ vol = getvol();
+ if (debug)
+#ifdef __Darwin__
+ printf("Unmute from '%f' (should be '%f') to '%f'!\n", vol, mutevol, oldvol);
+ mutevol = vol;
+ if (vol == mutevol) {
+#else
+ printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
+ if ((int)vol == mutevol) {
+#endif
+ if (smoothfade)
+ start = mutelevel;
+ else
+#ifdef __Darwin__
+ start = 1.0;
+#else
+ start = 100;
+#endif
+ for (x=start;x<100;x+=stepsize) {
+ mutevol = mutedlevel(oldvol, x);
+ setvol(mutevol);
+ /* Wait 0.01 sec */
+ usleep(10000);
+ }
+ setvol(oldvol);
+ } else
+ printf("Whoops, it's already been changed!\n");
+ muted = 0;
+}
+
+static void check_mute(void)
+{
+ int offhook = 0;
+ struct channel *chan;
+ chan = channels;
+ while(chan) {
+ if (chan->subs) {
+ offhook++;
+ break;
+ }
+ chan = chan->next;
+ }
+ if (offhook && !muted)
+ mute();
+ else if (!offhook && muted)
+ unmute();
+}
+
+static void delete_sub(struct channel *chan, char *name)
+{
+ struct subchannel *sub, *prev;
+ prev = NULL;
+ sub = chan->subs;
+ while(sub) {
+ if (!strcasecmp(sub->name, name)) {
+ if (prev)
+ prev->next = sub->next;
+ else
+ chan->subs = sub->next;
+ free(sub->name);
+ free(sub);
+ return;
+ }
+ prev = sub;
+ sub = sub->next;
+ }
+}
+
+static void append_sub(struct channel *chan, char *name)
+{
+ struct subchannel *sub;
+ sub = chan->subs;
+ while(sub) {
+ if (!strcasecmp(sub->name, name))
+ return;
+ sub = sub->next;
+ }
+ sub = malloc(sizeof(struct subchannel));
+ if (sub) {
+ memset(sub, 0, sizeof(struct subchannel));
+ if (!(sub->name = strdup(name))) {
+ free(sub);
+ return;
+ }
+ sub->next = chan->subs;
+ chan->subs = sub;
+ }
+}
+
+static void hangup_chan(char *channel)
+{
+ struct channel *chan;
+ if (debug)
+ printf("Hangup '%s'\n", channel);
+ chan = find_channel(channel);
+ if (chan)
+ delete_sub(chan, channel);
+ check_mute();
+}
+
+static void offhook_chan(char *channel)
+{
+ struct channel *chan;
+ if (debug)
+ printf("Offhook '%s'\n", channel);
+ chan = find_channel(channel);
+ if (chan)
+ append_sub(chan, channel);
+ check_mute();
+}
+
+static int wait_event(void)
+{
+ char *resp;
+ char event[120]="";
+ char channel[120]="";
+ char oldname[120]="";
+ char newname[120]="";
+
+ resp = get_line();
+ if (!resp) {
+ fprintf(stderr, "disconnected (6)\n");
+ return -1;
+ }
+ if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
+ strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
+ /* Consume the rest of the non-event */
+ while((resp = get_line()) && strlen(resp)) {
+ if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
+ strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
+ if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
+ strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
+ if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
+ strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
+ }
+ if (strlen(channel)) {
+ if (!strcasecmp(event, "Hangup"))
+ hangup_chan(channel);
+ else
+ offhook_chan(channel);
+ }
+ if (strlen(newname) && strlen(oldname)) {
+ if (!strcasecmp(event, "Rename")) {
+ hangup_chan(oldname);
+ offhook_chan(newname);
+ }
+ }
+ } else {
+ /* Consume the rest of the non-event */
+ while((resp = get_line()) && strlen(resp));
+ }
+ if (!resp) {
+ fprintf(stderr, "disconnected (7)\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: muted [-f] [-d]\n"
+ " -f : Do not fork\n"
+ " -d : Debug (implies -f)\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int x;
+ while((x = getopt(argc, argv, "fhd")) > 0) {
+ switch(x) {
+ case 'd':
+ debug = 1;
+ needfork = 0;
+ break;
+ case 'f':
+ needfork = 0;
+ break;
+ case 'h':
+ /* Fall through */
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ if (load_config())
+ exit(1);
+#ifndef __Darwin__
+ if (open_mixer())
+ exit(1);
+#endif
+ if (connect_asterisk()) {
+#ifndef __Darwin__
+ close(mixfd);
+#endif
+ exit(1);
+ }
+ if (login_asterisk()) {
+#ifndef __Darwin__
+ close(mixfd);
+#endif
+ fclose(astf);
+ exit(1);
+ }
+ if (needfork) {
+#ifndef HAVE_SBIN_LAUNCHD
+ if (daemon(0,0) < 0) {
+ fprintf(stderr, "daemon() failed: %s\n", strerror(errno));
+ exit(1);
+ }
+#else
+ fprintf(stderr, "Mac OS X detected. Use 'launchd -d muted -f' to launch.\n");
+ exit(1);
+#endif
+ }
+ for(;;) {
+ if (wait_event()) {
+ fclose(astf);
+ while(connect_asterisk()) {
+ sleep(5);
+ }
+ if (login_asterisk()) {
+ fclose(astf);
+ exit(1);
+ }
+ }
+ }
+ exit(0);
+}
diff --git a/utils/smsq.c b/utils/smsq.c
new file mode 100644
index 000000000..4b52ce7ef
--- /dev/null
+++ b/utils/smsq.c
@@ -0,0 +1,768 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2004 - 2005
+ *
+ * SMS queuing application for use with asterisk app_sms
+ * by Adrian Kennard
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include <stdio.h>
+#include <popt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+
+#include <asterisk/compat.h>
+#ifdef SOLARIS
+#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000
+#endif
+#if !defined(POPT_ARGFLAG_SHOW_DEFAULT)
+#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000
+#endif
+
+
+/* reads next USC character from null terminated UTF-8 string and advanced pointer */
+/* for non valid UTF-8 sequences, returns character as is */
+/* Does not advance pointer for null termination */
+static int utf8decode (unsigned char **pp)
+{
+ unsigned char *p = *pp;
+ if (!*p)
+ return 0; /* null termination of string */
+ (*pp)++;
+ if (*p < 0xC0)
+ return *p; /* ascii or continuation character */
+ if (*p < 0xE0)
+ {
+ if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
+ return *p; /* not valid UTF-8 */
+ (*pp)++;
+ return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
+ }
+ if (*p < 0xF0)
+ {
+ if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
+ return *p; /* not valid UTF-8 */
+ (*pp) += 2;
+ return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
+ }
+ if (*p < 0xF8)
+ {
+ if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
+ return *p; /* not valid UTF-8 */
+ (*pp) += 3;
+ return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
+ }
+ if (*p < 0xFC)
+ {
+ if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
+ || (p[4] & 0xC0) != 0x80)
+ return *p; /* not valid UTF-8 */
+ (*pp) += 4;
+ return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
+ }
+ if (*p < 0xFE)
+ {
+ if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
+ || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
+ return *p; /* not valid UTF-8 */
+ (*pp) += 5;
+ return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) +
+ (p[5] & 0x3F);
+ }
+ return *p; /* not sensible */
+}
+
+/* check for any queued messages in specific queue (queue="" means any queue) */
+/* returns 0 if nothing queued, 1 if queued and outgoing set up OK, 2 of outgoing exists */
+static char txqcheck (char *dir, char *queue, char subaddress, char *channel, char *callerid, int wait, int delay, int retries, int concurrent)
+{
+ char ogname[100],
+ temp[100],
+ dirname[100],
+ *p=NULL;
+ FILE *f;
+ DIR *d;
+ int ql = strlen (queue), qfl = ql;
+ struct dirent *fn;
+ snprintf (dirname, sizeof(dirname), "sms/%s", dir);
+ d = opendir (dirname);
+ if (!d)
+ return 0;
+ while ((fn = readdir (d))
+ && !(*fn->d_name != '.'
+ && ((!ql && (p = strchr (fn->d_name, '.'))) || (ql && !strncmp (fn->d_name, queue, ql) && fn->d_name[ql] == '.'))));
+ if (!fn)
+ {
+ closedir (d);
+ return 0;
+ }
+ if (!ql)
+ { /* not searching any specific queue, so use whatr we found as the queue */
+ queue = fn->d_name;
+ qfl = ql = p - queue;
+ }
+ p = strchr (queue, '-');
+ if (p && p < queue + ql)
+ {
+ ql = p - queue;
+ subaddress = p[1];
+ }
+ snprintf (temp, sizeof(temp), "sms/.smsq-%d", (int)getpid ());
+ f = fopen (temp, "w");
+ if (!f)
+ {
+ perror (temp);
+ closedir (d);
+ return 0;
+ }
+ fprintf (f, "Channel: ");
+ if (!channel)
+ fprintf (f, "Local/%.*s\n", ql, queue);
+ else
+ {
+ p = strchr (channel, '/');
+ if (!p)
+ p = channel;
+ p = strchr (p, 'X');
+ if (p)
+ fprintf (f, "%.*s%c%s\n", (int)(p - channel), channel, subaddress, p + 1);
+ else
+ fprintf (f, "%s\n", channel);
+ }
+ fprintf (f, "Callerid: SMS <");
+ if (!callerid)
+ fprintf (f, "%.*s", ql, queue);
+ else
+ {
+ p = strchr (callerid, 'X');
+ if (p)
+ fprintf (f, "%.*s%c%s", (int)(p - callerid), callerid, subaddress, p + 1);
+ else
+ fprintf (f, "%s", callerid);
+ }
+ fprintf (f, ">\n");
+ fprintf (f, "Application: SMS\n");
+ fprintf (f, "Data: %.*s", qfl, queue);
+ if (dir[1] == 't')
+ fprintf (f, "|s");
+ fprintf (f, "\nMaxRetries: %d\n", retries);
+ fprintf (f, "RetryTime: %d\n", delay);
+ fprintf (f, "WaitTime: %d\n", wait);
+ fclose (f);
+ closedir (d);
+ {
+ int try = 0;
+ while (try < concurrent)
+ {
+ try++;
+ snprintf(ogname, sizeof(ogname), "outgoing/smsq.%s.%s.%d", dir, queue, try);
+ if (!link (temp, ogname))
+ { /* queued OK */
+ unlink (temp);
+ return 1;
+ }
+ }
+ }
+ /* failed to create call queue */
+ unlink (temp);
+ return 2;
+}
+
+/* Process received queue entries and run through a process, setting environment variables */
+static void rxqcheck (char *dir, char *queue, char *process)
+{
+ char *p;
+ void *pp = &p;
+ char dirname[100],
+ temp[100];
+ DIR *d;
+ int ql = strlen (queue);
+ struct dirent *fn;
+ snprintf(temp, sizeof(temp), "sms/.smsq-%d", (int)getpid ());
+ snprintf(dirname, sizeof(dirname), "sms/%s", dir);
+ d = opendir (dirname);
+ if (!d)
+ return;
+ while ((fn = readdir (d)))
+ if ((*fn->d_name != '.'
+ && ((!ql && (p = strchr (fn->d_name, '.'))) || (ql && !strncmp (fn->d_name, queue, ql) && fn->d_name[ql] == '.'))))
+ { /* process file */
+ char filename[1010];
+ char line[1000];
+ unsigned short ud[160];
+ unsigned char udl = 0;
+ FILE *f;
+ snprintf (filename, sizeof(filename), "sms/%s/%s", dir, fn->d_name);
+ if (rename (filename, temp))
+ continue; /* cannot access file */
+ f = fopen (temp, "r");
+ unlink (temp);
+ if (!f)
+ {
+ perror (temp);
+ continue;
+ }
+ unsetenv ("oa");
+ unsetenv ("da");
+ unsetenv ("scts");
+ unsetenv ("pid");
+ unsetenv ("dcs");
+ unsetenv ("mr");
+ unsetenv ("srr");
+ unsetenv ("rp");
+ unsetenv ("vp");
+ unsetenv ("udh");
+ unsetenv ("ud");
+ unsetenv ("ude");
+ unsetenv ("ud8");
+ unsetenv ("ud16");
+ unsetenv ("morx");
+ unsetenv ("motx");
+ unsetenv ("queue");
+ if (*queue)
+ setenv ("queue", queue, 1);
+ setenv (dir, "", 1);
+ while (fgets (line, sizeof (line), f))
+ {
+ for (p = line; *p && *p != '\n' && *p != '\r'; p++);
+ *p = 0; /* strip eoln */
+ p = line;
+ if (!*p || *p == ';')
+ continue; /* blank line or comment, ignore */
+ while (isalnum (*p))
+ {
+ *p = tolower (*p);
+ p++;
+ }
+ while (isspace (*p))
+ *p++ = 0;
+ if (*p == '=')
+ { /* = */
+ *p++ = 0;
+ if (!strcmp (line, "oa") || !strcmp (line, "da") || !strcmp (line, "scts") || !strcmp (line, "pid")
+ || !strcmp (line, "dcs") || !strcmp (line, "mr") || !strcmp (line, "vp"))
+ setenv (line, p, 1);
+ else if ((!strcmp (line, "srr") || !strcmp (line, "rp")) && atoi (p))
+ setenv (line, "", 1);
+ else if (!strcmp (line, "ud"))
+ { /* read the user data as UTF-8 */
+ long v;
+ udl = 0;
+ while ((v = utf8decode (pp)) && udl < 160)
+ if (v && v <= 0xFFFF)
+ ud[udl++] = v;
+ }
+ } else if (*p == '#')
+ {
+ *p++ = 0;
+ if (*p == '#')
+ { /* ## */
+ p++;
+ if (!strcmp (line, "udh"))
+ setenv (line, p, 1);
+ else if (!strcmp (line, "ud"))
+ { /* read user data UCS-2 */
+ udl = 0;
+ while (*p && udl < 160)
+ {
+ if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
+ {
+ ud[udl++] =
+ (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
+ (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
+ (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
+ p += 4;
+ } else
+ break;
+ }
+ }
+ } else
+ { /* # */
+ if (!strcmp (line, "ud"))
+ { /* read user data UCS-1 */
+ udl = 0;
+ while (*p && udl < 160)
+ {
+ if (isxdigit (*p) && isxdigit (p[1]))
+ {
+ ud[udl++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
+ p += 2;
+ } else
+ break;
+ }
+ }
+ }
+ }
+ }
+ fclose (f);
+ /* set up user data variables */
+ {
+ char temp[481];
+ int n,
+ p;
+ for (n = 0, p = 0; p < udl; p++)
+ {
+ unsigned short v = ud[p];
+ if (v)
+ {
+ if (v < 0x80)
+ temp[n++] = v;
+ else if (v < 0x800)
+ {
+ temp[n++] = (0xC0 + (v >> 6));
+ temp[n++] = (0x80 + (v & 0x3F));
+ } else
+ {
+ temp[n++] = (0xE0 + (v >> 12));
+ temp[n++] = (0x80 + ((v >> 6) & 0x3F));
+ temp[n++] = (0x80 + (v & 0x3F));
+ }
+ }
+ }
+ temp[n] = 0;
+ setenv ("ud", temp, 1);
+ for (n = 0, p = 0; p < udl; p++)
+ {
+ unsigned short v = ud[p];
+ if (v < ' ' || v == '\\')
+ {
+ temp[n++] = '\\';
+ if (v == '\\')
+ temp[n++] = '\\';
+ else if (v == '\n')
+ temp[n++] = 'n';
+ else if (v == '\r')
+ temp[n++] = 'r';
+ else if (v == '\t')
+ temp[n++] = 't';
+ else if (v == '\f')
+ temp[n++] = 'f';
+ else
+ {
+ temp[n++] = '0' + (v >> 6);
+ temp[n++] = '0' + ((v >> 3) & 7);
+ temp[n++] = '0' + (v & 7);
+ }
+ } else if (v < 0x80)
+ temp[n++] = v;
+ else if (v < 0x800)
+ {
+ temp[n++] = (0xC0 + (v >> 6));
+ temp[n++] = (0x80 + (v & 0x3F));
+ } else
+ {
+ temp[n++] = (0xE0 + (v >> 12));
+ temp[n++] = (0x80 + ((v >> 6) & 0x3F));
+ temp[n++] = (0x80 + (v & 0x3F));
+ }
+ }
+ temp[n] = 0;
+ setenv ("ude", temp, 1);
+ for (p = 0; p < udl && ud[p] < 0x100; p++);
+ if (p == udl)
+ {
+ for (n = 0, p = 0; p < udl; p++)
+ {
+ sprintf (temp + n, "%02X", ud[p]);
+ n += 2;
+ }
+ setenv ("ud8", temp, 1);
+ }
+ for (n = 0, p = 0; p < udl; p++)
+ {
+ sprintf (temp + n, "%04X", ud[p]);
+ n += 4;
+ }
+ setenv ("ud16", temp, 1);
+ }
+ /* run the command */
+ if (system (process) == -1) {
+ fprintf(stderr, "Failed to fork process '%s'\n", process);
+ }
+ }
+ closedir (d);
+}
+
+/* Main app */
+int
+main (int argc, const char *argv[])
+{
+ char c;
+ int mt = 0,
+ mo = 0,
+ tx = 0,
+ rx = 0,
+ nodial = 0,
+ nowait = 0,
+ concurrent = 1,
+ motxwait = 10,
+ motxdelay = 1,
+ motxretries = 10,
+ mttxwait = 10,
+ mttxdelay = 30,
+ mttxretries = 100,
+ mr = -1,
+ pid = -1,
+ dcs = -1,
+ srr = 0,
+ rp = 0,
+ vp = 0,
+ udl = 0,
+ utf8 = 0,
+ ucs1 = 0,
+ ucs2 = 0;
+ unsigned short ud[160];
+ unsigned char *uds = 0,
+ *udh = 0;
+ char *da = 0,
+ *oa = 0,
+ *queue = "",
+ *udfile = 0,
+ *process = 0,
+ *spooldir = "/var/spool/asterisk",
+ *motxchannel = "Local/1709400X",
+ *motxcallerid = 0,
+ *mttxchannel = 0,
+ *mttxcallerid = "080058752X0",
+ *defaultsubaddress = "9",
+ subaddress = 0,
+ *scts = 0;
+ poptContext optCon; /* context for parsing command-line options */
+ const struct poptOption optionsTable[] = {
+ {"queue", 'q', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &queue, 0, "Queue [inc sub address]", "number[-X]"},
+ {"da", 'd', POPT_ARG_STRING, &da, 0, "Destination address", "number"},
+ {"oa", 'o', POPT_ARG_STRING, &oa, 0, "Origination address", "number"},
+ {"ud", 'm', POPT_ARG_STRING, &uds, 0, "Message", "text"},
+ {"ud-file", 'f', POPT_ARG_STRING, &udfile, 0, "Message file", "filename"},
+ {"UTF-8", 0, POPT_ARG_NONE, &utf8, 0, "File treated as null terminated UTF-8 (default)", 0},
+ {"UCS-1", 0, POPT_ARG_NONE, &ucs1, 0, "File treated as UCS-1", 0},
+ {"UCS-2", 0, POPT_ARG_NONE, &ucs2, 0, "File treated as UCS-2", 0},
+ {"mt", 't', POPT_ARG_NONE, &mt, 0, "Mobile Terminated", 0},
+ {"mo", 0, POPT_ARG_NONE, &mo, 0, "Mobile Originated", 0},
+ {"tx", 0, POPT_ARG_NONE, &tx, 0, "Send message", 0},
+ {"rx", 'r', POPT_ARG_NONE, &rx, 0, "Queue for receipt", 0},
+ {"process", 'e', POPT_ARG_STRING, &process, 0, "Rx queue process command", "command"},
+ {"no-dial", 'x', POPT_ARG_NONE, &nodial, 0, "Do not dial", 0},
+ {"no-wait", 0, POPT_ARG_NONE, &nowait, 0, "Do not wait if already calling", 0},
+ {"concurrent", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &concurrent, 0, "Number of concurrent calls to allow", "n"},
+ {"motx-channel", 0, POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &motxchannel, 0, "Channel for motx calls", "channel"},
+ {"motx-callerid", 0, POPT_ARG_STRING, &motxcallerid, 0,
+ "Caller ID for motx calls (default is queue name without sub address)", "number"},
+ {"motx-wait", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &motxwait, 0, "Time to wait for motx call to answer",
+ "seconds"},
+ {"motx-delay", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &motxdelay, 0, "Time between motx call retries", "seconds"},
+ {"motx-retries", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &motxretries, 0, "Number of retries for motx call", "n"},
+ {"mttx-channel", 0, POPT_ARG_STRING, &mttxchannel, 0,
+ "Channel for mttx calls (default is Local/ and queue name without sub address)", "channel"},
+ {"mttx-callerid", 0, POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &mttxcallerid, 0,
+ "Caller ID for mttx calls (default is queue name without sub address)", "number"},
+ {"mttx-wait", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &mttxwait, 0, "Time to wait for mttx call to answer",
+ "seconds"},
+ {"mttx-delay", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &mttxdelay, 0, "Time between mttx call retries", "seconds"},
+ {"mttx-retries", 0, POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &mttxretries, 0, "Number of retries for mttx call", "n"},
+ {"mr", 'n', POPT_ARG_INT, &mr, 0, "Message reference", "n"},
+ {"pid", 'p', POPT_ARG_INT, &pid, 0, "Protocol ID", "n"},
+ {"dcs", 'c', POPT_ARG_INT, &dcs, 0, "Data Coding Scheme", "n"},
+ {"udh", 0, POPT_ARG_STRING, &udh, 0, "User data header", "hex"},
+ {"srr", 0, POPT_ARG_NONE, &srr, 0, "Status Report Request", 0},
+ {"rp", 0, POPT_ARG_NONE, &rp, 0, "Return Path request", 0},
+ {"v", 0, POPT_ARG_INT, &vp, 0, "Validity Period", "seconds"},
+ {"scts", 0, POPT_ARG_STRING, &scts, 0, "Timestamp", "YYYY-MM-SSTHH:MM:SS"},
+ {"default-sub-address", 0, POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &defaultsubaddress, 0, "Default sub address", "X"},
+ {"spool-dir", 0, POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &spooldir, 0, "Asterisk spool dir", "dirname"},
+ POPT_AUTOHELP {NULL, 0, 0, NULL, 0}
+ };
+
+ optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
+ poptSetOtherOptionHelp (optCon, "<oa/da> <message>");
+
+ /* Now do options processing, get portname */
+ if ((c = poptGetNextOpt (optCon)) < -1)
+ {
+ /* an error occurred during option processing */
+ fprintf (stderr, "%s: %s\n", poptBadOption (optCon, POPT_BADOPTION_NOALIAS), poptStrerror (c));
+ return 1;
+ }
+ if (!ucs1 && !ucs2)
+ utf8 = 1;
+ if (utf8 + ucs1 + ucs2 > 1)
+ {
+ fprintf (stderr, "Pick one of UTF-8, UCS-1 or UCS-2 only\n");
+ return 1;
+ }
+ if (!udfile && (ucs1 || ucs2))
+ {
+ fprintf (stderr, "Command line arguments always treated as UTF-8\n");
+ return 1;
+ }
+ /* if (!where && poptPeekArg (optCon)) where = (char *) poptGetArg (optCon); */
+ if (!mt && !mo && process)
+ mt = 1;
+ if (!mt && !mo && oa)
+ mt = 1;
+ if (!mt)
+ mo = 1;
+ if (mt && mo)
+ {
+ fprintf (stderr, "Cannot be --mt and --mo\n");
+ return 1;
+ }
+ if (!rx && !tx && process)
+ rx = 1;
+ if (!rx)
+ tx = 1;
+ if (tx && rx)
+ {
+ fprintf (stderr, "Cannot be --tx and --rx\n");
+ return 1;
+ }
+ if (rx)
+ nodial = 1;
+ if (uds && udfile)
+ {
+ fprintf (stderr, "Cannot have --ud and --ud-file\n");
+ return 1;
+ }
+ if (mo && !da && poptPeekArg (optCon))
+ da = (char *) poptGetArg (optCon);
+ if (mt && !oa && poptPeekArg (optCon))
+ oa = (char *) poptGetArg (optCon);
+ if (tx && oa && mo)
+ {
+ fprintf (stderr, "--oa makes no sense with --mo as CLI is used (i.e. queue name)\n");
+ return 1;
+ }
+ if (tx && da && mt)
+ {
+ fprintf (stderr, "--da makes no sense with --mt as called number is used (i.e. queue name)\n");
+ return 1;
+ }
+ if (da && strlen (da) > 20)
+ {
+ fprintf (stderr, "--da too long\n");
+ return 1;
+ }
+ if (oa && strlen (oa) > 20)
+ {
+ fprintf (stderr, "--oa too long\n");
+ return 1;
+ }
+ if (queue && strlen (queue) > 20)
+ {
+ fprintf (stderr, "--queue name too long\n");
+ return 1;
+ }
+ if (mo && scts)
+ {
+ fprintf (stderr, "scts is set my service centre\n");
+ return 1;
+ }
+ if (uds)
+ { /* simple user data command line option in \UTF-8 */
+ while (udl < 160 && *uds)
+ {
+ int v = utf8decode (&uds);
+ if (v > 0xFFFF)
+ {
+ fprintf (stderr, "Invalid character U+%X at %d\n", v, udl);
+ return 1;
+ }
+ ud[udl++] = v;
+ }
+ }
+ if (!uds && !udfile && poptPeekArg (optCon))
+ { /* multiple command line arguments in UTF-8 */
+ while (poptPeekArg (optCon) && udl < 160)
+ {
+ unsigned char *a = (unsigned char *) poptGetArg (optCon);
+ if (udl && udl < 160)
+ ud[udl++] = ' '; /* space between arguments */
+ while (udl < 160 && *a)
+ {
+ int v = utf8decode (&a);
+ if (v > 0xFFFF)
+ {
+ fprintf (stderr, "Invalid character U+%X at %d\n", v, udl);
+ return 1;
+ }
+ ud[udl++] = v;
+ }
+ }
+ }
+ if (poptPeekArg (optCon))
+ {
+ fprintf (stderr, "Unknown argument %s\n", poptGetArg (optCon));
+ return 1;
+ }
+ if (udfile)
+ { /* get message from file */
+ unsigned char dat[1204],
+ *p = dat,
+ *e;
+ int f,
+ n;
+ if (*udfile)
+ f = open (udfile, O_RDONLY);
+ else
+ f = fileno (stdin);
+ if (f < 0)
+ {
+ perror (udfile);
+ return 1;
+ }
+ n = read (f, dat, sizeof (dat));
+ if (n < 0)
+ {
+ perror (udfile);
+ return 1;
+ }
+ if (*udfile)
+ close (f);
+ e = dat + n;
+ if (utf8)
+ { /* UTF-8 */
+ while (p < e && udl < 160 && *p)
+ ud[udl++] = utf8decode (&p);
+ } else if (ucs1)
+ { /* UCS-1 */
+ while (p < e && udl < 160)
+ ud[udl++] = *p++;
+ } else
+ { /* UCS-2 */
+ while (p + 1 < e && udl < 160)
+ {
+ ud[udl++] = (*p << 8) + p[1];
+ p += 2;
+ }
+ }
+ }
+ if (queue)
+ {
+ char *d = strrchr (queue, '-');
+ if (d && d[1])
+ subaddress = d[1];
+ else
+ subaddress = *defaultsubaddress;
+ }
+
+ if (chdir (spooldir))
+ {
+ perror (spooldir);
+ return 1;
+ }
+
+ if (oa || da)
+ { /* send message */
+ char temp[100],
+ queuename[100],
+ *dir = (mo ? rx ? "sms/morx" : "sms/motx" : rx ? "sms/mtrx" : "sms/mttx");
+ FILE *f;
+ snprintf (temp, sizeof(temp), "sms/.smsq-%d", (int)getpid ());
+ mkdir ("sms", 0777); /* ensure directory exists */
+ mkdir (dir, 0777); /* ensure directory exists */
+ snprintf (queuename, sizeof(queuename), "%s/%s.%ld-%d", dir, *queue ? queue : "0", (long)time (0), (int)getpid ());
+ f = fopen (temp, "w");
+ if (!f)
+ {
+ perror (temp);
+ return 1;
+ }
+ if (oa)
+ fprintf (f, "oa=%s\n", oa);
+ if (da)
+ fprintf (f, "da=%s\n", da);
+ if (scts)
+ fprintf (f, "scts=%s\n", scts);
+ if (pid >= 0)
+ fprintf (f, "pid=%d\n", pid);
+ if (dcs >= 0)
+ fprintf (f, "dcs=%d\n", dcs);
+ if (mr >= 0)
+ fprintf (f, "mr=%d\n", mr);
+ if (srr)
+ fprintf (f, "srr=1\n");
+ if (rp)
+ fprintf (f, "rp=1\n");
+ if (udh)
+ fprintf (f, "udh#%s\n", udh);
+ if (vp > 0)
+ fprintf (f, "vp=%d\n", vp);
+ if (udl)
+ {
+ int p;
+ for (p = 0; p < udl && ud[p] < 0x100; p++);
+ if (p == udl)
+ {
+ for (p = 0; p < udl && ud[p] < 0x80 && ud[p] >= 0x20; p++);
+ if (p == udl)
+ { /* use text */
+ fprintf (f, "ud=");
+ for (p = 0; p < udl; p++)
+ fputc (ud[p], f);
+ } else
+ { /* use one byte hex */
+ fprintf (f, "ud#");
+ for (p = 0; p < udl; p++)
+ fprintf (f, "%02X", ud[p]);
+ }
+ } else
+ { /* use two byte hex */
+ fprintf (f, "ud##");
+ for (p = 0; p < udl; p++)
+ fprintf (f, "%04X", ud[p]);
+ }
+ fprintf (f, "\n");
+ }
+ fclose (f);
+ if (rename (temp, queuename))
+ {
+ perror (queuename);
+ unlink (temp);
+ return 1;
+ }
+ }
+
+ if (!nodial && tx && !process)
+ { /* dial to send messages */
+ char ret=0,
+ try = 3;
+ if (nowait)
+ try = 1;
+ while (try--)
+ {
+ if (mo)
+ ret = txqcheck ("motx", queue, subaddress, motxchannel, motxcallerid, motxwait, motxdelay, motxretries, concurrent);
+ else
+ ret = txqcheck ("mttx", queue, subaddress, mttxchannel, mttxcallerid, mttxwait, mttxdelay, mttxretries, concurrent);
+ if (ret < 2)
+ break; /* sent, or queued OK */
+ if (try)
+ sleep (1);
+ }
+ if (ret == 2 && !nowait)
+ fprintf (stderr, "No call scheduled as already sending\n");
+ }
+ if (process)
+ rxqcheck (mo ? rx ? "morx" : "motx" : rx ? "mtrx" : "mttx", queue, process);
+
+ return 0;
+}
diff --git a/utils/stereorize.c b/utils/stereorize.c
new file mode 100644
index 000000000..c8428320d
--- /dev/null
+++ b/utils/stereorize.c
@@ -0,0 +1,159 @@
+/****************************************************************************
+ *
+ * Programs for processing sound files in raw- or WAV-format.
+ * -- Merge two mono WAV-files to one stereo WAV-file.
+ *
+ * Name: stereorize.c
+ * Version: 1.1
+ * Author: Mark Roberts <mark@manumark.de>
+ * Michael Labuschke <michael@labuschke.de>
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <assert.h>
+#include "frame.h"
+
+static char *Version = "stereorize 1.1, November 5th 2000";
+static char *Usage =
+"Usage: stereorize [options] infile-left infile-right outfile\n\n"
+
+"Example:\n"
+" stereorize left.wav right.wav stereo.wav -h\n\n"
+
+"Creates stereo.wav (with WAV-header, option -h) from data in mono files\n"
+"left.wav and right.wav.\n"
+;
+
+int main( int argcount, char *args[])
+{
+ int i, k[2], maxk, stdin_in_use=FALSE;
+ short *leftsample, *rightsample, *stereosample;
+ FILE *channel[2];
+ char *filename[2], *tempname;
+
+ version = Version;
+ usage = Usage;
+
+ channel[0] = NULL;
+ channel[1] = NULL;
+
+ parseargs( argcount, args, NOFILES | NOCOMPLAIN);
+
+ for (i = 0; i < 2; i++)
+ {
+ filename[i] = parsefilearg( argcount, args);
+ if (filename[i] == NULL)
+ argerrornum( NULL, ME_NOTENOUGHFILES);
+ if (strcmp (filename[i], "-") == 0)
+ {
+ if (stdin_in_use)
+ argerrortxt( filename[i] + 1,
+ "Cannot use <stdin> for both input files");
+ filename[i] = "<stdin>";
+ channel[i] = stdin;
+ stdin_in_use = TRUE;
+ }
+ else
+ {
+ channel[i] = fopen(filename[i], "rb");
+ }
+ if (channel[i] == NULL)
+ fatalerror( "Error opening input file '%s': %s\n", filename[i],strerror(errno));
+ else
+ inform("Using file '%s' as input\n", filename[i]);
+ }
+ for (i = 0; i < 2; i++)
+ {
+ assert ( channel[i] != NULL);
+ readwavheader( channel[i]);
+ if (iswav && channels != 1)
+ inform("Warning: '%s' is no mono file\n", filename[i]);
+ }
+
+ outfilename = parsefilearg( argcount, args);
+ if (outfilename == NULL) argerrornum( NULL, ME_NOOUTFILE);
+ if (strcmp (outfilename, "-") == 0)
+ {
+ outfilename = "<stdout>";
+ out = stdout;
+ }
+ else
+ {
+ out = fopen(outfilename, "wb");
+ }
+ if (out == NULL)
+ fatalerror( "Error opening output file '%s': %s\n", outfilename,strerror(errno));
+ else
+ inform("Using file '%s' as output\n", outfilename);
+
+ if ((tempname = parsefilearg( argcount, args)) != NULL)
+ argerrornum( tempname, ME_TOOMANYFILES);
+
+ checknoargs(argcount, args); /* Check that no arguments are left */
+
+ leftsample = malloc( sizeof(*leftsample) * BUFFSIZE);
+ rightsample = malloc( sizeof(*leftsample) * BUFFSIZE);
+ stereosample = malloc( sizeof(*leftsample) * 2 * BUFFSIZE);
+ if (leftsample == NULL || rightsample == NULL || stereosample == NULL)
+ fatalperror ("");
+
+ channels = 2; /* Output files are stereo */
+ if (wavout)
+ {
+ if ((strcmp(outfilename,"<stdout>")!=0) && (fseek( out, 0, SEEK_SET) != 0))
+ fatalerror("Couldn't navigate output file '%s': %s\n",outfilename, strerror(errno));
+ makewavheader();
+ }
+
+ startstopwatch();
+ while (TRUE)
+ {
+ maxk = 0;
+ for (i = 0; i < 2; i++)
+ {
+ k[i] = fread(i==0? leftsample : rightsample,
+ sizeof(*leftsample),
+ BUFFSIZE,
+ channel[i]);
+ if (k[i] == -1)
+ fatalerror("Error reading file '%s': %s\n", filename[i],strerror(errno));
+ if (k[i] > maxk)
+ maxk = k[i];
+ }
+ if (maxk == 0)
+ myexit (0);
+
+ /*-------------------------------------------------*
+ * First the left channel as far as it goes ... *
+ *-------------------------------------------------*/
+ for (i = 0; i < k[0]; i++)
+ stereosample[2 * i] = leftsample[i];
+ /*-------------------------------------------------*
+ * ... and fill up till the end of this buffer. *
+ *-------------------------------------------------*/
+ for (; i < maxk; i++)
+ stereosample[2 * i] = 0;
+
+ /*-------------------------------------------------*
+ * Next the right channel as far as it goes ... *
+ *-------------------------------------------------*/
+ for (i = 0; i < k[1]; i++)
+ stereosample[2 * i + 1] = rightsample[i];
+ /*-------------------------------------------------*
+ * ... and fill up till the end of this buffer. *
+ *-------------------------------------------------*/
+ for (; i < maxk; i++)
+ stereosample[2 * i + 1] = 0;
+
+ if (!fwrite(stereosample, sizeof(*leftsample), 2 * maxk, out)) {
+ fatalerror("Error writing to file '%s': %s\n",
+ outfilename, strerror(errno));
+ }
+ }
+ /* That was an endless loop. This point is never reached. */
+}
diff --git a/utils/streamplayer.c b/utils/streamplayer.c
new file mode 100644
index 000000000..ebb12e54b
--- /dev/null
+++ b/utils/streamplayer.c
@@ -0,0 +1,124 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \author Russell Bryant <russell@digium.com>
+ *
+ * \brief A utility for reading from a raw TCP stream
+ *
+ * This application is intended for use when a raw TCP stream is desired to be
+ * used as a music on hold source for Asterisk. Some devices are capable of
+ * taking some kind of audio input and provide it as a raw TCP stream over the
+ * network, which is what inspired someone to fund this to be written.
+ * However, it would certainly be possible to write your own server application
+ * to provide music over a TCP stream from a centralized location.
+ *
+ * This application is quite simple. It just reads the data from the TCP
+ * stream and dumps it straight to stdout. Due to the way Asterisk handles
+ * music on hold sources, this application checks to make sure writing
+ * to stdout will not be a blocking operation before doing so. If so, the data
+ * is just thrown away. This ensures that the stream will continue to be
+ * serviced, even if Asterisk is not currently using the source.
+ *
+ * \todo Update this application to be able to connect to a stream via HTTP,
+ * since that is the #1 most requested feature, and it would be quite useful.
+ * A lot of people think that is what this is for and email me when it does
+ * not work. :)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__) || defined(__CYGWIN__)
+#include <netinet/in.h>
+#endif
+#include <sys/time.h>
+
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sin;
+ struct hostent *hp;
+ int s;
+ int res;
+ char buf[2048];
+ fd_set wfds;
+ struct timeval tv;
+
+ if (argc != 3) {
+ fprintf(stderr, "streamplayer -- A utility for reading from a raw TCP stream.\n");
+ fprintf(stderr, "Written for use with Asterisk (http://www.asterisk.org)\n");
+ fprintf(stderr, "Copyright (C) 2005 -- Russell Bryant -- Digium, Inc.\n\n");
+ fprintf(stderr, "Usage: ./streamplayer <ip> <port>\n");
+ exit(1);
+ }
+
+ hp = gethostbyname(argv[1]);
+ if (!hp) {
+ fprintf(stderr, "Unable to lookup IP for host '%s'\n", argv[1]);
+ exit(1);
+ }
+
+ memset(&sin, 0, sizeof(sin));
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(atoi(argv[2]));
+ memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (s < 0) {
+ fprintf(stderr, "Unable to allocate socket!\n");
+ exit(1);
+ }
+
+ res = connect(s, (struct sockaddr *)&sin, sizeof(sin));
+
+ if (res) {
+ fprintf(stderr, "Unable to connect to host!\n");
+ close(s);
+ exit(1);
+ }
+
+ while (1) {
+ res = read(s, buf, sizeof(buf));
+
+ if (res < 1)
+ break;
+
+ memset(&tv, 0, sizeof(tv));
+ FD_ZERO(&wfds);
+ FD_SET(1, &wfds);
+
+ select(2, NULL, &wfds, NULL, &tv);
+
+ if (FD_ISSET(1, &wfds)) {
+ if (write(1, buf, res) < 1) {
+ break;
+ }
+ }
+ }
+
+ close(s);
+ exit(res);
+}