Index: channels/chan_oss.c
===================================================================
--- channels/chan_oss.c	(revision 9031)
+++ channels/chan_oss.c	(working copy)
@@ -34,6 +34,7 @@
 
 #include <stdio.h>
 #include <ctype.h>	/* for isalnum */
+#include <math.h>	/* exp and log */
 #include <string.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
@@ -89,6 +90,7 @@
  * where 'foo' is the name of the card you want.
  *
  * oss.conf parameters are
+START_CONFIG
 
 [general]
 ; general config options, default values are shown
@@ -108,7 +110,10 @@
 ; mixer="-f /dev/mixer0 pcm 80 ; mixer command to run on start
 ; queuesize=10		; frames in device driver
 ; frags=8		; argument to SETFRAGMENT
+; boost = n		; mic volume boost in dB
 
+END_CONFIG
+
 .. and so on for the other cards.
 
  */
@@ -280,6 +285,13 @@
 
 	int overridecontext;
 	int mute;
+
+	/* boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must
+	 * be representable in 16 bits to avoid overflows.
+	 */
+#define	BOOST_SCALE	(1<<9)
+#define	BOOST_MAX	40	/* slightly less than 7 bits */
+	int boost;	/* input boost, scaled by BOOST_SCALE */
 	char device[64];	/* device to open */
 
 	pthread_t sthread;
@@ -315,6 +327,7 @@
 	.ctx = "default",
 	.readpos = AST_FRIENDLY_OFFSET,	/* start here on reads */
 	.lastopen = { 0, 0 },
+	.boost = BOOST_SCALE,
 };
 
 static char *oss_active;	 /* the active device */
@@ -355,11 +368,13 @@
 static struct chan_oss_pvt *find_desc(char *dev)
 {
 	struct chan_oss_pvt *o;
+	if (dev == NULL)
+		ast_log(LOG_WARNING, "null dev\n");
 
-	for (o = oss_default.next; o && strcmp(o->name, dev) != 0; o = o->next)
+	for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next)
 		;
 	if (o == NULL)
-		ast_log(LOG_WARNING, "could not find <%s>\n", dev);
+		ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
 	return o;
 }
 
@@ -699,8 +718,8 @@
 	struct chan_oss_pvt *o = c->tech_pvt;
 	struct ast_frame f = { 0, };
 
-	ast_verbose(" << Call to '%s' on console from <%s><%s><%s> >>\n",
-		dest, c->cid.cid_dnid, c->cid.cid_num, c->cid.cid_name);
+	ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
+		dest, c->cid.cid_dnid, c->cid.cid_rdnis, c->cid.cid_name, c->cid.cid_num);
 	if (o->autoanswer) {
 		ast_verbose( " << Auto-answered >> \n" );
 		f.frametype = AST_FRAME_CONTROL;
@@ -804,6 +823,7 @@
 	struct chan_oss_pvt *o = c->tech_pvt;
 	struct ast_frame *f = &o->read_f;
 
+	/* XXX can be simplified returning &ast_null_frame */
 	/* prepare a NULL frame in case we don't have enough data to return */
 	bzero(f, sizeof(struct ast_frame));
 	f->frametype = AST_FRAME_NULL;
@@ -830,6 +850,19 @@
 	f->samples = FRAME_SIZE;
 	f->datalen = FRAME_SIZE * 2;
 	f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
+	if (o->boost != BOOST_SCALE) { /* scale and clip values */
+		int i, x;
+		int16_t *p = (int16_t *)f->data;
+		for (i = 0; i < f->samples; i++) {
+			x = (p[i] * o->boost) / BOOST_SCALE;
+			if (x > 32767)
+				x = 32767;
+			else if (x < -32768)
+				x = -32768;
+			p[i] = x;
+		}
+	}
+	
 	f->offset = AST_FRIENDLY_OFFSET;
 	return f;
 }
@@ -886,6 +919,8 @@
 	c->tech = &oss_tech;
 	snprintf(c->name, sizeof(c->name), "OSS/%s", o->device + 5);
 	c->type = o->type;
+	if (o->sounddev < 0)
+		setformat(o, O_RDWR);
 	c->fds[0] = o->sounddev; /* -1 if device closed, override later */
 	c->nativeformats = AST_FORMAT_SLINEAR;
 	c->readformat = AST_FORMAT_SLINEAR;
@@ -902,6 +937,8 @@
                 c->cid.cid_num = ast_strdup(o->cid_num);
         if (!ast_strlen_zero(o->cid_name))
                 c->cid.cid_name = ast_strdup(o->cid_name);
+        if (!ast_strlen_zero(ext))
+		c->cid.cid_dnid = strdup(ext);
 
 	o->owner = c;
 	ast_setstate(c, state);
@@ -1028,14 +1055,13 @@
 "       Sends a text message for display on the remote terminal.\n";
 
 /*
- * concatenate all arguments into a single string
+ * concatenate all arguments into a single string. argv is NULL-terminated
+ * so we can use it right away
  */
 static int console_sendtext(int fd, int argc, char *argv[])
 {
 	struct chan_oss_pvt *o = find_desc(oss_active);
-	int tmparg = 2;
-	char text2send[TEXT_SIZE] = "";
-	struct ast_frame f = { 0, };
+	char buf[TEXT_SIZE];
 
 	if (argc < 2)
 		return RESULT_SHOWUSAGE;
@@ -1043,18 +1069,15 @@
 		ast_cli(fd, "Not in a call\n");
 		return RESULT_FAILURE;
 	}
-	while (tmparg < argc) {
-		strncat(text2send, argv[tmparg++],
-			sizeof(text2send) - strlen(text2send) - 1);
-		strncat(text2send, " ",
-			sizeof(text2send) - strlen(text2send) - 1);
-	}
-	if (!ast_strlen_zero(text2send)) {
-		text2send[strlen(text2send) - 1] = '\n';
+	ast_join(buf, sizeof(buf) - 1, argv+2);
+	if (!ast_strlen_zero(buf)) {
+		struct ast_frame f = { 0, };
+		int i = strlen(buf);
+		buf[i] = '\n';
 		f.frametype = AST_FRAME_TEXT;
 		f.subclass = 0;
-		f.data = text2send;
-		f.datalen = strlen(text2send);
+		f.data = buf;
+		f.datalen = i + 1;
 		ast_queue_frame(o->owner, &f);
 	}
 	return RESULT_SUCCESS;
@@ -1249,6 +1285,42 @@
 	return RESULT_SUCCESS;
 }
 
+/*
+ * store the boost factor
+ */
+static void store_boost(struct chan_oss_pvt *o, char *s)
+{
+	double boost = 0;
+	if (sscanf(s, "%lf", &boost) != 1) {
+		ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
+		return;
+	}
+	if (boost < - BOOST_MAX) {
+		ast_log(LOG_WARNING, "boost %s too small, using %d\n",
+			s, -BOOST_MAX);
+		boost = -BOOST_MAX;
+	} else if (boost > BOOST_MAX) {
+		ast_log(LOG_WARNING, "boost %s too large, using %d\n",
+			s, BOOST_MAX);
+		boost = BOOST_MAX;
+	}
+	boost = exp(log(10)*boost/20) * BOOST_SCALE;
+	o->boost = boost;
+	ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
+}
+
+static int do_boost(int fd, int argc, char *argv[])
+{
+	struct chan_oss_pvt *o = find_desc(oss_active);
+
+	if (argc == 2)
+		ast_cli(fd, "boost currently %5.1f\n",
+			20 * log10(((double)o->boost/(double)BOOST_SCALE)) );
+	else if (argc == 3)
+		store_boost(o, argv[2]);
+	return RESULT_SUCCESS;
+}
+
 static struct ast_cli_entry myclis[] = {
 	{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
 	{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
@@ -1259,7 +1331,8 @@
 	{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
 	{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
 	{ { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete },
+	{ { "oss", "boost", NULL }, do_boost, "Sets/displays mic boost in dB"},
 	{ { "console", NULL }, console_active, "Sets/displays active console", console_usage },
 };
 
 /*
@@ -1333,6 +1407,7 @@
 		M_STR("extension", o->ext)
 		M_F("mixer", store_mixer(o, v->value))
 		M_F("callerid", store_callerid(o, v->value))
+		M_F("boost", store_boost(o, v->value))
 		M_END(;);
 	}
 	if (ast_strlen_zero(o->device))
