From de4188df06a58b20da7da1da0843080548a801c5 Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sat, 17 Jul 2004 20:12:28 +0000
Subject: [PATCH] Merge musiconhold stuff (bug #2027), restructure AGI to
 eventually support registration

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3460 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/Makefile                   |  2 +-
 configs/musiconhold.conf.sample |  2 +
 include/asterisk/agi.h          | 48 ++++++++++++++++++
 res/Makefile                    |  4 +-
 apps/app_agi.c => res/res_agi.c | 27 +++-------
 res/res_musiconhold.c           | 90 ++++++++++++++++++++-------------
 6 files changed, 117 insertions(+), 56 deletions(-)
 create mode 100755 include/asterisk/agi.h
 rename apps/app_agi.c => res/res_agi.c (98%)

diff --git a/apps/Makefile b/apps/Makefile
index bdf491e35d..9ac9736767 100755
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -17,7 +17,7 @@ USE_POSTGRES_VM_INTERFACE=0
 #APPS=app_dial.so app_playback.so app_directory.so app_intercom.so app_mp3.so 
 APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
      app_system.so app_echo.so app_record.so app_image.so app_url.so app_disa.so \
-     app_agi.so app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
+     app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
      app_zapateller.so app_setcallerid.so app_festival.so \
      app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
      app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
diff --git a/configs/musiconhold.conf.sample b/configs/musiconhold.conf.sample
index 4cb296d9c6..991ccae9ec 100755
--- a/configs/musiconhold.conf.sample
+++ b/configs/musiconhold.conf.sample
@@ -7,3 +7,5 @@
 ;random => quietmp3:/var/lib/asterisk/mohmp3,-z
 ;unbuffered => mp3nb:/var/lib/asterisk/mohmp3
 ;quietunbuf => quietmp3nb:/var/lib/asterisk/mohmp3
+; Note that the custom mode cannot handle escaped parameters (specifically embedded spaces)
+;manual => custom:/var/lib/asterisk/mohmp3,/usr/bin/mpg123 -q -r 8000 -f 8192 -b 2048 --mono -s
diff --git a/include/asterisk/agi.h b/include/asterisk/agi.h
new file mode 100755
index 0000000000..25899d58cb
--- /dev/null
+++ b/include/asterisk/agi.h
@@ -0,0 +1,48 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * AGI Extension interfaces
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#ifndef _ASTERISK_AGI_H
+#define _ASTERISK_AGI_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct agi_state {
+	int fd;		/* FD for general output */
+	int audio;	/* FD for audio output */
+	int ctrl;	/* FD for input control */
+} AGI;
+
+typedef struct agi_command {
+	/* Null terminated list of the words of the command */
+	char *cmda[AST_MAX_CMD_LEN];
+	/* Handler for the command (channel, AGI state, # of arguments, argument list). 
+	    Returns RESULT_SHOWUSAGE for improper arguments */
+	int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
+	/* Summary of the command (< 60 characters) */
+	char *summary;
+	/* Detailed usage information */
+	char *usage;
+	struct agi_command *next;
+} agi_command;
+
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+
+
+#endif
diff --git a/res/Makefile b/res/Makefile
index 302c3499f6..afd3af9371 100755
--- a/res/Makefile
+++ b/res/Makefile
@@ -11,7 +11,8 @@
 # the GNU General Public License
 #
 
-MODS=res_adsi.so res_parking.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so
+MODS=res_adsi.so res_parking.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so \
+     res_agi.so
 MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
 MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
 MODS+=$(shell if [ -f "/usr/include/osp/osp.h" ]; then echo "res_osp.so"; fi)
@@ -30,6 +31,7 @@ OSPLIB=/usr/lib/libosp.a
 all: depend $(MODS)
 
 install: all
+	rm -f $(DESTDIR)$(MODULES_DIR)/app_agi.so 
 	for x in $(MODS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
 
 res_crypto.so: res_crypto.o
diff --git a/apps/app_agi.c b/res/res_agi.c
similarity index 98%
rename from apps/app_agi.c
rename to res/res_agi.c
index 64790237c0..ba4ab0ec29 100755
--- a/apps/app_agi.c
+++ b/res/res_agi.c
@@ -38,32 +38,16 @@
 #include <asterisk/musiconhold.h>
 #include <asterisk/utils.h>
 #include <asterisk/lock.h>
+#include <asterisk/agi.h>
 #include "../asterisk.h"
 #include "../astconf.h"
 
 #define MAX_ARGS 128
+#define MAX_COMMANDS 128
 
 /* Recycle some stuff from the CLI interface */
 #define fdprintf ast_cli
 
-typedef struct agi_state {
-	int fd;		/* FD for general output */
-	int audio;	/* FD for audio output */
-	int ctrl;	/* FD for input control */
-} AGI;
-
-typedef struct agi_command {
-	/* Null terminated list of the words of the command */
-	char *cmda[AST_MAX_CMD_LEN];
-	/* Handler for the command (channel, AGI state, # of arguments, argument list). 
-	    Returns RESULT_SHOWUSAGE for improper arguments */
-	int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
-	/* Summary of the command (< 60 characters) */
-	char *summary;
-	/* Detailed usage information */
-	char *usage;
-} agi_command;
-
 static char *tdesc = "Asterisk Gateway Interface (AGI)";
 
 static char *app = "AGI";
@@ -1102,7 +1086,7 @@ static char usage_noop[] =
 " Usage: NOOP\n"
 "    Does nothing.\n";
 
-static agi_command commands[] = {
+static agi_command commands[MAX_COMMANDS] = {
 	{ { "answer", NULL }, handle_answer, "Asserts answer", usage_answer },
 	{ { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
 	{ { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
@@ -1112,7 +1096,7 @@ static agi_command commands[] = {
 	{ { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
 	{ { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
 	{ { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
-        { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
+	{ { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
 	{ { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
 	{ { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
 	{ { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
@@ -1159,6 +1143,7 @@ static int help_workhorse(int fd, char *match[])
 	if (match)
 		join(matchstr, sizeof(matchstr), match);
 	for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
+		if (!commands[x].cmda[0]) break;
 		e = &commands[x]; 
 		if (e)
 			join(fullcmd, sizeof(fullcmd), e->cmda);
@@ -1181,6 +1166,7 @@ static agi_command *find_command(char *cmds[], int exact)
 	int y;
 	int match;
 	for (x=0;x < sizeof(commands) / sizeof(commands[0]);x++) {
+		if (!commands[x].cmda[0]) break;
 		/* start optimistic */
 		match = 1;
 		for (y=0;match && cmds[y]; y++) {
@@ -1430,6 +1416,7 @@ static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
 
 	for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
 		char *stringp=NULL;
+		if (!commands[x].cmda[0]) break;
 		e = &commands[x]; 
 		if (e)
 			join(fullcmd, sizeof(fullcmd), e->cmda);
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index b446551c1d..647956532a 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -79,6 +79,7 @@ struct mohclass {
 	int pid;		/* PID of mpg123 */
 	int quiet;
 	int single;
+	int custom;
 	pthread_t thread;
 	struct mohdata *members;
 	/* Source of audio */
@@ -119,34 +120,49 @@ static int spawn_mp3(struct mohclass *class)
 		ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
 		return -1;
  	}
-	argv[argc++] = "mpg123";
-	argv[argc++] = "-q";
-	argv[argc++] = "-s";
-	argv[argc++] = "--mono";
-	argv[argc++] = "-r";
-	argv[argc++] = "8000";
-
-	if (!class->single) {
-		argv[argc++] = "-b";
-		argv[argc++] = "2048";
-	}
 
-	argv[argc++] = "-f";
-	
-	if (class->quiet) {
-		argv[argc++] = "4096";
-	} else
-		argv[argc++] = "8192";
-
-	/* Look for extra arguments and add them to the list */
-	strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
-	argptr = xargs;
-	while(argptr && !ast_strlen_zero(argptr)) {
-		argv[argc++] = argptr;
-		argptr = strchr(argptr, ',');
-		if (argptr) {
-			*argptr = '\0';
-			argptr++;
+	if (!class->custom) {
+		argv[argc++] = "mpg123";
+		argv[argc++] = "-q";
+		argv[argc++] = "-s";
+		argv[argc++] = "--mono";
+		argv[argc++] = "-r";
+		argv[argc++] = "8000";
+		
+		if (!class->single) {
+			argv[argc++] = "-b";
+			argv[argc++] = "2048";
+		}
+
+		argv[argc++] = "-f";
+
+		if (class->quiet)
+			argv[argc++] = "4096";
+		else
+			argv[argc++] = "8192";
+
+		/* Look for extra arguments and add them to the list */
+		strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
+		argptr = xargs;
+		while(argptr && !ast_strlen_zero(argptr)) {
+			argv[argc++] = argptr;
+			argptr = strchr(argptr, ',');
+			if (argptr) {
+				*argptr = '\0';
+				argptr++;
+			}
+		}
+	} else {
+		/* Format arguments for argv vector */
+		strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
+		argptr = xargs;
+		while(argptr && !ast_strlen_zero(argptr)) {
+			argv[argc++] = argptr;
+			argptr = strchr(argptr, ' ');
+			if (argptr) {
+				*argptr = '\0';
+				argptr++;
+			}
 		}
 	}
 
@@ -195,12 +211,16 @@ static int spawn_mp3(struct mohclass *class)
 			close(x);
 		/* Child */
 		chdir(class->dir);
-		/* Default install is /usr/local/bin */
-		execv(LOCAL_MPG_123, argv);
-		/* Many places have it in /usr/bin */
-		execv(MPG_123, argv);
-		/* Check PATH as a last-ditch effort */
-		execvp("mpg123", argv);
+		if(class->custom) {
+			execv(argv[0], argv);
+		} else {
+			/* Default install is /usr/local/bin */
+			execv(LOCAL_MPG_123, argv);
+			/* Many places have it in /usr/bin */
+			execv(MPG_123, argv);
+			/* Check PATH as a last-ditch effort */
+			execvp("mpg123", argv);
+		}
 		ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
 		close(fds[1]);
 		exit(1);
@@ -506,7 +526,9 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
 	strncpy(moh->class, classname, sizeof(moh->class) - 1);
 	if (miscargs)
 		strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
-	if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3")) {
+	if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
+		if (!strcasecmp(mode, "custom"))
+			moh->custom = 1;
 		if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
 			moh->single = 1;
 		if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
-- 
GitLab