Index: apps/app_chanspy.c
===================================================================
--- apps/app_chanspy.c	(revision 7798)
+++ apps/app_chanspy.c	(working copy)
@@ -72,6 +72,9 @@
 "      'Agent/1234'.\n"
 "  Options:\n"
 "    b - Only spy on channels involved in a bridged call.\n"
+"    e - Encode the recorded session file. Ignored if option r isn't also given.\n"
+"        At this moment, only the mp3 format is supported, and it requires the\n"
+"        'lame' program to be installed.\n"
 "    g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
 "             'grp'.\n"
 "    q - Don't play a beep when beginning to spy on a channel.\n"
@@ -80,16 +83,20 @@
 "                    default is 'chanspy'.\n"
 "    v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
 "                 negative value refers to a quieter setting.\n"
+"    x - Doesn't wait for the spied channel to make a call if none is active;\n"
+"        instead, exit quietly with a return code of 0.\n"
 ;
 
 static const char *chanspy_spy_type = "ChanSpy";
 
 enum {
-	OPTION_QUIET	 = (1 << 0),	/* Quiet, no announcement */
-	OPTION_BRIDGED   = (1 << 1),	/* Only look at bridged calls */
-	OPTION_VOLUME    = (1 << 2),	/* Specify initial volume */
-	OPTION_GROUP     = (1 << 3),	/* Only look at channels in group */
-	OPTION_RECORD    = (1 << 4),	/* Record */
+	OPTION_QUIET	  = (1 << 0),	/* Quiet, no announcement */
+	OPTION_BRIDGED    = (1 << 1),	/* Only look at bridged calls */
+	OPTION_VOLUME     = (1 << 2),	/* Specify initial volume */
+	OPTION_GROUP      = (1 << 3),	/* Only look at channels in group */
+	OPTION_RECORD     = (1 << 4),	/* Record */
+	OPTION_NOCHAN_EXIT= (1 << 5),	/* Exit quietly if channel not found */
+	OPTION_ENCODE     = (1 << 6),	/* Encode afrer record (just MP3 for now) */
 } chanspy_opt_flags;
 
 enum {
@@ -102,6 +109,8 @@
 AST_APP_OPTIONS(chanspy_opts, {
 	AST_APP_OPTION('q', OPTION_QUIET),
 	AST_APP_OPTION('b', OPTION_BRIDGED),
+	AST_APP_OPTION('x', OPTION_NOCHAN_EXIT),
+	AST_APP_OPTION('e', OPTION_ENCODE),
 	AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
 	AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
 	AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
@@ -379,9 +388,12 @@
 		num = 0,
 		oldrf = 0,
 		oldwf = 0,
+		foundchan = 0,
 		fd = 0;
 	struct ast_flags flags;
 	signed char zero_volume = 0;
+	char filename[512];
+	char cmdline[2048];
 
 	if (!(args = ast_strdupa((char *)data))) {
 		ast_log(LOG_ERROR, "Out of memory!\n");
@@ -442,14 +454,33 @@
 	}
 
 	if (recbase) {
-		char filename[512];
 		snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
 		if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
+			char *name = strdup(filename);
+			char *directory = NULL;
+			char *cmd = NULL;
+			if (name) {
+				directory = strrchr(filename, '/');
+				if (directory) {
+					*directory = 0;
+					cmd = malloc(strlen(name) + 20);
+					if (cmd) {
+						sprintf(cmd, "mkdir -p \"%s\"", name);
+						ast_safe_system(cmd);
+						fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+					}
+				}
+				free(name);
+			}
+		}
+
+		if (fd <= 0)
 			ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
 			fd = 0;
 		}
 	}
 
+	foundchan = 0;
 	for(;;) {
 		if (!silent) {
 			res = ast_streamfile(chan, "beep", chan->language);
@@ -517,7 +548,9 @@
 						}
 						count++;
 						prev = peer;
+						foundchan = 1;
 						res = channel_spy(chan, peer, &volfactor, fd);
+						ast_log(LOG_DEBUG, "channel_spy() returns %d.\n", res);
 						if (res == -1) {
 							break;
 						} else if (res > 1 && spec) {
@@ -534,12 +567,40 @@
 				break;
 			}
 		}
+		if ((!foundchan) && (ast_test_flag(&flags, OPTION_NOCHAN_EXIT))) {
+			ast_log(LOG_DEBUG, "No channels found in one-off spying: hasta la vista.\n");
+			res = 0;
+			ast_clear_flag(chan, AST_FLAG_SPYING);
+			break;
+		}
+
 		waitms = count ? 100 : 5000;
 	}
 	
+	if (foundchan && (ast_test_flag(&flags, OPTION_NOCHAN_EXIT))) {
+		ast_log(LOG_DEBUG, "Found a channel in an one-off spying, setting return value to -1.\n");
+		res = -1;
+	}
 
 	if (fd > 0) {
-		close(fd);
+		if (lseek(fd, 0, SEEK_END) == 0) {
+			close(fd);
+			unlink(filename);
+			ast_log(LOG_DEBUG, "We had a zero-length spy file (%s). Discarded.\n", filename);
+		} else {
+			close(fd);
+			if (ast_test_flag(&flags, OPTION_ENCODE)) {
+				filename[strlen(filename) - 3] = 0;	/* Excise "raw" termination */
+				snprintf(cmdline, sizeof(cmdline),
+				         "lame -r -x -s 8 -m m --bitwidth 16 %sraw %smp3 >/dev/null 2>&1 "
+				             "&& rm -f %sraw",
+				         filename, filename, filename);
+				ast_log(LOG_DEBUG, "Converting spy file to MP3: [%s]\n", cmdline);
+				ast_safe_system(cmdline);
+			} else {
+				ast_log(LOG_DEBUG, "No encoding requested for spy file (%s).\n", filename);
+			}
+		}
 	}
 
 	if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
