Index: channel.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channel.c,v
retrieving revision 1.153
diff -u -r1.153 channel.c
--- channel.c	23 Dec 2004 15:11:46 -0000	1.153
+++ channel.c	24 Dec 2004 01:09:36 -0000
@@ -613,6 +613,10 @@
 		chan->monitor->stop( chan, 0 );
 	}
 
+	/* If there is native format music-on-hold state, free it */
+	if(chan->music_state)
+		ast_moh_cleanup(chan);
+
 	/* Free translatosr */
 	if (chan->pvt->readtrans)
 		ast_translator_free_path(chan->pvt->readtrans);
@@ -2960,22 +2964,26 @@
 	return group;
 }
 
-
 static int (*ast_moh_start_ptr)(struct ast_channel *, char *) = NULL;
 static void (*ast_moh_stop_ptr)(struct ast_channel *) = NULL;
+static void (*ast_moh_cleanup_ptr)(struct ast_channel *) = NULL;
 
 
 void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, char *),
-								void (*stop_ptr)(struct ast_channel *)) 
+								 void (*stop_ptr)(struct ast_channel *),
+								 void (*cleanup_ptr)(struct ast_channel *)
+								 ) 
 {
 	ast_moh_start_ptr = start_ptr;
 	ast_moh_stop_ptr = stop_ptr;
+	ast_moh_cleanup_ptr = cleanup_ptr;
 }
 
 void ast_uninstall_music_functions(void) 
 {
 	ast_moh_start_ptr = NULL;
 	ast_moh_stop_ptr = NULL;
+	ast_moh_cleanup_ptr = NULL;
 }
 
 /*! Turn on/off music on hold on a given channel */
@@ -2996,3 +3004,10 @@
 	if(ast_moh_stop_ptr)
 		ast_moh_stop_ptr(chan);
 }
+
+void ast_moh_cleanup(struct ast_channel *chan) 
+{
+	if(ast_moh_cleanup_ptr)
+        ast_moh_cleanup_ptr(chan);
+}
+
Index: file.c
===================================================================
RCS file: /usr/cvsroot/asterisk/file.c,v
retrieving revision 1.53
diff -u -r1.53 file.c
--- file.c	14 Nov 2004 22:38:34 -0000	1.53
+++ file.c	24 Dec 2004 01:09:36 -0000
@@ -431,9 +431,13 @@
 		res = ret ? ret : -1;
 	return res;
 }
-
 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
 {
+	return ast_openstream_full(chan, filename, preflang, 0);
+}
+
+struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
+{
 	/* This is a fairly complex routine.  Essentially we should do 
 	   the following:
 	   
@@ -452,10 +456,13 @@
 	char filename3[256]="";
 	char *endpart;
 	int res;
-	ast_stopstream(chan);
-	/* do this first, otherwise we detect the wrong writeformat */
-	if (chan->generator)
-		ast_deactivate_generator(chan);
+
+	if (asis) {
+		/* do this first, otherwise we detect the wrong writeformat */
+		ast_stopstream(chan);
+		if (chan->generator)
+			ast_deactivate_generator(chan);
+	}
 	if (preflang && !ast_strlen_zero(preflang)) {
 		strncpy(filename3, filename, sizeof(filename3) - 1);
 		endpart = strrchr(filename3, '/');
Index: include/asterisk/channel.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/channel.h,v
retrieving revision 1.64
diff -u -r1.64 channel.h
--- include/asterisk/channel.h	16 Dec 2004 03:15:20 -0000	1.64
+++ include/asterisk/channel.h	24 Dec 2004 01:09:36 -0000
@@ -88,7 +88,8 @@
 
 	/*! Default music class */
 	char musicclass[MAX_LANGUAGE];
-
+	/*! Music State*/
+	void *music_state;
 	/*! Current generator data if there is any */
 	void *generatordata;
 	/*! Current active data generator */
@@ -230,6 +231,7 @@
 #define AST_FLAG_BLOCKING	(1 << 3)	/* if we are blocking */
 #define AST_FLAG_ZOMBIE		(1 << 4)	/* if we are a zombie */
 #define AST_FLAG_EXCEPTION	(1 << 5)	/* if there is a pending exception */
+#define AST_FLAG_MOH        (1 << 6)    /* listening to moh */
 
 struct ast_bridge_config {
 	int play_to_caller;
Index: include/asterisk/musiconhold.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/musiconhold.h,v
retrieving revision 1.3
diff -u -r1.3 musiconhold.h
--- include/asterisk/musiconhold.h	9 Dec 2004 19:55:01 -0000	1.3
+++ include/asterisk/musiconhold.h	24 Dec 2004 01:09:36 -0000
@@ -25,8 +25,11 @@
 extern void ast_moh_stop(struct ast_channel *chan);
 
 extern void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, char *),
-								 void (*stop_ptr)(struct ast_channel *));
+										void (*stop_ptr)(struct ast_channel *),
+										void (*cleanup_ptr)(struct ast_channel *));
+	
 extern void ast_uninstall_music_functions(void);
+void ast_moh_cleanup(struct ast_channel *chan);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
Index: res/res_musiconhold.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_musiconhold.c,v
retrieving revision 1.41
diff -u -r1.41 res_musiconhold.c
--- res/res_musiconhold.c	9 Dec 2004 19:55:01 -0000	1.41
+++ res/res_musiconhold.c	24 Dec 2004 01:09:36 -0000
@@ -16,6 +16,7 @@
 #include <asterisk/logger.h>
 #include <asterisk/channel.h>
 #include <asterisk/pbx.h>
+#include <../astconf.h>
 #include <asterisk/options.h>
 #include <asterisk/module.h>
 #include <asterisk/translate.h>
@@ -25,6 +26,7 @@
 #include <asterisk/config.h>
 #include <asterisk/utils.h>
 #include <stdlib.h>
+#include <asterisk/cli.h>
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
@@ -45,10 +47,13 @@
 #endif
 #include <unistd.h>
 #include <sys/ioctl.h>
+#define MAX_MOHFILES 512
+#define MAX_MOHFILE_LEN 128
 
 static char *app0 = "MusicOnHold";
 static char *app1 = "WaitMusicOnHold";
 static char *app2 = "SetMusicOnHold";
+static int die_with_dignity = 0;
 
 static char *synopsis0 = "Play Music On Hold indefinitely";
 static char *synopsis1 = "Wait, playing Music On Hold";
@@ -73,15 +78,28 @@
 
 static int respawn_time = 20;
 
+struct moh_files_state {
+	struct mohclass *class;
+	struct ast_filestream *stream;
+	int origwfmt;
+	int samples;
+	int sample_queue;
+	unsigned char pos;
+	unsigned char save_pos;
+};
+
 struct mohclass {
 	char class[80];
 	char dir[256];
 	char miscargs[256];
+	char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
+	int total_files;
 	int destroyme;
 	int pid;		/* PID of mpg123 */
 	int quiet;
 	int single;
 	int custom;
+	int randomize;
 	time_t start;
 	pthread_t thread;
 	struct mohdata *members;
@@ -101,17 +119,154 @@
 
 static struct mohclass *mohclasses;
 
-
 AST_MUTEX_DEFINE_STATIC(moh_lock);
 
 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
 #define MPG_123 "/usr/bin/mpg123"
 #define MAX_MP3S 256
 
+static void moh_files_release(struct ast_channel *chan, void *data)
+{
+	struct moh_files_state *state = chan->music_state;
+
+	if (chan && state) {
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
+
+		if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
+			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
+		}
+		state->save_pos = state->pos + 1;
+	}
+}
+
+
+static int ast_moh_files_next(struct ast_channel *chan) {
+	struct moh_files_state *state = chan->music_state;
+
+	if(state->save_pos) {
+		state->pos = state->save_pos - 1;
+		state->save_pos = 0;
+	} else {
+		state->samples = 0;
+		if (chan->stream) {
+			ast_closestream(chan->stream);
+			chan->stream = NULL;
+			state->pos++;
+		}
+
+		if (state->class->randomize) {
+			srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files);
+			state->pos = rand();
+		}
+	}
+
+	state->pos = state->pos % state->class->total_files;
+	
+	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+		ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
+		return -1;
+	}
+	if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
+		ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
+		state->pos++;
+		return -1;
+	}
+
+	if (option_verbose > 2)
+		ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
+
+
+	if (state->samples)
+		ast_seekstream(chan->stream, state->samples, SEEK_SET);
+
+	return state->pos;
+}
+
+
+static struct ast_frame *moh_files_readframe(struct ast_channel *chan) {
+	struct ast_frame *f = NULL;
+	
+	if (!chan->stream || !(f = ast_readframe(chan->stream))) {
+		if (ast_moh_files_next(chan) > -1)
+			f = ast_readframe(chan->stream);
+	}
+
+	return f;
+}
+
+static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
+{
+	struct moh_files_state *state = chan->music_state;
+	struct ast_frame *f = NULL;
+	int res = 0;
+	state->sample_queue += samples;
+
+	while(state->sample_queue > 0) {
+		if ((f = moh_files_readframe(chan))) {
+			state->samples += f->samples;
+			res = ast_write(chan, f);
+			ast_frfree(f);
+			if(res < 0) {
+				ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
+				return -1;
+			}
+			state->sample_queue -= f->samples;
+		} else
+			return -1;	
+	}
+	return res;
+}
+
+
+static void *moh_files_alloc(struct ast_channel *chan, void *params)
+{
+	struct moh_files_state *state;
+	struct mohclass *class = params;
+	int allocated = 0;
+
+	if ((!chan->music_state) && ((state = malloc(sizeof(struct moh_files_state))))) {
+		chan->music_state = state;
+		allocated = 1;
+	} else 
+		state = chan->music_state;
+
+
+	if(state) {
+		if (allocated || state->class != class) {
+			/* initialize */
+			memset(state, 0, sizeof(struct moh_files_state));
+			state->class = class;
+		}
+
+		state->origwfmt = chan->writeformat;
+
+		if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+			ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
+			free(chan->music_state);
+			chan->music_state = NULL;
+		} else {
+			if (option_verbose > 2)
+				ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
+		}
+
+
+	}
+	
+	return chan->music_state;
+}
+
+static struct ast_generator moh_file_stream = 
+{
+	alloc: moh_files_alloc,
+	release: moh_files_release,
+	generate: moh_files_generator,
+};
+
 static int spawn_mp3(struct mohclass *class)
 {
 	int fds[2];
-	int files;
+	int files=0;
 	char fns[MAX_MP3S][80];
 	char *argv[MAX_MP3S + 50];
 	char xargs[256];
@@ -119,11 +274,13 @@
 	int argc = 0;
 	DIR *dir;
 	struct dirent *de;
+
+	
 	dir = opendir(class->dir);
 	if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
 		ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
 		return -1;
- 	}
+	}
 
 	if (!class->custom) {
 		argv[argc++] = "mpg123";
@@ -137,14 +294,14 @@
 			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;
@@ -156,7 +313,7 @@
 				argptr++;
 			}
 		}
-	} else {
+	} else  {
 		/* Format arguments for argv vector */
 		strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
 		argptr = xargs;
@@ -171,16 +328,17 @@
 	}
 
 	files = 0;
-	if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://"))
-	{
+	if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
 		strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
 		argv[argc++] = fns[files];
 		files++;
-	}
-	else
-	{
+	} else {
 		while((de = readdir(dir)) && (files < MAX_MP3S)) {
-			if ((strlen(de->d_name) > 3) && !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3")) {
+			if ((strlen(de->d_name) > 3) && 
+				((class->custom && 
+				  (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
+				   !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln")))
+				 || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
 				strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
 				argv[argc++] = fns[files];
 				files++;
@@ -189,6 +347,7 @@
 	}
 	argv[argc] = NULL;
 	closedir(dir);
+	
 	if (pipe(fds)) {	
 		ast_log(LOG_WARNING, "Pipe failed\n");
 		return -1;
@@ -229,18 +388,19 @@
 				close(x);
 			}
 		}
-		/* Child */
-		chdir(class->dir);
-		if(class->custom) {
+        /* Child */
+
+        if(class->custom) {
+			chdir(class->dir);
 			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);
-		}
+        } 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);
@@ -456,8 +616,7 @@
 {
 	struct mohdata *res;
 	struct mohclass *class;
-	ast_mutex_lock(&moh_lock);
-	class = get_mohbyname(params);
+	class = params;
 	if (class)
 		res = mohalloc(class);
 	else {
@@ -465,7 +624,6 @@
 			ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
 		res = NULL;
 	}
-	ast_mutex_unlock(&moh_lock);
 	if (res) {
 		res->origwfmt = chan->writeformat;
 		if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
@@ -473,10 +631,6 @@
 			moh_release(NULL, res);
 			res = NULL;
 		}
-#if 0
-		/* Allow writes to interrupt */
-		chan->writeinterrupt = 1;
-#endif		
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
 	}
@@ -489,7 +643,8 @@
 	struct mohdata *moh = data;
 	short buf[1280 + AST_FRIENDLY_OFFSET / 2];
 	int res;
-
+	if(!moh->parent->pid)
+		return - 1;
 	len = samples * 2;
 	if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
 		ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), (int)len, chan->name);
@@ -525,6 +680,58 @@
 	generate: moh_generate,
 };
 
+static int moh_scan_files(struct mohclass *class) {
+
+	DIR *files_DIR;
+	struct dirent *files_dirent;
+	char path[512];
+	char filepath[MAX_MOHFILE_LEN];
+	char *scan;
+	struct stat statbuf;
+	int dirnamelen;
+	int i;
+	
+	files_DIR = opendir(class->dir);
+	if (!files_DIR) {
+		ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
+		return -1;
+	}
+
+	class->total_files = 0;
+	dirnamelen = strlen(class->dir) + 2;
+	getcwd(path, 512);
+	chdir(class->dir);
+	memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
+
+	while ((files_dirent = readdir(files_DIR))) {
+		if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
+			continue;
+
+		snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
+
+		if (stat(filepath, &statbuf))
+			continue;
+
+		if (!S_ISREG(statbuf.st_mode))
+			continue;
+
+		if ((scan = strrchr(filepath, '.')))
+			*scan = '\0';
+
+		/* if the file is present in multiple formats, ensure we only put it into the list once */
+		for (i = 0; i < class->total_files; i++)
+			if (!strcmp(filepath, class->filearray[i]))
+				break;
+
+		if (i == class->total_files)
+			strcpy(class->filearray[class->total_files++], filepath);
+	}
+
+	closedir(files_DIR);
+	chdir(path);
+	return class->total_files;
+}
+
 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
 {
 	struct mohclass *moh;
@@ -545,16 +752,30 @@
 	time(&moh->start);
 	moh->start -= respawn_time;
 	strncpy(moh->class, classname, sizeof(moh->class) - 1);
-	if (miscargs)
+	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") || !strcasecmp(mode, "custom")) {
+		if (strchr(miscargs,'r'))
+			moh->randomize=1;
+	}
+	if (!strcasecmp(mode, "files")) {
+		if (param)
+			strncpy(moh->dir, param, sizeof(moh->dir) - 1);
+		if (!moh_scan_files(moh)) {
+			free(moh);
+			return -1;
+		}
+	} else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
+
+		if (param)
+			strncpy(moh->dir, param, sizeof(moh->dir) - 1);
+
 		if (!strcasecmp(mode, "custom"))
 			moh->custom = 1;
-		if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
+		else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
 			moh->single = 1;
-		if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
+		else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
 			moh->quiet = 1;
-		strncpy(moh->dir, param, sizeof(moh->dir) - 1);
+		
 		moh->srcfd = -1;
 #ifdef ZAPATA_MOH
 		/* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
@@ -588,28 +809,66 @@
 	return 0;
 }
 
+static void local_ast_moh_cleanup(struct ast_channel *chan)
+{
+	if(chan->music_state) {
+		free(chan->music_state);
+		chan->music_state = NULL;
+	}
+}
+
 static int local_ast_moh_start(struct ast_channel *chan, char *class)
 {
+	struct mohclass *mohclass;
+
 	if (!class || ast_strlen_zero(class))
 		class = chan->musicclass;
 	if (!class || ast_strlen_zero(class))
 		class = "default";
-	return ast_activate_generator(chan, &mohgen, class);
+	ast_mutex_lock(&moh_lock);
+	mohclass = get_mohbyname(class);
+	ast_mutex_unlock(&moh_lock);
+
+	if (!mohclass) {
+		ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
+		return -1;
+	}
+
+	ast_set_flag(chan, AST_FLAG_MOH);
+	if (mohclass->total_files) {
+		return ast_activate_generator(chan, &moh_file_stream, mohclass);
+	} else
+		return ast_activate_generator(chan, &mohgen, mohclass);
 }
 
 static void local_ast_moh_stop(struct ast_channel *chan)
 {
+	ast_clear_flag(chan, AST_FLAG_MOH);
 	ast_deactivate_generator(chan);
+
+	if(chan->music_state) {
+		if(chan->stream) {
+			ast_closestream(chan->stream);
+			chan->stream = NULL;
+		}
+	}
 }
 
-static void load_moh_classes(void)
+static int load_moh_classes(void)
 {
 	struct ast_config *cfg;
 	struct ast_variable *var;
 	char *data;
 	char *args;
+	int x = 0;
 	cfg = ast_load("musiconhold.conf");
 	if (cfg) {
+		var = ast_variable_browse(cfg, "general");
+		while(var) {
+			if(!strcmp(var->name,"die_with_dignity"))
+				die_with_dignity = ast_true(var->value);
+			var = var->next;
+		}
 		var = ast_variable_browse(cfg, "classes");
 		while(var) {
 			data = strchr(var->value, ':');
@@ -621,53 +880,131 @@
 					*args = '\0';
 					args++;
 				}
-				moh_register(var->name, var->value, data,args);
+				if(!(get_mohbyname(var->name))) {
+					moh_register(var->name, var->value, data, args);
+					x++;
+				}
+			}
+			var = var->next;
+		}
+		var = ast_variable_browse(cfg, "moh_files");
+		while(var) {
+			if(!(get_mohbyname(var->name))) {
+				args = strchr(var->value, ',');
+				if (args) {
+					*args = '\0';
+					args++;
+				}
+				moh_register(var->name, "files", var->value, args);
+				x++;
 			}
 			var = var->next;
 		}
+
 		ast_destroy(cfg);
 	}
+	return x;
 }
 
 static void ast_moh_destroy(void)
 {
-	struct mohclass *moh;
+	struct mohclass *moh,*tmp;
 	char buff[8192];
-	int bytes, tbytes=0, stime = 0;
+	int bytes, tbytes=0, stime = 0, pid = 0;
 	if (option_verbose > 1)
-		ast_verbose(VERBOSE_PREFIX_2 "Destroying any remaining musiconhold processes\n");
+		ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
 	ast_mutex_lock(&moh_lock);
 	moh = mohclasses;
+
 	while(moh) {
 		if (moh->pid) {
 			ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
 			stime = time(NULL);
-			kill(moh->pid, SIGKILL);
+			pid = moh->pid;
+			moh->pid = 0;
+			kill(pid, SIGKILL);
 			while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
 				tbytes = tbytes + bytes;
 			}
-			ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", moh->pid, tbytes);
+			ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
 			close(moh->srcfd);
-			moh->pid = 0;
 		}
+		tmp = moh;
 		moh = moh->next;
+		free(tmp);
 	}
+	mohclasses = NULL;
 	ast_mutex_unlock(&moh_lock);
 }
 
+
+static void moh_on_off(int on) {
+	struct ast_channel *chan = ast_channel_walk_locked(NULL);
+	while(chan) {
+		if(ast_test_flag(chan, AST_FLAG_MOH)) {
+			if(on)
+				local_ast_moh_start(chan,NULL);
+			else
+				ast_deactivate_generator(chan);
+		}
+		ast_mutex_unlock(&chan->lock);
+		chan = ast_channel_walk_locked(chan);
+	}
+}
+
+static int moh_cli(int fd, int argc, char *argv[]) 
+{
+	int x = 0;
+	moh_on_off(0);
+	ast_moh_destroy();
+	x = load_moh_classes();
+	moh_on_off(1);
+	ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
+	return 0;
+}
+
+static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
+
+
+static int handle_SIGSEGV(int sig)
+{
+    /* Indicate need to reload */
+	ast_moh_destroy();
+	exit(0);
+}
+
+
+
 int load_module(void)
 {
 	int res;
+	if(die_with_dignity)
+		(void) signal(SIGSEGV,(void *) handle_SIGSEGV);
 	load_moh_classes();
-	ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop);
+	ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
 	res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
 	ast_register_atexit(ast_moh_destroy);
+	ast_cli_register(&cli_moh);
 	if (!res)
 		res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
 	if (!res)
 		res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
+
 	return res;
 }
+
+int reload(void)
+{
+    struct mohclass *moh = mohclasses;
+    load_moh_classes();
+    while(moh) {
+        if (moh->total_files)
+            moh_scan_files(moh);
+        moh = moh->next;
+    }
+    return 0;
+}
+
 
 int unload_module(void)
 {
