diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c
index bc1adcc791cce7c8636ead33b2119bf36f098b8c..556bafd713a50ad76f5a40a2299e5dc4a554709e 100644
--- a/apps/app_chanisavail.c
+++ b/apps/app_chanisavail.c
@@ -160,13 +160,13 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
 				status = inuse = ast_device_state(trychan);
 			}
 			if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
-					ast_str_append(&tmp_availchan, 0, "%s%s", tmp_availchan->used ? "&" : "", tempchan->name);
+					ast_str_append(&tmp_availchan, 0, "%s%s", ast_str_strlen(tmp_availchan) ? "&" : "", tempchan->name);
 					
 					snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
-					ast_str_append(&tmp_availorig, 0, "%s%s", tmp_availorig->used ? "&" : "", tmp);
+					ast_str_append(&tmp_availorig, 0, "%s%s", ast_str_strlen(tmp_availorig) ? "&" : "", tmp);
 
 					snprintf(tmp, sizeof(tmp), "%d", status);
-					ast_str_append(&tmp_availstat, 0, "%s%s", tmp_availstat->used ? "&" : "", tmp);
+					ast_str_append(&tmp_availstat, 0, "%s%s", ast_str_strlen(tmp_availstat) ? "&" : "", tmp);
 
 					ast_hangup(tempchan);
 					tempchan = NULL;
@@ -176,16 +176,16 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
 					}
 			} else {
 				snprintf(tmp, sizeof(tmp), "%d", status);
-				ast_str_append(&tmp_availstat, 0, "%s%s", tmp_availstat->used ? "&" : "", tmp);
+				ast_str_append(&tmp_availstat, 0, "%s%s", ast_str_strlen(tmp_availstat) ? "&" : "", tmp);
 			}
 			cur = rest;
 		} while (cur);
 	}
 
-	pbx_builtin_setvar_helper(chan, "AVAILCHAN", tmp_availchan->str);
+	pbx_builtin_setvar_helper(chan, "AVAILCHAN", ast_str_buffer(tmp_availchan));
 	/* Store the originally used channel too */
-	pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp_availorig->str);
-	pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp_availstat->str);
+	pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", ast_str_buffer(tmp_availorig));
+	pbx_builtin_setvar_helper(chan, "AVAILSTATUS", ast_str_buffer(tmp_availstat));
 
 	return 0;
 }
diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c
index d3bf17f6cd35b76ce6dbed6bbdb5654248222c0a..c598bee750d3760c32d811f5c50404fa89c06213 100644
--- a/apps/app_dumpchan.c
+++ b/apps/app_dumpchan.c
@@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
+#include "asterisk/app.h"
 
 /*** DOCUMENTATION
 	<application name="DumpChan" language="en_US">
@@ -148,7 +149,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 
 static int dumpchan_exec(struct ast_channel *chan, void *data)
 {
-	struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX very large! */
+	struct ast_str *vars = ast_str_thread_get(&global_app_buf, 16);
 	char info[1024];
 	int level = 0;
 	static char *line = "================================================================================";
@@ -156,10 +157,11 @@ static int dumpchan_exec(struct ast_channel *chan, void *data)
 	if (!ast_strlen_zero(data))
 		level = atoi(data);
 
-	pbx_builtin_serialize_variables(chan, &vars);
-	serialize_showchan(chan, info, sizeof(info));
-	if (option_verbose >= level)
-		ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, vars->str, line);
+	if (option_verbose >= level) {
+		serialize_showchan(chan, info, sizeof(info));
+		pbx_builtin_serialize_variables(chan, &vars);
+		ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, ast_str_buffer(vars), line);
+	}
 
 	return 0;
 }
diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c
index 20eda9b437870ce54f90510dfe73175c8437ba10..936a111ac6befb13233bb861c294196b48bc6fe1 100644
--- a/apps/app_externalivr.c
+++ b/apps/app_externalivr.c
@@ -122,8 +122,8 @@ static void send_eivr_event(FILE *handle, const char event, const char *data,
 		ast_str_append(&tmp, 0, ",%s", data);
 	}
 
-	fprintf(handle, "%s\n", tmp->str);
-	ast_debug(1, "sent '%s'\n", tmp->str);
+	fprintf(handle, "%s\n", ast_str_buffer(tmp));
+	ast_debug(1, "sent '%s'\n", ast_str_buffer(tmp));
 }
 
 static void *gen_alloc(struct ast_channel *chan, void *params)
@@ -276,7 +276,7 @@ static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *out
 
 		ast_str_append(&newstring, 0, "%s=%s,", variable, value);
 		ast_channel_unlock(chan);
-		ast_copy_string(outbuf, newstring->str, outbuflen);
+		ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen);
 	}
 }
 
@@ -659,7 +659,8 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
  				continue;
   
 			if (input[0] == 'P') {
- 				send_eivr_event(eivr_events, 'P', args->str, chan);
+				struct ast_str *tmp = (struct ast_str *) args;
+ 				send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan);
 			} else if ( input[0] == 'T' ) {
 				ast_chan_log(LOG_WARNING, chan, "Answering channel if needed and starting generator\n");
 				if (chan->_state != AST_STATE_UP) {
diff --git a/apps/app_followme.c b/apps/app_followme.c
index bce763f29d60691014bf86e80e59e8446aaa874f..62a3cb2481685c04ee9ab1bb838498d985262ec4 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -960,9 +960,8 @@ static struct call_followme *find_realtime(const char *name)
 		}
 		/* This one has to exist; it was part of the query */
 		ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
-		ast_str_make_space(&str, strlen(numstr) + 1);
-		ast_copy_string(str->str, numstr, str->len);
-		if ((cur = create_followme_number(str->str, timeout, atoi(ordstr)))) {
+		ast_str_set(&str, 0, "%s", numstr);
+		if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
 			AST_LIST_INSERT_TAIL(&new->numbers, cur, entry);
 		}
 	}
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index d22cef3cb0ce5dcb99dce60dd2f97e4c0a4b892a..025ad3561cb23f1cf65d038a19be293a6df29519 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -1260,7 +1260,7 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 			min = ((now - cnf->start) % 3600) / 60;
 			sec = (now - cnf->start) % 60;
 			if (!concise) {
-				ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
+				ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
 			} else {
 				ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
 					cnf->confno,
@@ -1345,9 +1345,9 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		return CLI_SHOWUSAGE;
 	}
 
-	ast_debug(1, "Cmdline: %s\n", cmdline->str);
+	ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
 
-	admin_exec(NULL, cmdline->str);
+	admin_exec(NULL, ast_str_buffer(cmdline));
 	ast_free(cmdline);
 
 	return CLI_SUCCESS;
@@ -1435,9 +1435,9 @@ static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
 		return CLI_SHOWUSAGE;
 	}
 
-	ast_debug(1, "Cmdline: %s\n", cmdline->str);
+	ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
 
-	admin_exec(NULL, cmdline->str);
+	admin_exec(NULL, ast_str_buffer(cmdline));
 	ast_free(cmdline);
 
 	return CLI_SUCCESS;
@@ -4615,7 +4615,7 @@ static void *run_station(void *data)
 	ast_set_flag(&conf_flags, 
 		CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
 	answer_trunk_chan(trunk_ref->chan);
-	conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
+	conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
 	if (conf) {
 		conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
 		dispose_conf(conf);
@@ -4625,7 +4625,7 @@ static void *run_station(void *data)
 	if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
 		trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
 		ast_str_append(&conf_name, 0, ",K");
-		admin_exec(NULL, conf_name->str);
+		admin_exec(NULL, ast_str_buffer(conf_name));
 		trunk_ref->trunk->hold_stations = 0;
 		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
 	}
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 1863acdaaf87530ce762825092b1664800c57da8..70c9151605afc011fa7d715404bdf60c6d2e6955 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -2284,7 +2284,7 @@ static void do_hang(struct callattempt *o)
 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
 {
-	struct ast_str *buf = ast_str_alloca(len + 1);
+	struct ast_str *buf = ast_str_thread_get(&global_app_buf, len + 1);
 	char *tmp;
 
 	if (pbx_builtin_serialize_variables(chan, &buf)) {
@@ -2292,7 +2292,7 @@ static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
 
 		/* convert "\n" to "\nVariable: " */
 		strcpy(vars, "Variable: ");
-		tmp = buf->str;
+		tmp = ast_str_buffer(buf);
 
 		for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
 			vars[j] = tmp[i];
@@ -2601,12 +2601,12 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing)
 	if (qe->parent->randomperiodicannounce) {
 		qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
 	} else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 
-		ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
+		ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
 		qe->last_periodic_announce_sound = 0;
 	}
 	
 	/* play the announcement */
-	res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
+	res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
 
 	if ((res > 0 && !valid_exit(qe, res)) || res < 0)
 		res = 0;
@@ -5734,7 +5734,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 		ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
 			int2strat(q->strategy), q->holdtime, q->weight,
 			q->callscompleted, q->callsabandoned,sl,q->servicelevel);
-		do_print(s, fd, out->str);
+		do_print(s, fd, ast_str_buffer(out));
 		if (!ao2_container_count(q->members))
 			do_print(s, fd, "   No Members");
 		else {
@@ -5759,7 +5759,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 						mem->calls, (long) (time(NULL) - mem->lastcall));
 				else
 					ast_str_append(&out, 0, " has taken no calls yet");
-				do_print(s, fd, out->str);
+				do_print(s, fd, ast_str_buffer(out));
 				ao2_ref(mem, -1);
 			}
 		}
@@ -5774,7 +5774,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 				ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
 					pos++, qe->chan->name, (long) (now - qe->start) / 60,
 					(long) (now - qe->start) % 60, qe->prio);
-				do_print(s, fd, out->str);
+				do_print(s, fd, ast_str_buffer(out));
 			}
 		}
 		do_print(s, fd, "");	/* blank line between entries */
@@ -5795,7 +5795,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 			ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
 		else
 			ast_str_set(&out, 0, "No queues.");
-		do_print(s, fd, out->str);
+		do_print(s, fd, ast_str_buffer(out));
 	}
 	return CLI_SUCCESS;
 }
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index f23624fa25a3f19c3fb980a241e500d6f340ad0d..fc2a5244cdf3090ba4de00a6d9d59adbfb306e3f 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -10196,12 +10196,12 @@ static void free_vm_zones(void)
 	AST_LIST_UNLOCK(&zones);
 }
 
-static char *substitute_escapes(const char *value)
+static const char *substitute_escapes(const char *value)
 {
-	char *current, *result;
+	char *current;
 
 	/* Add 16 for fudge factor */
-	struct ast_str *str = ast_str_create(strlen(value) + 16);
+	struct ast_str *str = ast_str_thread_get(&global_app_buf, strlen(value) + 16);
 
 	/* Substitute strings \r, \n, and \t into the appropriate characters */
 	for (current = (char *) value; *current; current++) {
@@ -10235,10 +10235,7 @@ static char *substitute_escapes(const char *value)
 		}
 	}
 
-	result = ast_strdup(str->str);
-	ast_free(str);
-
-	return result;
+	return ast_str_buffer(str);
 }
 
 static int load_config(int reload)
@@ -10858,13 +10855,13 @@ static int load_config(int reload)
 			emailsubject = ast_strdup(val);
 		}
 		if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
-			emailbody = substitute_escapes(val);
+			emailbody = ast_strdup(substitute_escapes(val));
 		}
 		if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
 			pagersubject = ast_strdup(val);
 		}
 		if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
-			pagerbody = substitute_escapes(val);
+			pagerbody = ast_strdup(substitute_escapes(val));
 		}
 		AST_LIST_UNLOCK(&users);
 		ast_config_destroy(cfg);
diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c
index a8665add490f255f4facc6270f1765e9b9c38b41..6b9b090f3d6765ca57bc72e6003ee4fe00133b1c 100644
--- a/cdr/cdr_adaptive_odbc.c
+++ b/cdr/cdr_adaptive_odbc.c
@@ -317,8 +317,8 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
 #define LENGTHEN_BUF1(size)														\
 			do {																\
 				/* Lengthen buffer, if necessary */								\
-				if (sql->used + size + 1 > sql->len) {                          \
-					if (ast_str_make_space(&sql, ((sql->len + size + 1) / 512 + 1) * 512) != 0) { \
+				if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) {       \
+					if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 1) / 512 + 1) * 512) != 0) { \
 						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
 						ast_free(sql);											\
 						ast_free(sql2);											\
@@ -330,8 +330,8 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
 
 #define LENGTHEN_BUF2(size)														\
 			do {																\
-				if (sql2->used + size + 1 > sql2->len) {                        \
-					if (ast_str_make_space(&sql2, ((sql2->len + size + 3) / 512 + 1) * 512) != 0) { \
+				if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) {     \
+					if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
 						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
 						ast_free(sql);											\
 						ast_free(sql2);											\
@@ -368,12 +368,13 @@ static int odbc_log(struct ast_cdr *cdr)
 	}
 
 	AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
+		int first = 1;
 		ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
 		ast_str_set(&sql2, 0, " VALUES (");
 
 		/* No need to check the connection now; we'll handle any failure in prepare_and_execute */
 		if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
-			ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
+			ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
 			continue;
 		}
 
@@ -442,11 +443,11 @@ static int odbc_log(struct ast_cdr *cdr)
 						}
 					}
 
-					ast_str_append(&sql, 0, "%s,", entry->name);
+					ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 					LENGTHEN_BUF2(strlen(colptr));
 
 					/* Encode value, with escaping */
-					ast_str_append(&sql2, 0, "'");
+					ast_str_append(&sql2, 0, "%s'", first ? "" : ",");
 					for (tmp = colptr; *tmp; tmp++) {
 						if (*tmp == '\'') {
 							ast_str_append(&sql2, 0, "''");
@@ -456,7 +457,7 @@ static int odbc_log(struct ast_cdr *cdr)
 							ast_str_append(&sql2, 0, "%c", *tmp);
 						}
 					}
-					ast_str_append(&sql2, 0, "',");
+					ast_str_append(&sql2, 0, "'");
 					break;
 				case SQL_TYPE_DATE:
 					{
@@ -469,16 +470,16 @@ static int odbc_log(struct ast_cdr *cdr)
 							(month == 2 && year % 4 == 0 && day > 29) ||
 							(month == 2 && year % 4 != 0 && day > 28)) {
 							ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr);
-							break;
+							continue;
 						}
 
 						if (year > 0 && year < 100) {
 							year += 2000;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(17);
-						ast_str_append(&sql2, 0, "{ d '%04d-%02d-%02d' },", year, month, day);
+						ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day);
 					}
 					break;
 				case SQL_TYPE_TIME:
@@ -488,12 +489,12 @@ static int odbc_log(struct ast_cdr *cdr)
 
 						if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
 							ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(15);
-						ast_str_append(&sql2, 0, "{ t '%02d:%02d:%02d' },", hour, minute, second);
+						ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second);
 					}
 					break;
 				case SQL_TYPE_TIMESTAMP:
@@ -511,16 +512,16 @@ static int odbc_log(struct ast_cdr *cdr)
 							(month == 2 && year % 4 != 0 && day > 28) ||
 							hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
 							ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
-							break;
+							continue;
 						}
 
 						if (year > 0 && year < 100) {
 							year += 2000;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(26);
-						ast_str_append(&sql2, 0, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second);
+						ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second);
 					}
 					break;
 				case SQL_INTEGER:
@@ -528,12 +529,12 @@ static int odbc_log(struct ast_cdr *cdr)
 						int integer = 0;
 						if (sscanf(colptr, "%d", &integer) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(12);
-						ast_str_append(&sql2, 0, "%d,", integer);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
 					}
 					break;
 				case SQL_BIGINT:
@@ -541,12 +542,12 @@ static int odbc_log(struct ast_cdr *cdr)
 						long long integer = 0;
 						if (sscanf(colptr, "%lld", &integer) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(24);
-						ast_str_append(&sql2, 0, "%lld,", integer);
+						ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer);
 					}
 					break;
 				case SQL_SMALLINT:
@@ -554,12 +555,12 @@ static int odbc_log(struct ast_cdr *cdr)
 						short integer = 0;
 						if (sscanf(colptr, "%hd", &integer) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(6);
-						ast_str_append(&sql2, 0, "%d,", integer);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
 					}
 					break;
 				case SQL_TINYINT:
@@ -567,12 +568,12 @@ static int odbc_log(struct ast_cdr *cdr)
 						char integer = 0;
 						if (sscanf(colptr, "%hhd", &integer) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(4);
-						ast_str_append(&sql2, 0, "%d,", integer);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
 					}
 					break;
 				case SQL_BIT:
@@ -580,14 +581,14 @@ static int odbc_log(struct ast_cdr *cdr)
 						char integer = 0;
 						if (sscanf(colptr, "%hhd", &integer) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-							break;
+							continue;
 						}
 						if (integer != 0)
 							integer = 1;
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(2);
-						ast_str_append(&sql2, 0, "%d,", integer);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
 					}
 					break;
 				case SQL_NUMERIC:
@@ -596,12 +597,12 @@ static int odbc_log(struct ast_cdr *cdr)
 						double number = 0.0;
 						if (sscanf(colptr, "%lf", &number) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(entry->decimals);
-						ast_str_append(&sql2, 0, "%*.*lf,", entry->decimals, entry->radix, number);
+						ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
 					}
 					break;
 				case SQL_FLOAT:
@@ -611,35 +612,37 @@ static int odbc_log(struct ast_cdr *cdr)
 						double number = 0.0;
 						if (sscanf(colptr, "%lf", &number) != 1) {
 							ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
-							break;
+							continue;
 						}
 
-						ast_str_append(&sql, 0, "%s,", entry->name);
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
 						LENGTHEN_BUF2(entry->decimals);
-						ast_str_append(&sql2, 0, "%lf,", number);
+						ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number);
 					}
 					break;
 				default:
 					ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
+					continue;
 				}
+				first = 0;
 			}
 		}
 
 		/* Concatenate the two constructed buffers */
-		LENGTHEN_BUF1(sql2->used);
-		sql->str[sql->used - 1] = ')';
-		sql2->str[sql2->used - 1] = ')';
-		ast_str_append(&sql, 0, "%s", sql2->str);
+		LENGTHEN_BUF1(ast_str_strlen(sql2));
+		ast_str_append(&sql, 0, ")");
+		ast_str_append(&sql2, 0, ")");
+		ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
 
-		ast_verb(11, "[%s]\n", sql->str);
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
 
-		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql->str);
+		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
 		if (stmt) {
 			SQLRowCount(stmt, &rows);
 			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		}
 		if (rows == 0) {
-			ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
+			ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
 		}
 early_release:
 		ast_odbc_release_obj(obj);
@@ -647,11 +650,11 @@ early_release:
 	AST_RWLIST_UNLOCK(&odbc_tables);
 
 	/* Next time, just allocate buffers that are that big to start with. */
-	if (sql->used > maxsize) {
-		maxsize = sql->used;
+	if (ast_str_strlen(sql) > maxsize) {
+		maxsize = ast_str_strlen(sql);
 	}
-	if (sql2->used > maxsize2) {
-		maxsize2 = sql2->used;
+	if (ast_str_strlen(sql2) > maxsize2) {
+		maxsize2 = ast_str_strlen(sql2);
 	}
 
 	ast_free(sql);
diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c
index fea808dc697e2ca3d2add81bdeb890dd6050fb91..8a4a43e1ffb2fd90dd86307c1904ece950400e4c 100644
--- a/cdr/cdr_manager.c
+++ b/cdr/cdr_manager.c
@@ -95,7 +95,7 @@ static int load_config(int reload)
 			v = ast_variable_browse(cfg, cat);
 			while (v) {
 				if (customfields && !ast_strlen_zero(v->name) && !ast_strlen_zero(v->value)) {
-					if( (customfields->used + strlen(v->value) + strlen(v->name) + 14) < customfields->len) {
+					if ((ast_str_strlen(customfields) + strlen(v->value) + strlen(v->name) + 14) < ast_str_size(customfields)) {
 						ast_str_append(&customfields, -1, "%s: ${CDR(%s)}\r\n", v->value, v->name);
 						ast_log(LOG_NOTICE, "Added mapping %s: ${CDR(%s)}\n", v->value, v->name);
 					} else {
@@ -145,10 +145,10 @@ static int manager_log(struct ast_cdr *cdr)
 
 	buf[0] = 0;
 	/* Custom fields handling */
-	if (customfields != NULL && customfields->used > 0) {
+	if (customfields != NULL && ast_str_strlen(customfields)) {
 		memset(&dummy, 0, sizeof(dummy));
 		dummy.cdr = cdr;
-		pbx_substitute_variables_helper(&dummy, customfields->str, buf, sizeof(buf) - 1);
+		pbx_substitute_variables_helper(&dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
 	}
 
 	manager_event(EVENT_FLAG_CDR, "Cdr",
diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c
index eddc8187d5d85938767258d4698b426d076deb0f..34ba9dd0cc1d2c4d587e38b2fda054a44e00e8d7 100644
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -73,31 +73,31 @@ struct columns {
 
 static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
 
-#define LENGTHEN_BUF1(size)														\
-			do {																\
-				/* Lengthen buffer, if necessary */								\
-				if (sql->used + size + 1 > sql->len) {	\
-					if (ast_str_make_space(&sql, ((sql->len + size + 1) / 512 + 1) * 512) != 0) {	\
+#define LENGTHEN_BUF1(size)                                               \
+			do {                                                          \
+				/* Lengthen buffer, if necessary */                       \
+				if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \
+					if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) {	\
 						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n"); \
-						ast_free(sql);											\
-						ast_free(sql2);											\
-						AST_RWLIST_UNLOCK(&psql_columns);						\
-						return -1;												\
-					}															\
-				}																\
+						ast_free(sql);                                    \
+						ast_free(sql2);                                   \
+						AST_RWLIST_UNLOCK(&psql_columns);                 \
+						return -1;                                        \
+					}                                                     \
+				}                                                         \
 			} while (0)
 
-#define LENGTHEN_BUF2(size)														\
-			do {																\
-				if (sql2->used + size + 1 > sql2->len) {				\
-					if (ast_str_make_space(&sql2, ((sql2->len + size + 3) / 512 + 1) * 512) != 0) {	\
+#define LENGTHEN_BUF2(size)                               \
+			do {                                          \
+				if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) {  \
+					if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) {	\
 						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n");	\
-						ast_free(sql);											\
-						ast_free(sql2);											\
-						AST_RWLIST_UNLOCK(&psql_columns);						\
-						return -1;												\
-					}															\
-				}																\
+						ast_free(sql);                    \
+						ast_free(sql2);                   \
+						AST_RWLIST_UNLOCK(&psql_columns); \
+						return -1;                        \
+					}                                     \
+				}                                         \
 			} while (0)
 
 static int pgsql_log(struct ast_cdr *cdr)
@@ -125,7 +125,8 @@ static int pgsql_log(struct ast_cdr *cdr)
 		struct columns *cur;
 		struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
 		char buf[257], escapebuf[513], *value;
-
+		int first = 1;
+  
 		if (!sql || !sql2) {
 			if (sql) {
 				ast_free(sql);
@@ -150,85 +151,86 @@ static int pgsql_log(struct ast_cdr *cdr)
 				if (cur->notnull && !cur->hasdefault) {
 					/* Field is NOT NULL (but no default), must include it anyway */
 					LENGTHEN_BUF1(strlen(cur->name) + 2);
-					ast_str_append(&sql, 0, "\"%s\",", cur->name);
+					ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
 					LENGTHEN_BUF2(3);
-					ast_str_append(&sql2, 0, "'',");
+					ast_str_append(&sql2, 0, "%s''", first ? "" : ",");
+					first = 0;
 				}
 				continue;
 			}
 
 			LENGTHEN_BUF1(strlen(cur->name) + 2);
-			ast_str_append(&sql, 0, "\"%s\",", cur->name);
+			ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
 
 			if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
-					LENGTHEN_BUF2(12);
-					ast_str_append(&sql2, 0, "%ld", cdr->start.tv_sec);
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->start.tv_sec);
 				} else if (strncmp(cur->type, "float", 5) == 0) {
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "%f", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
 				} else {
 					/* char, hopefully */
-					LENGTHEN_BUF2(30);
+					LENGTHEN_BUF2(31);
 					ast_localtime(&cdr->start, &tm, NULL);
 					ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-					ast_str_append(&sql2, 0, "%s", buf);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
 				}
 			} else if (strcmp(cur->name, "answer") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
-					LENGTHEN_BUF2(12);
-					ast_str_append(&sql2, 0, "%ld", cdr->answer.tv_sec);
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->answer.tv_sec);
 				} else if (strncmp(cur->type, "float", 5) == 0) {
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "%f", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
 				} else {
 					/* char, hopefully */
-					LENGTHEN_BUF2(30);
+					LENGTHEN_BUF2(31);
 					ast_localtime(&cdr->start, &tm, NULL);
 					ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-					ast_str_append(&sql2, 0, "%s", buf);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
 				}
 			} else if (strcmp(cur->name, "end") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
-					LENGTHEN_BUF2(12);
-					ast_str_append(&sql2, 0, "%ld", cdr->end.tv_sec);
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->end.tv_sec);
 				} else if (strncmp(cur->type, "float", 5) == 0) {
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "%f", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
 				} else {
 					/* char, hopefully */
-					LENGTHEN_BUF2(30);
+					LENGTHEN_BUF2(31);
 					ast_localtime(&cdr->end, &tm, NULL);
 					ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-					ast_str_append(&sql2, 0, "%s", buf);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
 				}
 			} else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
 				if (cur->type[0] == 'i') {
 					/* Get integer, no need to escape anything */
 					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
-					LENGTHEN_BUF2(12);
-					ast_str_append(&sql2, 0, "%s", value);
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
 				} else if (strncmp(cur->type, "float", 5) == 0) {
 					struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "%f", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
 				} else {
 					/* Char field, probably */
 					struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "'%f'", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
 				}
 			} else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
 					/* Integer, no need to escape anything */
 					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1);
-					LENGTHEN_BUF2(12);
-					ast_str_append(&sql2, 0, "%s", value);
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
 				} else {
 					/* Although this is a char field, there are no special characters in the values for these fields */
 					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
-					LENGTHEN_BUF2(30);
-					ast_str_append(&sql2, 0, "'%s'", value);
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value);
 				}
 			} else {
 				/* Arbitrary field, could be anything */
@@ -236,20 +238,20 @@ static int pgsql_log(struct ast_cdr *cdr)
 				if (strncmp(cur->type, "int", 3) == 0) {
 					long long whatever;
 					if (value && sscanf(value, "%lld", &whatever) == 1) {
-						LENGTHEN_BUF2(25);
-						ast_str_append(&sql2, 0, "%lld", whatever);
+						LENGTHEN_BUF2(26);
+						ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever);
 					} else {
-						LENGTHEN_BUF2(1);
-						ast_str_append(&sql2, 0, "0");
+						LENGTHEN_BUF2(2);
+						ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
 					}
 				} else if (strncmp(cur->type, "float", 5) == 0) {
 					long double whatever;
 					if (value && sscanf(value, "%Lf", &whatever) == 1) {
-						LENGTHEN_BUF2(50);
-						ast_str_append(&sql2, 0, "%30Lf", whatever);
+						LENGTHEN_BUF2(51);
+						ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever);
 					} else {
-						LENGTHEN_BUF2(1);
-						ast_str_append(&sql2, 0, "0");
+						LENGTHEN_BUF2(2);
+						ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
 					}
 				/* XXX Might want to handle dates, times, and other misc fields here XXX */
 				} else {
@@ -257,19 +259,16 @@ static int pgsql_log(struct ast_cdr *cdr)
 						PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL);
 					else
 						escapebuf[0] = '\0';
-					LENGTHEN_BUF2(strlen(escapebuf) + 2);
-					ast_str_append(&sql2, 0, "'%s'", escapebuf);
+					LENGTHEN_BUF2(strlen(escapebuf) + 3);
+					ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf);
 				}
 			}
-			LENGTHEN_BUF2(1);
-			ast_str_append(&sql2, 0, ",");
+			first = 0;
   		}
 		AST_RWLIST_UNLOCK(&psql_columns);
-		LENGTHEN_BUF1(sql2->len);
-		sql->str[sql->used - 1] = ')';
-		sql2->str[sql2->used - 1] = ')';
-		ast_str_append(&sql, 0, "%s", sql2->str);
-		ast_verb(11, "[%s]\n", sql->str);
+		LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
+		ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
 
 		ast_debug(2, "inserting a CDR record.\n");
 
@@ -297,7 +296,7 @@ static int pgsql_log(struct ast_cdr *cdr)
 				return -1;
 			}
 		}
-		result = PQexec(conn, sql->str);
+		result = PQexec(conn, ast_str_buffer(sql));
 		if (PQresultStatus(result) != PGRES_COMMAND_OK) {
 			pgerror = PQresultErrorMessage(result);
 			ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n");
@@ -308,7 +307,7 @@ static int pgsql_log(struct ast_cdr *cdr)
 				ast_log(LOG_ERROR, "Connection reestablished.\n");
 				connected = 1;
 				PQclear(result);
-				result = PQexec(conn, sql->str);
+				result = PQexec(conn, ast_str_buffer(sql));
 				if (PQresultStatus(result) != PGRES_COMMAND_OK) {
 					pgerror = PQresultErrorMessage(result);
 					ast_log(LOG_ERROR, "HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c
index 8541d0888f482a74bf2638ff555529b2c67fe988..3bac49550fd1c9948190bd3da883e7d206dae211 100644
--- a/cdr/cdr_sqlite3_custom.c
+++ b/cdr/cdr_sqlite3_custom.c
@@ -101,13 +101,10 @@ static int load_column_config(const char *tmp)
 			ast_free(save);
 			return -1;
 		}
-		if (!column_string->used)
-			ast_str_set(&column_string, 0, "%s", escaped);
-		else
-			ast_str_append(&column_string, 0, ",%s", escaped);
+		ast_str_append(&column_string, 0, "%s%s", ast_str_strlen(column_string) ? "," : "", escaped);
 		sqlite3_free(escaped);
 	}
-	if (!(columns = ast_strdup(column_string->str))) {
+	if (!(columns = ast_strdup(ast_str_buffer(column_string)))) {
 		ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table);
 		ast_free(column_string);
 		ast_free(save);
@@ -158,17 +155,16 @@ static int load_config(int reload)
 	struct ast_variable *mappingvar;
 	const char *tmp;
 
-	if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
-		if (reload)
-			ast_log(LOG_WARNING, "Failed to reload configuration file.\n");
-		else
-			ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
+	if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated.");
 		return -1;
-	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
 		return 0;
+	}
 
-	if (reload)
+	if (reload) {
 		free_config();
+	}
 
 	ast_mutex_lock(&lock);
 
@@ -180,17 +176,15 @@ static int load_config(int reload)
 	}
 
 	/* Mapping must have a table name */
-	tmp = ast_variable_retrieve(cfg, "master", "table");
-	if (!ast_strlen_zero(tmp))
+	if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "master", "table"))) {
 		ast_copy_string(table, tmp, sizeof(table));
-	else {
+	} else {
 		ast_log(LOG_WARNING, "Table name not specified.  Assuming cdr.\n");
 		strcpy(table, "cdr");
 	}
 
 	/* Columns */
-	tmp = ast_variable_retrieve(cfg, "master", "columns");
-	if (load_column_config(tmp)) {
+	if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) {
 		ast_mutex_unlock(&lock);
 		ast_config_destroy(cfg);
 		free_config();
@@ -198,8 +192,7 @@ static int load_config(int reload)
 	}
 
 	/* Values */
-	tmp = ast_variable_retrieve(cfg, "master", "values");
-	if (load_values_config(tmp)) {
+	if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) {
 		ast_mutex_unlock(&lock);
 		ast_config_destroy(cfg);
 		free_config();
@@ -230,8 +223,9 @@ static int free_config(void)
 		columns = NULL;
 	}
 
-	while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list)))
+	while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) {
 		ast_free(value);
+	}
 
 	ast_mutex_unlock(&lock);
 
@@ -253,16 +247,12 @@ static int sqlite3_log(struct ast_cdr *cdr)
 		struct ast_str *value_string = ast_str_create(1024);
 		dummy.cdr = cdr;
 		AST_LIST_TRAVERSE(&sql_values, value, list) {
-			memset(subst_buf, 0, sizeof(subst_buf));
 			pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
 			escaped = sqlite3_mprintf("%q", subst_buf);
-			if (!value_string->used)
-				ast_str_append(&value_string, 0, "'%s'", escaped);
-			else
-				ast_str_append(&value_string, 0, ",'%s'", escaped);
+			ast_str_append(&value_string, 0, "%s'%s'", ast_str_strlen(value_string) ? "," : "", escaped);
 			sqlite3_free(escaped);
 		}
-		sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, value_string->str);
+		sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, ast_str_buffer(value_string));
 		ast_debug(1, "About to log: %s\n", sql);
 		ast_free(value_string);
 	}
@@ -272,8 +262,9 @@ static int sqlite3_log(struct ast_cdr *cdr)
 	/* XXX This seems awful arbitrary... */
 	for (count = 0; count < 5; count++) {
 		res = sqlite3_exec(db, sql, NULL, NULL, &error);
-		if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
+		if (res != SQLITE_BUSY && res != SQLITE_LOCKED) {
 			break;
+		}
 		usleep(200);
 	}
 
@@ -282,8 +273,9 @@ static int sqlite3_log(struct ast_cdr *cdr)
 		sqlite3_free(error);
 	}
 
-	if (sql)
+	if (sql) {
 		sqlite3_free(sql);
+	}
 
 	ast_mutex_unlock(&lock);
 
@@ -313,8 +305,9 @@ static int load_module(void)
 			free_config();
 			return AST_MODULE_LOAD_DECLINE;
 		}
-	} else
+	} else {
 		return AST_MODULE_LOAD_DECLINE;
+	}
 
 	/* is the database there? */
 	snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR);
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index dff85fd7d9bca7b5069a2ec5d9124932501e1cb1..b3a728752a5c43a505e73abe61c81f7973975f42 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -6102,12 +6102,12 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 		else	
 			ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
 		for (x = 0; x < 3; x++) {
-			if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6))
+			if ((idx != x) && i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name), i->subs[x].owner->name + 6))
 				break;
 		}
 		y++;
 	} while (x < 3);
-	tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", chan_name->str);
+	tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name));
 	if (!tmp)
 		return NULL;
 	tmp->tech = &dahdi_tech;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f8391cef05cbbed0ea4d2568d07b23e0bda88bb9..37ae2ca24f56f61e8ad4c9464a0a480129ea5a3f 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -2031,6 +2031,8 @@ static void temp_pvt_cleanup(void *);
 
 /*! \brief A per-thread temporary pvt structure */
 AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
+AST_THREADSTORAGE(transmit_state_buffer);
+AST_THREADSTORAGE(mailbox_buffer);
 
 #ifdef LOW_MEMORY
 static void ts_ast_rtp_destroy(void *);
@@ -2261,7 +2263,7 @@ static int reload_config(enum channelreloadreason reason);
 static int expire_register(const void *data);
 static void *do_monitor(void *data);
 static int restart_monitor(void);
-static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer);
+static char *peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer);
 /* static int sip_addrcmp(char *name, struct sockaddr_in *sin);	Support for peer matching */
 static int sip_refer_allocate(struct sip_pvt *p);
 static void ast_quiet_chan(struct ast_channel *chan);
@@ -2707,7 +2709,7 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
 		}
 
 		/* Read in headers one line at a time */
-		while (req.len < 4 || strncmp((char *)&req.data->str + req.len - 4, "\r\n\r\n", 4)) {
+		while (req.len < 4 || strncmp(ast_str_buffer(req.data) + req.len - 4, "\r\n\r\n", 4)) {
 			ast_mutex_lock(&tcptls_session->lock);
 			if (!fgets(buf, sizeof(buf), tcptls_session->f)) {
 				ast_mutex_unlock(&tcptls_session->lock);
@@ -2716,8 +2718,8 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
 			ast_mutex_unlock(&tcptls_session->lock);
 			if (me->stop) 
 				 goto cleanup;
-			ast_str_append(&req.data, 0, "%s", buf);
-			req.len = req.data->used;
+			ast_str_append(&req.data, -1, "%s", buf);
+			req.len = ast_str_strlen(req.data);
 		}
 		copy_request(&reqcpy, &req);
 		parse_request(&reqcpy);
@@ -2733,8 +2735,8 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
 				if (me->stop)
 					goto cleanup;
 				cl -= strlen(buf);
-				ast_str_append(&req.data, 0, "%s", buf);
-				req.len = req.data->used;
+				ast_str_append(&req.data, -1, "%s", buf);
+				req.len = ast_str_strlen(req.data);
 			}
 		}
 		/*! \todo XXX If there's no Content-Length or if the content-length and what
@@ -3163,21 +3165,24 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len)
 	int res = 0;
 	const struct sockaddr_in *dst = sip_real_dst(p);
 
-	ast_debug(2, "Trying to put '%.10s' onto %s socket destined for %s:%d\n", data->str, get_transport_pvt(p), ast_inet_ntoa(dst->sin_addr), htons(dst->sin_port));
+	ast_debug(2, "Trying to put '%.10s' onto %s socket destined for %s:%d\n", ast_str_buffer(data), get_transport_pvt(p), ast_inet_ntoa(dst->sin_addr), htons(dst->sin_port));
 
-	if (sip_prepare_socket(p) < 0)
+	if (sip_prepare_socket(p) < 0) {
 		return XMIT_ERROR;
+	}
 
-	if (p->socket.tcptls_session)
+	if (p->socket.tcptls_session) {
 		ast_mutex_lock(&p->socket.tcptls_session->lock);
+	}
 
-	if (p->socket.type & SIP_TRANSPORT_UDP) 
-		res = sendto(p->socket.fd, data->str, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
-	else {
-		if (p->socket.tcptls_session->f) 
-			res = ast_tcptls_server_write(p->socket.tcptls_session, data->str, len);
-		else
+	if (p->socket.type & SIP_TRANSPORT_UDP) {
+		res = sendto(p->socket.fd, ast_str_buffer(data), len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+	} else {
+		if (p->socket.tcptls_session->f) {
+			res = ast_tcptls_server_write(p->socket.tcptls_session, ast_str_buffer(data), len);
+		} else {
 			ast_debug(2, "No p->socket.tcptls_session->f len=%d\n", len);
+		}
 	} 
 
 	if (p->socket.tcptls_session)
@@ -3193,8 +3198,9 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len)
 			res = XMIT_ERROR;	/* Don't bother with trying to transmit again */
 		}
 	}
-	if (res != len)
+	if (res != len) {
 		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
+	}
 
 	return res;
 }
@@ -3354,10 +3360,10 @@ static int retrans_pkt(const void *data)
 			ast_verbose("Retransmitting #%d (%s) to %s:%d:\n%s\n---\n",
 				pkt->retrans, sip_nat_mode(pkt->owner),
 				ast_inet_ntoa(dst->sin_addr),
-				ntohs(dst->sin_port), pkt->data->str);
+				ntohs(dst->sin_port), ast_str_buffer(pkt->data));
 		}
 
-		append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data->str);
+		append_history(pkt->owner, "ReTx", "%d %s", reschedule, ast_str_buffer(pkt->data));
 		xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
 		sip_pvt_unlock(pkt->owner);
 		if (xmitres == XMIT_ERROR)
@@ -3472,7 +3478,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res
 		ast_free(pkt);
 		return AST_FAILURE;
 	}
-	ast_str_set(&pkt->data, 0, "%s%s", data->str, "\0");
+	ast_str_set(&pkt->data, 0, "%s", ast_str_buffer(data));
 	pkt->packetlen = len;
 	/* copy other parameters from the caller */
 	pkt->method = sipmethod;
@@ -3674,7 +3680,7 @@ static void __sip_pretend_ack(struct sip_pvt *p)
 			return;
 		}
 		cur = p->packets;
-		method = (cur->method) ? cur->method : find_sip_method(cur->data->str);
+		method = (cur->method) ? cur->method : find_sip_method(ast_str_buffer(cur->data));
 		__sip_ack(p, cur->seqno, cur->is_resp, method);
 	}
 }
@@ -3687,7 +3693,7 @@ static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
 
 	for (cur = p->packets; cur; cur = cur->next) {
 		if (cur->seqno == seqno && cur->is_resp == resp &&
-			(cur->is_resp || method_match(sipmethod, cur->data->str))) {
+			(cur->is_resp || method_match(sipmethod, ast_str_buffer(cur->data)))) {
 			/* this is our baby */
 			if (cur->retransid > -1) {
 				if (sipdebug)
@@ -3716,7 +3722,7 @@ static void add_blank(struct sip_request *req)
 	if (!req->lines) {
 		/* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */
 		ast_str_append(&req->data, 0, "\r\n");
-		req->len = req->data->used;
+		req->len = ast_str_strlen(req->data);
 	}
 }
 
@@ -3732,12 +3738,12 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
 		ast_verbose("\n<--- %sTransmitting (%s) to %s:%d --->\n%s\n<------------>\n",
 			reliable ? "Reliably " : "", sip_nat_mode(p),
 			ast_inet_ntoa(dst->sin_addr),
-			ntohs(dst->sin_port), req->data->str);
+			ntohs(dst->sin_port), ast_str_buffer(req->data));
 	}
 	if (p->do_history) {
 		struct sip_request tmp = { .rlPart1 = NULL, };
 		parse_copy(&tmp, req);
-		append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data->str, get_header(&tmp, "CSeq"), 
+		append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", ast_str_buffer(tmp.data), get_header(&tmp, "CSeq"), 
 			(tmp.method == SIP_RESPONSE || tmp.method == SIP_UNKNOWN) ? tmp.rlPart2 : sip_methods[tmp.method].text);
 		ast_free(tmp.data);
 	}
@@ -3765,15 +3771,16 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
 
 	add_blank(req);
 	if (sip_debug_test_pvt(p)) {
-		if (ast_test_flag(&p->flags[0], SIP_NAT_ROUTE))
-			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port), req->data->str);
-		else
-			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port), req->data->str);
+		if (ast_test_flag(&p->flags[0], SIP_NAT_ROUTE)) {
+			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port), ast_str_buffer(req->data));
+		} else {
+			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port), ast_str_buffer(req->data));
+		}
 	}
 	if (p->do_history) {
 		struct sip_request tmp = { .rlPart1 = NULL, };
 		parse_copy(&tmp, req);
-		append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", tmp.data->str, get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
+		append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", ast_str_buffer(tmp.data), get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
 		ast_free(tmp.data);
 	}
 	res = (reliable) ?
@@ -5504,7 +5511,7 @@ static int sip_hangup(struct ast_channel *ast)
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 
 	/* Start the process if it's not already started */
-	if (!p->alreadygone && p->initreq.data && !ast_strlen_zero(p->initreq.data->str)) {
+	if (!p->alreadygone && p->initreq.data && ast_str_strlen(p->initreq.data)) {
 		if (needcancel) {	/* Outgoing call, not up */
 			if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 				/* stop retransmitting an INVITE that has not received a response */
@@ -7017,7 +7024,7 @@ static int lws2sws(char *msgbuf, int len)
 */
 static int parse_request(struct sip_request *req)
 {
-	char *c = req->data->str, **dst = req->header;
+	char *c = ast_str_buffer(req->data), **dst = req->header;
 	int i = 0, lim = SIP_MAX_HEADERS - 1;
 	unsigned int skipping_headers = 0;
 
@@ -7915,7 +7922,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		/* Activate a re-invite */
 		ast_queue_frame(p->owner, &ast_null_frame);
 		/* Queue Manager Unhold event */
-		append_history(p, "Unhold", "%s", req->data->str);
+		append_history(p, "Unhold", "%s", ast_str_buffer(req->data));
 		if (sip_cfg.callevents)
 			manager_event(EVENT_FLAG_CALL, "Hold",
 				      "Status: Off\r\n"
@@ -7937,7 +7944,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		/* Activate a re-invite */
 		ast_queue_frame(p->owner, &ast_null_frame);
 		/* Queue Manager Hold event */
-		append_history(p, "Hold", "%s", req->data->str);
+		append_history(p, "Hold", "%s", ast_str_buffer(req->data));
 		if (sip_cfg.callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
 			manager_event(EVENT_FLAG_CALL, "Hold",
 				      "Status: On\r\n"
@@ -7980,8 +7987,8 @@ static int add_header(struct sip_request *req, const char *var, const char *valu
 		return -1;
 	}
 
-	ast_str_append(&req->data, 0, "%s: %s\r\n", var, value);
-	req->header[req->headers] = req->data->str + req->len;
+	ast_str_append(&req->data, -1, "%s: %s\r\n", var, value);
+	req->header[req->headers] = ast_str_buffer(req->data) + req->len;
 
 	if (sip_cfg.compactheaders)
 		var = find_alias(var, var);
@@ -8007,16 +8014,12 @@ static int add_line(struct sip_request *req, const char *line)
 		ast_log(LOG_WARNING, "Out of SIP line space\n");
 		return -1;
 	}
-	if (!req->lines)
+	if (!req->lines) {
 		/* Add extra empty return */
-		req->len += ast_str_append(&req->data, 0, "\r\n");
-	if (req->len >= sizeof(req->data->str) - 4) {
-		ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
-		return -1;
+		req->len += ast_str_append(&req->data, -1, "\r\n");
 	}
-	req->line[req->lines] = req->data->str + req->len;
-	ast_str_append(&req->data, 0, "%s", line);
-	req->len += strlen(req->line[req->lines]);
+	req->line[req->lines] = ast_str_buffer(req->data) + ast_str_strlen(req->data);
+	req->len += ast_str_append(&req->data, -1, "%s", line);
 	req->lines++;
 	return 0;	
 }
@@ -8080,7 +8083,7 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
 
 			/* Find ;rport;  (empty request) */
 			rport = strstr(leftmost, ";rport");
-			if (rport && *(rport+6) == '=') 
+			if (rport && *(rport + 6) == '=') 
 				rport = NULL;		/* We already have a parameter to rport */
 
 			/* Check rport if NAT=yes or NAT=rfc3581 (which is the default setting)  */
@@ -8232,9 +8235,9 @@ static int init_resp(struct sip_request *resp, const char *msg)
 	resp->method = SIP_RESPONSE;
 	if (!(resp->data = ast_str_create(SIP_MIN_PACKET)))
 		return -1;
-	resp->header[0] = resp->data->str;
-	ast_str_set(&resp->data, 0, "SIP/2.0 %s\r\n", msg);
-	resp->len = strlen(resp->header[0]);
+	ast_str_set(&resp->data, -1, "SIP/2.0 %s\r\n", msg);
+	resp->header[0] = ast_str_buffer(resp->data);
+	resp->len = ast_str_strlen(resp->data);
 	resp->headers++;
 	return 0;
 }
@@ -8247,9 +8250,9 @@ static int init_req(struct sip_request *req, int sipmethod, const char *recip)
 	if (!(req->data = ast_str_create(SIP_MIN_PACKET)))
 		return -1;
 	req->method = sipmethod;
-	req->header[0] = req->data->str;
-	ast_str_set(&req->data, 0, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
-	req->len = strlen(req->header[0]);
+	ast_str_set(&req->data, -1, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
+	req->header[0] = ast_str_buffer(req->data);
+	req->len = ast_str_strlen(req->data);
 	req->headers++;
 	return 0;
 }
@@ -8896,11 +8899,11 @@ static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
 	ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
 	if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
 		ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
-	len = m_modem->used + a_modem->used;
+	len = ast_str_strlen(m_modem) + ast_str_strlen(a_modem);
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
-	add_line(resp, m_modem->str);
-	add_line(resp, a_modem->str);
+	add_line(resp, ast_str_buffer(m_modem));
+	add_line(resp, ast_str_buffer(a_modem));
 
 	/* Update lastrtprx when we send our SDP */
 	p->lastrtprx = p->lastrtptx = time(NULL);
@@ -8938,10 +8941,12 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo,
 {
 	/* First, get our address */
 	ast_rtp_get_us(p->rtp, sin);
-	if (p->vrtp)
+	if (p->vrtp) {
 		ast_rtp_get_us(p->vrtp, vsin);
-	if (p->trtp)
+	}
+	if (p->trtp) {
 		ast_rtp_get_us(p->trtp, tsin);
+	}
 
 	/* Now, try to figure out where we want them to send data */
 	/* Is this a re-invite to move the media out, then use the original offer from caller  */
@@ -8991,12 +8996,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	struct sockaddr_in tdest = { 0, };
 
 	/* SDP fields */
-	char *version = 	"v=0\r\n";		/* Protocol version */
-	char subject[256];				/* Subject of the session */
-	char owner[256];				/* Session owner/creator */
-	char connection[256];				/* Connection data */
-	char *session_time = "t=0 0\r\n"; 			/* Time the session is active */
-	char bandwidth[256] = "";			/* Max bitrate */
+	char *version = "v=0\r\n";                      /* Protocol version */
+	char subject[256];                              /* Subject of the session */
+	char owner[256];                                /* Session owner/creator */
+	char connection[256];                           /* Connection data */
+	char *session_time = "t=0 0\r\n";               /* Time the session is active */
+	char bandwidth[256] = "";                       /* Max bitrate */
 	char *hold;
 	struct ast_str *m_audio = ast_str_alloca(256);  /* Media declaration line for audio */
 	struct ast_str *m_video = ast_str_alloca(256);  /* Media declaration line for video */
@@ -9030,11 +9035,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 
 	/* Set RTP Session ID and version */
 	if (!p->sessionid) {
-		p->sessionid = (int)ast_random();
+		p->sessionid = (int) ast_random();
 		p->sessionversion = p->sessionid;
 	} else {
-		if (oldsdp == FALSE)
+		if (oldsdp == FALSE) {
 			p->sessionversion++;
+		}
 	}
 
 	capability = p->jointcapability;
@@ -9052,23 +9058,26 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 #endif
 
 	/* Check if we need audio */
-	if (capability & AST_FORMAT_AUDIO_MASK)
+	if (capability & AST_FORMAT_AUDIO_MASK) {
 		needaudio = TRUE;
+	}
 
 	/* Check if we need video in this call */
 	if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
 		if (p->vrtp) {
 			needvideo = TRUE;
 			ast_debug(2, "This call needs video offers!\n");
-		} else
+		} else {
 			ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
+		}
 	}
 
 	/* Get our media addresses */
 	get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
 		
-	if (debug) 
-		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port));	
+	if (debug) {
+		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port));
+	}
 
 	/* Ok, we need video. Let's add what we need for video and set codecs.
 	   Video is handled differently than audio since we can not transcode. */
@@ -9076,30 +9085,36 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
 
 		/* Build max bitrate string */
-		if (p->maxcallbitrate)
+		if (p->maxcallbitrate) {
 			snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
-		if (debug) 
-			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));	
+		}
+		if (debug) {
+			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));
+		}
 	}
 
 	/* Check if we need text in this call */
 	if((capability & AST_FORMAT_TEXT_MASK) && !p->notext) {
-		if (sipdebug_text)
+		if (sipdebug_text) {
 			ast_verbose("We think we can do text\n");
+		}
 		if (p->trtp) {
-			if (sipdebug_text)
+			if (sipdebug_text) {
 				ast_verbose("And we have a text rtp object\n");
+			}
 			needtext = TRUE;
 			ast_debug(2, "This call needs text offers! \n");
-		} else
+		} else {
 			ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
+		}
 	}
 		
 	/* Ok, we need text. Let's add what we need for text and set codecs.
 	   Text is handled differently than audio since we can not transcode. */
 	if (needtext) {
-		if (sipdebug_text)
+		if (sipdebug_text) {
 			ast_verbose("Lets set up the text sdp\n");
+		}
 		/* Determine text destination */
 		if (p->tredirip.sin_addr.s_addr) {
 			tdest.sin_addr = p->tredirip.sin_addr;
@@ -9110,9 +9125,9 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		}
 		ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
 
-		if (debug) /* XXX should I use tdest below ? */
+		if (debug) { /* XXX should I use tdest below ? */
 			ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));	
-
+		}
 	}
 
 	/* Start building generic SDP headers */
@@ -9124,12 +9139,13 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
 	ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
 
-	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
+	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) {
 		hold = "a=recvonly\r\n";
-	else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
+	} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE) {
 		hold = "a=inactive\r\n";
-	else
+	} else {
 		hold = "a=sendrecv\r\n";
+	}
 
 	/* Now, start adding audio codecs. These are added in this order:
 		- First what was requested by the calling channel
@@ -9153,14 +9169,15 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	for (x = 0; x < 32; x++) {
 		int codec;
 
-		if (!(codec = ast_codec_pref_index(&p->prefs, x)))
-			break; 
-
-		if (!(capability & codec))
+		if (!(codec = ast_codec_pref_index(&p->prefs, x))) {
+			break;
+		}
+		if (!(capability & codec)) {
 			continue;
-
-		if (alreadysent & codec)
+		}
+		if (alreadysent & codec) {
 			continue;
+		}
 
 		add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
 				 &m_audio, &a_audio,
@@ -9170,67 +9187,85 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 
 	/* Now send any other common audio and video codecs, and non-codec formats: */
 	for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
-		if (!(capability & x))	/* Codec not requested */
+		if (!(capability & x)) {  /* Codec not requested */
 			continue;
+		}
 
-		if (alreadysent & x)	/* Already added to SDP */
+		if (alreadysent & x) {    /* Already added to SDP */
 			continue;
+		}
 
-		if (x & AST_FORMAT_AUDIO_MASK)
+		if (x & AST_FORMAT_AUDIO_MASK) {
 			add_codec_to_sdp(p, x, SDP_SAMPLE_RATE(x),
 				 &m_audio, &a_audio, debug, &min_audio_packet_size);
-		else if (x & AST_FORMAT_VIDEO_MASK) 
+		} else if (x & AST_FORMAT_VIDEO_MASK) {
 			add_vcodec_to_sdp(p, x, 90000,
 				 &m_video, &a_video, debug, &min_video_packet_size);
-		else if (x & AST_FORMAT_TEXT_MASK)
+		} else if (x & AST_FORMAT_TEXT_MASK) {
 			add_tcodec_to_sdp(p, x, 1000,
 				 &m_text, &a_text, debug, &min_text_packet_size);
+		}
 	}
 
 	/* Now add DTMF RFC2833 telephony-event as a codec */
 	for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
-		if (!(p->jointnoncodeccapability & x))
+		if (!(p->jointnoncodeccapability & x)) {
 			continue;
+		}
 
 		add_noncodec_to_sdp(p, x, 8000, &m_audio, &a_audio, debug);
 	}
 
 	ast_debug(3, "-- Done with adding codecs to SDP\n");
 
-	if (!p->owner || !ast_internal_timing_enabled(p->owner))
+	if (!p->owner || !ast_internal_timing_enabled(p->owner)) {
 		ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
+	}
 
-	if (min_audio_packet_size)
+	if (min_audio_packet_size) {
 		ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
+	}
 
  	/* XXX don't think you can have ptime for video */
-	if (min_video_packet_size)
+	if (min_video_packet_size) {
 		ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
+	}
 
  	/* XXX don't think you can have ptime for text */
- 	if (min_text_packet_size)
+ 	if (min_text_packet_size) {
  		ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
+	}
  
-	if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
-			m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
-			a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
+	if (	ast_str_size(m_audio) - ast_str_strlen(m_audio) < 2 ||
+			ast_str_size(m_video) - ast_str_strlen(m_video) < 2 ||
+			ast_str_size(m_text) - ast_str_strlen(m_text) < 2 ||
+			ast_str_size(a_text) - ast_str_strlen(a_text) < 2 ||
+			ast_str_size(a_audio) - ast_str_strlen(a_audio) < 2 ||
+			ast_str_size(a_video) - ast_str_strlen(a_video) < 2) {
 		ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
+	}
 
-	if (needaudio)
+	if (needaudio) {
  		ast_str_append(&m_audio, 0, "\r\n");
- 	if (needvideo)
+	}
+ 	if (needvideo) {
  		ast_str_append(&m_video, 0, "\r\n");
- 	if (needtext)
+	}
+ 	if (needtext) {
  		ast_str_append(&m_text, 0, "\r\n");
+	}
 
  	len = strlen(version) + strlen(subject) + strlen(owner) +
 		strlen(connection) + strlen(session_time);
-	if (needaudio)
-		len += m_audio->used + a_audio->used + strlen(hold);
- 	if (needvideo) /* only if video response is appropriate */
- 		len += m_video->used + a_video->used + strlen(bandwidth) + strlen(hold);
- 	if (needtext) /* only if text response is appropriate */
- 		len += m_text->used + a_text->used + strlen(hold);
+	if (needaudio) {
+		len += ast_str_strlen(m_audio) + ast_str_strlen(a_audio) + strlen(hold);
+	}
+ 	if (needvideo) { /* only if video response is appropriate */
+ 		len += ast_str_strlen(m_video) + ast_str_strlen(a_video) + strlen(bandwidth) + strlen(hold);
+	}
+ 	if (needtext) { /* only if text response is appropriate */
+ 		len += ast_str_strlen(m_text) + ast_str_strlen(a_text) + strlen(hold);
+	}
 
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
@@ -9238,22 +9273,23 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	add_line(resp, owner);
 	add_line(resp, subject);
 	add_line(resp, connection);
-	if (needvideo)	 	/* only if video response is appropriate */
+	if (needvideo) {	 	/* only if video response is appropriate */
 		add_line(resp, bandwidth);
+	}
 	add_line(resp, session_time);
 	if (needaudio) {
-		add_line(resp, m_audio->str);
-		add_line(resp, a_audio->str);
+		add_line(resp, ast_str_buffer(m_audio));
+		add_line(resp, ast_str_buffer(a_audio));
 		add_line(resp, hold);
 	}
 	if (needvideo) { /* only if video response is appropriate */
-		add_line(resp, m_video->str);
-		add_line(resp, a_video->str);
+		add_line(resp, ast_str_buffer(m_video));
+		add_line(resp, ast_str_buffer(a_video));
 		add_line(resp, hold);	/* Repeat hold for the video stream */
 	}
 	if (needtext) { /* only if text response is appropriate */
-		add_line(resp, m_text->str);
-		add_line(resp, a_text->str);
+		add_line(resp, ast_str_buffer(m_text));
+		add_line(resp, ast_str_buffer(a_text));
 		add_line(resp, hold);	/* Repeat hold for the text stream */
 	}
 
@@ -9303,14 +9339,13 @@ static void copy_request(struct sip_request *dst, const struct sip_request *src)
 	 * the place and so a memcpy is the only way to accurately copy the string
 	 */
 
-	if (!dst->data && !(dst->data = ast_str_create(src->data->used + 1)))
+	if (!dst->data && !(dst->data = ast_str_create(ast_str_strlen(src->data) + 1)))
 		return;
-	else if (dst->data->len < src->data->used + 1)
-		ast_str_make_space(&dst->data, src->data->used + 1);
-		
-	memcpy(dst->data->str, src->data->str, src->data->used + 1);
-	dst->data->used = src->data->used;
-	offset = ((void *)dst->data->str) - ((void *)src->data->str);
+	else if (ast_str_size(dst->data) < ast_str_strlen(src->data) + 1)
+		ast_str_make_space(&dst->data, ast_str_strlen(src->data) + 1);
+
+	ast_str_set(&dst->data, 0, "%s", ast_str_buffer(src->data));
+	offset = ((void *)ast_str_buffer(dst->data)) - ((void *)ast_str_buffer(src->data));
 	/* Now fix pointer arithmetic */
 	for (x = 0; x < src->headers; x++)
 		dst->header[x] += offset;
@@ -9659,7 +9694,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
  	/* This is the request URI, which is the next hop of the call
  		which may or may not be the destination of the call
  	*/
-	ast_string_field_set(p, uri, invite->str);
+	ast_string_field_set(p, uri, ast_str_buffer(invite));
   
  	if (!ast_strlen_zero(p->todnid)) {
  		/*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */
@@ -9942,8 +9977,8 @@ static int find_calling_channel(struct ast_channel *c, void *data) {
 /*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
 static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
 {
-	struct ast_str *tmp = ast_str_alloca(4000);
-	char from[256], to[256];
+	struct ast_str *tmp = ast_str_thread_get(&transmit_state_buffer, 4000);
+	char from[256] = "", to[256] = "";
 	char *c, *mfrom, *mto;
 	struct sip_request req;
 	char hint[AST_MAX_EXTENSION];
@@ -9953,9 +9988,6 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 	char *pidfstate = "--";
 	char *pidfnote= "Ready";
 	
-	memset(from, 0, sizeof(from));
-	memset(to, 0, sizeof(to));
-
 	switch (state) {
 	case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
 		statestring = (global_notifyringing) ? "early" : "confirmed";
@@ -10145,8 +10177,8 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 		break;
 	}
 
-	add_header_contentLength(&req, tmp->used);
-	add_line(&req, tmp->str);
+	add_header_contentLength(&req, ast_str_strlen(tmp));
+	add_line(&req, ast_str_buffer(tmp));
 
 	p->pendinginvite = p->ocseq;	/* Remember that we have a pending NOTIFY in order not to confuse the NOTIFY subsystem */
 
@@ -10184,8 +10216,8 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs,
 			add_header(&req, "Subscription-State", "terminated;reason=timeout");
 	}
 
-	add_header_contentLength(&req, out->used);
-	add_line(&req, out->str);
+	add_header_contentLength(&req, ast_str_strlen(out));
+	add_line(&req, ast_str_buffer(out));
 
 	if (!p->initreq.headers) 
 		initialize_initreq(p, &req);
@@ -11452,7 +11484,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
 	if (res == AST_DYNSTR_BUILD_FAILED)
 		return AUTH_SECRET_FAILED; /*! XXX \todo need a better return code here */
 
-	c = buf->str;
+	c = ast_str_buffer(buf);
 
 	while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
 		for (i = keys; i->key != NULL; i++) {
@@ -13943,7 +13975,7 @@ static char *sip_qualify_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 }
 
 /*! \brief list peer mailboxes to CLI */
-static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer)
+static char *peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer)
 {
 	struct sip_mailbox *mailbox;
 
@@ -13954,6 +13986,7 @@ static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer
 			S_OR(mailbox->context, ""),
 			AST_LIST_NEXT(mailbox, entry) ? "," : "");
 	}
+	return ast_str_buffer(*mailbox_str);
 }
 
 /*! \brief Show one peer in detail (main function) */
@@ -13990,7 +14023,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		}
 	}
 	if (peer && type==0 ) { /* Normal listing */
-		struct ast_str *mailbox_str = ast_str_alloca(512);
+		struct ast_str *mailbox_str = ast_str_thread_get(&mailbox_buffer, 16);
 		ast_cli(fd, "\n\n");
 		ast_cli(fd, "  * Name       : %s\n", peer->name);
 		if (realtimepeers) {	/* Realtime is enabled */
@@ -14019,8 +14052,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		print_group(fd, peer->callgroup, 0);
 		ast_cli(fd, "  Pickupgroup  : ");
 		print_group(fd, peer->pickupgroup, 0);
-		peer_mailboxes_to_str(&mailbox_str, peer);
-		ast_cli(fd, "  Mailbox      : %s\n", mailbox_str->str);
+		ast_cli(fd, "  Mailbox      : %s\n", peer_mailboxes_to_str(&mailbox_str, peer));
 		ast_cli(fd, "  VM Extension : %s\n", peer->vmexten);
 		ast_cli(fd, "  LastMsgsSent : %d/%d\n", (peer->lastmsgssent & 0x7fff0000) >> 16, peer->lastmsgssent & 0xffff);
 		ast_cli(fd, "  Call limit   : %d\n", peer->call_limit);
@@ -14106,7 +14138,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		peer = unref_peer(peer, "sip_show_peer: unref_peer: done with peer ptr");
 	} else  if (peer && type == 1) { /* manager listing */
 		char buffer[256];
-		struct ast_str *mailbox_str = ast_str_alloca(512);
+		struct ast_str *mailbox_str = ast_str_thread_get(&mailbox_buffer, 16);
 		astman_append(s, "Channeltype: SIP\r\n");
 		astman_append(s, "ObjectName: %s\r\n", peer->name);
 		astman_append(s, "ChanObjectType: peer\r\n");
@@ -14127,8 +14159,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		astman_append(s, "%s\r\n", ast_print_group(buffer, sizeof(buffer), peer->callgroup));
 		astman_append(s, "Pickupgroup: ");
 		astman_append(s, "%s\r\n", ast_print_group(buffer, sizeof(buffer), peer->pickupgroup));
-		peer_mailboxes_to_str(&mailbox_str, peer);
-		astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str);
+		astman_append(s, "VoiceMailbox: %s\r\n", peer_mailboxes_to_str(&mailbox_str, peer));
 		astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
 		astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
 		astman_append(s, "Call-limit: %d\r\n", peer->call_limit);
@@ -14695,7 +14726,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags)
 		arg->numchans++;
 	}
 	if (cur->subscribed != NONE && arg->subscriptions) {
-		struct ast_str *mailbox_str = ast_str_alloca(512);
+		struct ast_str *mailbox_str = ast_str_thread_get(&mailbox_buffer, 16);
 		if (cur->subscribed == MWI_NOTIFICATION && cur->relatedpeer)
 			peer_mailboxes_to_str(&mailbox_str, cur->relatedpeer);
 		ast_cli(arg->fd, FORMAT4, ast_inet_ntoa(dst->sin_addr),
@@ -14705,7 +14736,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags)
 				cur->subscribed == MWI_NOTIFICATION ? "--" : cur->subscribeuri,
 				cur->subscribed == MWI_NOTIFICATION ? "<none>" : ast_extension_state2str(cur->laststate), 
 				subscription_type2str(cur->subscribed),
-				cur->subscribed == MWI_NOTIFICATION ? S_OR(mailbox_str->str, "<none>") : "<none>",
+				cur->subscribed == MWI_NOTIFICATION ? AS_OR(mailbox_str, "<none>") : "<none>",
 				cur->expiry
 			);
 		arg->numchans++;
@@ -15791,9 +15822,8 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
 	} else  if (!strcasecmp(colname, "useragent")) {
 		ast_copy_string(buf, peer->useragent, len);
 	} else  if (!strcasecmp(colname, "mailbox")) {
-		struct ast_str *mailbox_str = ast_str_alloca(512);
-		peer_mailboxes_to_str(&mailbox_str, peer);
-		ast_copy_string(buf, mailbox_str->str, len);
+		struct ast_str *mailbox_str = ast_str_thread_get(&mailbox_buffer, 16);
+		ast_copy_string(buf, peer_mailboxes_to_str(&mailbox_str, peer), len);
 	} else  if (!strcasecmp(colname, "context")) {
 		ast_copy_string(buf, peer->context, len);
 	} else  if (!strcasecmp(colname, "expire")) {
@@ -18092,12 +18122,12 @@ static int do_magic_pickup(struct ast_channel *channel, const char *extension, c
 
 	ast_str_set(&str, 0, "%s@%s", extension, context);
 
-	ast_debug(2, "About to call Pickup(%s)\n", str->str);
+	ast_debug(2, "About to call Pickup(%s)\n", ast_str_buffer(str));
 
 	/* There is no point in capturing the return value since pickup_exec
 	   doesn't return anything meaningful unless the passed data is an empty
 	   string (which in our case it will not be) */
-	pbx_exec(channel, pickup, str->str);
+	pbx_exec(channel, pickup, ast_str_buffer(str));
 
 	return 0;
 }
@@ -20197,7 +20227,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
 		return 1;
 	}
 
-	if (ast_str_set(&req.data, 0, "%s", readbuf) == AST_DYNSTR_BUILD_FAILED) {
+	if (ast_str_set(&req.data, -1, "%s", readbuf) == AST_DYNSTR_BUILD_FAILED) {
 		return -1;
 	}
 
@@ -20230,11 +20260,11 @@ static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin)
 	if (sip_debug_test_addr(sin))	/* Set the debug flag early on packet level */
 		req->debug = 1;
 	if (sip_cfg.pedanticsipchecking)
-		req->len = lws2sws(req->data->str, req->len);	/* Fix multiline headers */
+		req->len = lws2sws(ast_str_buffer(req->data), req->len);	/* Fix multiline headers */
 	if (req->debug) {
 		ast_verbose("\n<--- SIP read from %s:%s:%d --->\n%s\n<------------->\n", 
 			get_transport(req->socket.type), ast_inet_ntoa(sin->sin_addr), 
-			ntohs(sin->sin_port), req->data->str);
+			ntohs(sin->sin_port), ast_str_buffer(req->data));
 	}
 
 	if(parse_request(req) == -1) { /* Bad packet, can't parse */
@@ -20281,7 +20311,7 @@ static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin)
 	p->recv = *sin;
 
 	if (p->do_history) /* This is a request or response, note what it was for */
-		append_history(p, "Rx", "%s / %s / %s", req->data->str, get_header(req, "CSeq"), req->rlPart2);
+		append_history(p, "Rx", "%s / %s / %s", ast_str_buffer(req->data), get_header(req, "CSeq"), req->rlPart2);
 
 	if (!lockretry) {
 		if (p->owner)
@@ -20526,9 +20556,8 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e
 	} else if (cache_only) {
 		return 0;
 	} else { /* Fall back to manually checking the mailbox */
-		struct ast_str *mailbox_str = ast_str_alloca(512);
-		peer_mailboxes_to_str(&mailbox_str, peer);
-		ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs);
+		struct ast_str *mailbox_str = ast_str_thread_get(&mailbox_buffer, 16);
+		ast_app_inboxcount(peer_mailboxes_to_str(&mailbox_str, peer), &newmsgs, &oldmsgs);
 	}
 	
 	if (peer->mwipvt) {
@@ -21972,7 +22001,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 			ast_copy_string(peer->name, v->value, sizeof(peer->name));
 		else if (realtime && !strcasecmp(v->name, "fullcontact")) {
 			/* Reconstruct field, because realtime separates our value at the ';' */
-			if (fullcontact->used > 0) {
+			if (ast_str_strlen(fullcontact) > 0) {
 				ast_str_append(&fullcontact, 0, ";%s", v->value);
 			} else {
 				ast_str_set(&fullcontact, 0, "%s", v->value);
@@ -22254,8 +22283,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 		peer->socket.type = default_primary_transport;
 	}
 
-	if (fullcontact->used > 0) {
-		ast_string_field_set(peer, fullcontact, fullcontact->str);
+	if (ast_str_strlen(fullcontact) > 0) {
+		ast_string_field_set(peer, fullcontact, ast_str_buffer(fullcontact));
 		peer->rt_fromcontact = TRUE;
 		/* We have a hostname in the fullcontact, but if we don't have an
 		 * address listed on the entry (or if it's 'dynamic'), then we need to
@@ -22264,7 +22293,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 		 * register once again). */
 		/* XXX May need to revisit the final argument; does the realtime DB store whether
 		 * the original contact was over TLS or not? XXX */
-		__set_address_from_contact(fullcontact->str, &peer->addr, 0);
+		__set_address_from_contact(ast_str_buffer(fullcontact), &peer->addr, 0);
 	}
 
 	if (srvlookup && peer->dnsmgr == NULL) {
diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c
index 224a924ced4eeeb6721a35fe48bc00b556b6a5c6..55c1630e790c849a8902c028d21c568634f0b007 100644
--- a/channels/iax2-parser.c
+++ b/channels/iax2-parser.c
@@ -929,7 +929,7 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
 				for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
 					if (strcmp(tmp, var2->name) == 0) {
 						ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
-						var = ast_variable_new(tmp, str->str, var2->file);
+						var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
 						var->next = var2->next;
 						if (prev) {
 							prev->next = var;
diff --git a/configure b/configure
index 1087fe07b539552e4cbbb0c45f859ed333abed53..b3622faa0c04d42b46c21063331a508954232bc7 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 160097 .
+# From configure.ac Revision: 163168 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61 for asterisk 1.6.
 #
diff --git a/funcs/func_curl.c b/funcs/func_curl.c
index 3a936e704d8b0c0332dc0d043c4c574de0380c0f..d4f34b8509ee0d7d0b1baf9d801b44738c6ccecc 100644
--- a/funcs/func_curl.c
+++ b/funcs/func_curl.c
@@ -354,14 +354,11 @@ static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *da
 	register int realsize = size * nmemb;
 	struct ast_str **pstr = (struct ast_str **)data;
 
-	ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, (*pstr)->len, (*pstr)->used);
+	ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, ast_str_size(*pstr), ast_str_strlen(*pstr));
 
-	if (ast_str_make_space(pstr, (((*pstr)->used + realsize + 1) / 512 + 1) * 512 + 230) == 0) {
-		memcpy(&((*pstr)->str[(*pstr)->used]), ptr, realsize);
-		(*pstr)->used += realsize;
-	}
+	ast_str_append_substr(pstr, 0, ptr, realsize);
 
-	ast_debug(3, "Now, len=%zu, used=%zu\n", (*pstr)->len, (*pstr)->used);
+	ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr));
 
 	return realsize;
 }
@@ -467,18 +464,15 @@ static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info,
 		curl_easy_setopt(*curl, CURLOPT_POST, 0);
 	}
 
-	if (str->used) {
-		str->str[str->used] = '\0';
-		if (str->str[str->used - 1] == '\n') {
-			str->str[str->used - 1] = '\0';
-		}
+	if (ast_str_strlen(str)) {
+		ast_str_trim_blanks(str);
 
-		ast_log(LOG_NOTICE, "str='%s'\n", str->str);
+		ast_debug(3, "str='%s'\n", ast_str_buffer(str));
 		if (hashcompat) {
-			char *remainder = str->str;
+			char *remainder = ast_str_buffer(str);
 			char *piece;
-			struct ast_str *fields = ast_str_create(str->used / 2);
-			struct ast_str *values = ast_str_create(str->used / 2);
+			struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2);
+			struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2);
 			int rowcount = 0;
 			while ((piece = strsep(&remainder, "&"))) {
 				char *name = strsep(&piece, "=");
@@ -488,12 +482,12 @@ static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info,
 				ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", piece);
 				rowcount++;
 			}
-			pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", fields->str);
-			ast_copy_string(buf, values->str, len);
+			pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
+			ast_copy_string(buf, ast_str_buffer(values), len);
 			ast_free(fields);
 			ast_free(values);
 		} else {
-			ast_copy_string(buf, str->str, len);
+			ast_copy_string(buf, ast_str_buffer(str), len);
 		}
 		ret = 0;
 	}
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c
index 36f530c6a888c9c2ec0814e99baaf40ac9f7df32..06ffecc5036318a2bf5571663574408f7a3cd82f 100644
--- a/funcs/func_odbc.c
+++ b/funcs/func_odbc.c
@@ -34,6 +34,7 @@
 	<use>iodbc</use>
  ***/
 
+#define USE_ODBC
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -46,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/res_odbc.h"
 #include "asterisk/app.h"
 #include "asterisk/cli.h"
+#include "asterisk/strings.h"
 
 /*** DOCUMENTATION
 	<function name="ODBC_FETCH" language="en_US">
@@ -281,8 +283,8 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
 	/* Additionally set the value as a whole (but push an empty string if value is NULL) */
 	pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
 
-	pbx_substitute_variables_helper(chan, query->sql_write, buf->str, buf->len - 1);
-	pbx_substitute_variables_helper(chan, query->sql_insert, insertbuf->str, insertbuf->len - 1);
+	ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
+	ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
 
 	/* Restore prior values */
 	for (i = 0; i < args.argc; i++) {
@@ -300,7 +302,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
 		if (!ast_strlen_zero(query->writehandle[dsn])) {
 			obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
 			if (obj)
-				stmt = ast_odbc_direct_execute(obj, generic_execute, buf->str);
+				stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf));
 		}
 		if (stmt) {
 			status = "SUCCESS";
@@ -309,14 +311,14 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
 		}
 	}
 
-	if (stmt && rows == 0 && !ast_strlen_zero(insertbuf->str)) {
+	if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) {
 		SQLCloseCursor(stmt);
 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		for (dsn = 0; dsn < 5; dsn++) {
 			if (!ast_strlen_zero(query->writehandle[dsn])) {
 				obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
 				if (obj) {
-					stmt = ast_odbc_direct_execute(obj, generic_execute, insertbuf->str);
+					stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
 				}
 			}
 			if (stmt) {
@@ -409,8 +411,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 		pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
 	}
 
-	ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
-	pbx_substitute_variables_helper(chan, query->sql_read, sql->str, sql->len - 1);
+	ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
 
 	/* Restore prior values */
 	for (x = 0; x < args.argc; x++) {
@@ -435,7 +436,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 		if (!ast_strlen_zero(query->readhandle[dsn])) {
 			obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
 			if (obj) {
-				stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str);
+				stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql));
 			}
 		}
 		if (stmt) {
@@ -444,7 +445,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 	}
 
 	if (!stmt) {
-		ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql->str);
+		ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
 		if (obj) {
 			ast_odbc_release_obj(obj);
 		}
@@ -460,7 +461,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 
 	res = SQLNumResultCols(stmt, &colcount);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql->str);
+		ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
 		SQLCloseCursor(stmt);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 		ast_odbc_release_obj(obj);
@@ -478,13 +479,13 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		int res1 = -1;
 		if (res == SQL_NO_DATA) {
-			ast_verb(4, "Found no rows [%s]\n", sql->str);
+			ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
 			res1 = 0;
 			buf[0] = '\0';
 			ast_copy_string(rowcount, "0", sizeof(rowcount));
 			status = "NODATA";
 		} else {
-			ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str);
+			ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
 			status = "FETCHERROR";
 		}
 		SQLCloseCursor(stmt);
@@ -505,6 +506,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 		for (x = 0; x < colcount; x++) {
 			int i;
 			struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
+			char *ptrcoldata;
 
 			if (y == 0) {
 				char colname[256];
@@ -516,30 +518,15 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 					snprintf(colname, sizeof(colname), "field%d", x);
 				}
 
-				if (coldata->len < maxcol + 1) {
-					ast_str_make_space(&coldata, maxcol + 1);
-				}
+				ast_str_make_space(&coldata, maxcol + 1);
 
-				if (colnames->used) {
+				if (ast_str_strlen(colnames)) {
 					ast_str_append(&colnames, 0, ",");
 				}
-				ast_str_make_space(&colnames, strlen(colname) * 2 + 1 + colnames->used);
-
-				/* Copy data, encoding '\' and ',' for the argument parser */
-				for (i = 0; i < sizeof(colname); i++) {
-					if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) {
-						colnames->str[colnames->used++] = '\\';
-					}
-					colnames->str[colnames->used++] = colname[i];
-
-					if (colname[i] == '\0') {
-						colnames->used--;
-						break;
-					}
-				}
+				ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
 
 				if (resultset) {
-					void *tmp = ast_realloc(resultset, sizeof(*resultset) + colnames->used + 1);
+					void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
 					if (!tmp) {
 						ast_log(LOG_ERROR, "No space for a new resultset?\n");
 						ast_free(resultset);
@@ -555,12 +542,12 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 						return -1;
 					}
 					resultset = tmp;
-					strcpy((char *)resultset + sizeof(*resultset), colnames->str);
+					strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
 				}
 			}
 
 			buflen = strlen(buf);
-			res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator);
+			res = ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
 			if (indicator == SQL_NULL_DATA) {
 				ast_debug(3, "Got NULL data\n");
 				ast_str_reset(coldata);
@@ -568,39 +555,42 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 			}
 
 			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql->str);
+				ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
 				y = -1;
 				buf[0] = '\0';
 				goto end_acf_read;
 			}
 
-			ast_debug(2, "Got coldata of '%s'\n", coldata->str);
-			coldata->used = strlen(coldata->str);
+			ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
+
+			if (buflen) {
+				buf[buflen++] = ',';
+			}
 
 			/* Copy data, encoding '\' and ',' for the argument parser */
-			for (i = 0; i < coldata->used; i++) {
-				if (escapecommas && (coldata->str[i] == '\\' || coldata->str[i] == ',')) {
+			ptrcoldata = ast_str_buffer(coldata);
+			for (i = 0; i < ast_str_strlen(coldata); i++) {
+				if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
 					buf[buflen++] = '\\';
 				}
-				buf[buflen++] = coldata->str[i];
+				buf[buflen++] = ptrcoldata[i];
 
-				if (buflen >= len - 2)
+				if (buflen >= len - 2) {
 					break;
+				}
 
-				if (coldata->str[i] == '\0')
+				if (ptrcoldata[i] == '\0') {
 					break;
+				}
 			}
 
-			buf[buflen++] = ',';
 			buf[buflen] = '\0';
 			ast_debug(2, "buf is now set to '%s'\n", buf);
 		}
-		/* Trim trailing comma */
-		buf[buflen - 1] = '\0';
 		ast_debug(2, "buf is now set to '%s'\n", buf);
 
 		if (resultset) {
-			row = ast_calloc(1, sizeof(*row) + buflen);
+			row = ast_calloc(1, sizeof(*row) + buflen + 1);
 			if (!row) {
 				ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
 				status = "MEMERROR";
@@ -612,8 +602,10 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
 			/* Get next row */
 			res = SQLFetch(stmt);
 			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				if (res != SQL_NO_DATA)
-					ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str);
+				if (res != SQL_NO_DATA) {
+					ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
+				}
+				/* Number of rows in the resultset */
 				y++;
 				break;
 			}
@@ -624,7 +616,7 @@ end_acf_read:
 	snprintf(rowcount, sizeof(rowcount), "%d", y);
 	pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
 	pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
-	pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames->str);
+	pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
 	if (resultset) {
 		int uid;
 		struct ast_datastore *odbc_store;
@@ -1042,8 +1034,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
 	}
 
-	/*!\note This does not set sql->used, so don't try to use that value. */
-	pbx_substitute_variables_helper(chan, query->sql_read, sql->str, sql->len - 1);
+	ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
 	ast_channel_free(chan);
 
 	if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
@@ -1068,7 +1059,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 			}
 
 			ast_debug(1, "Got obj\n");
-			if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str))) {
+			if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
 				ast_odbc_release_obj(obj);
 				continue;
 			}
@@ -1077,7 +1068,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 
 			res = SQLNumResultCols(stmt, &colcount);
 			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", sql->str);
+				ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
 				SQLCloseCursor(stmt);
 				SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 				ast_odbc_release_obj(obj);
@@ -1091,10 +1082,10 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 				SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 				ast_odbc_release_obj(obj);
 				if (res == SQL_NO_DATA) {
-					ast_cli(a->fd, "Returned %d rows.  Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], sql->str);
+					ast_cli(a->fd, "Returned %d rows.  Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql));
 					break;
 				} else {
-					ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, sql->str);
+					ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
 				}
 				AST_RWLIST_UNLOCK(&queries);
 				return CLI_SUCCESS;
@@ -1106,18 +1097,14 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 						snprintf(colname, sizeof(colname), "field%d", x);
 					}
 
-					if (coldata->len < maxcol + 1) {
-						ast_str_make_space(&coldata, maxcol + 1);
-					}
-
-					res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator);
+					res = ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
 					if (indicator == SQL_NULL_DATA) {
 						ast_str_set(&coldata, 0, "(nil)");
 						res = SQL_SUCCESS;
 					}
 
 					if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-						ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, sql->str);
+						ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
 						SQLCloseCursor(stmt);
 						SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 						ast_odbc_release_obj(obj);
@@ -1125,7 +1112,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 						return CLI_SUCCESS;
 					}
 
-					ast_cli(a->fd, "%-20.20s  %s\n", colname, coldata->str);
+					ast_cli(a->fd, "%-20.20s  %s\n", colname, ast_str_buffer(coldata));
 				}
 				/* Get next row */
 				res = SQLFetch(stmt);
@@ -1144,10 +1131,10 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		ast_odbc_release_obj(obj);
 
 		if (!executed) {
-			ast_cli(a->fd, "Failed to execute query. [%s]\n", sql->str);
+			ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
 		}
 	} else { /* No execution, just print out the resulting SQL */
-		ast_cli(a->fd, "%s\n", sql->str);
+		ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
 	}
 	AST_RWLIST_UNLOCK(&queries);
 	return CLI_SUCCESS;
@@ -1250,8 +1237,8 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
 	/* Additionally set the value as a whole (but push an empty string if value is NULL) */
 	pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
-	pbx_substitute_variables_helper(chan, query->sql_write, sql->str, sql->len - 1);
-	ast_debug(1, "SQL is %s\n", sql->str);
+	ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
+	ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
 	ast_channel_free(chan);
 
 	if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
@@ -1268,7 +1255,7 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 			if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) {
 				continue;
 			}
-			if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str))) {
+			if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
 				ast_odbc_release_obj(obj);
 				continue;
 			}
@@ -1286,7 +1273,7 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 			ast_cli(a->fd, "Failed to execute query.\n");
 		}
 	} else { /* No execution, just print out the resulting SQL */
-		ast_cli(a->fd, "%s\n", sql->str);
+		ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
 	}
 	AST_RWLIST_UNLOCK(&queries);
 	return CLI_SUCCESS;
diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c
index 17e3a2d2b5008e27d32605709946579289ad3c59..0658645110c5959b9ae258b4e667cbb149c06640 100644
--- a/funcs/func_realtime.c
+++ b/funcs/func_realtime.c
@@ -141,24 +141,6 @@ AST_THREADSTORAGE(buf1);
 AST_THREADSTORAGE(buf2);
 AST_THREADSTORAGE(buf3);
 
-static char *hash_escape(struct ast_str **str, const char *value)
-{
-	int len;
-	ast_str_reset(*str);
-
-	if ((*str)->len < (len = strlen(value) * 2 + 1)) {
-		ast_str_make_space(str, len);
-	}
-	for (; *value; value++) {
-		if (*value == ',' || *value == '\\') {
-			(*str)->str[(*str)->used++] = '\\';
-		}
-		(*str)->str[(*str)->used++] = *value;
-	}
-	(*str)->str[(*str)->used] = '\0';
-	return (*str)->str;
-}
-
 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) 
 {
 	struct ast_variable *var, *head;
@@ -206,7 +188,7 @@ static int function_realtime_read(struct ast_channel *chan, const char *cmd, cha
 	out = ast_str_alloca(resultslen);
 	for (var = head; var; var = var->next)
 		ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
-	ast_copy_string(buf, out->str, len);
+	ast_copy_string(buf, ast_str_buffer(out), len);
 
 	if (chan)
 		ast_autoservice_stop(chan);
@@ -303,16 +285,16 @@ static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *d
 			}
 		} else if (which == rthash) {
 			ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value);
-			ast_str_append(&fields, 0, "%s%s", first ? "" : ",", hash_escape(&escapebuf, var->name));
-			ast_str_append(&values, 0, "%s%s", first ? "" : ",", hash_escape(&escapebuf, var->value));
+			ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX));
+			ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX));
 			first = 0;
 		}
 	}
 	ast_variables_destroy(head);
 
 	if (which == rthash) {
-		pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", fields->str);
-		ast_copy_string(buf, values->str, len);
+		pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
+		ast_copy_string(buf, ast_str_buffer(values), len);
 	}
 
 	if (chan) {
@@ -418,7 +400,7 @@ static int function_realtime_readdestroy(struct ast_channel *chan, const char *c
 	for (var = head; var; var = var->next) {
 		ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
 	}
-	ast_copy_string(buf, out->str, len);
+	ast_copy_string(buf, ast_str_buffer(out), len);
 
 	ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
 
diff --git a/funcs/func_strings.c b/funcs/func_strings.c
index da7525170c8312a1cdd4232a7ad82f42be90551e..fa43752a424b68abd7891597c68e754ed04a613f 100644
--- a/funcs/func_strings.c
+++ b/funcs/func_strings.c
@@ -321,7 +321,7 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
 	);
 	const char *orig_list, *ptr;
 	const char *begin, *cur, *next;
-	int dlen, flen;
+	int dlen, flen, first = 1;
 	struct ast_str *result = ast_str_thread_get(&result_buf, 16);
 	char *delim;
 
@@ -385,15 +385,12 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
 			begin += flen + dlen;
 		} else {
 			/* Copy field to output */
-			if (result->used) {
+			if (!first) {
 				ast_str_append(&result, 0, "%s", delim);
 			}
 
-			/* Have to do it this way, since we're not null-terminated. */
-			strncpy(result->str + result->used, begin, cur - begin);
-			result->used += cur - begin;
-			result->str[result->used] = '\0';
-
+			ast_str_append_substr(&result, 0, begin, cur - begin + 1);
+			first = 0;
 			begin = cur + dlen;
 		}
 	} while (*cur != '\0');
@@ -401,7 +398,7 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
 		ast_channel_unlock(chan);
 	}
 
-	ast_copy_string(buf, result->str, len);
+	ast_copy_string(buf, ast_str_buffer(result), len);
 
 	return 0;
 }
diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index 851ad9fa650dc9e465dc4428c8e7757e6291b2f3..79af2313e1aac2921200e1875089bc68b0396c81 100644
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -23,12 +23,17 @@
 #ifndef _ASTERISK_APP_H
 #define _ASTERISK_APP_H
 
+#include "asterisk/strings.h"
+#include "asterisk/threadstorage.h"
+
 struct ast_flags64;
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
+AST_THREADSTORAGE_EXTERNAL(global_app_buf);
+
 /* IVR stuff */
 
 /*! \brief Callback function for IVR
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 7ece623791ee63771d6f29c3f4e6a9020f4d5a12..312c2546e983bd9729c397473d5d5ab0fd451e93 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -282,7 +282,7 @@ void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chan);
  * Changes the value of the last executed app
  * Returns nothing
  */
-void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data);
+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data);
 
 /*! 
  * \brief Convert a string to a detail record AMA flag 
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index 3348bb8d75bdcb1f58fdc146a6328546194b1e6c..2bb95930f67b9cf0483dcac84a9fa467757a5d85 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -114,11 +114,11 @@ struct ast_switch {
 };
 
 struct ast_timing {
-	int hastime;				/*!< If time construct exists */
-	unsigned int monthmask;			/*!< Mask for month */
-	unsigned int daymask;			/*!< Mask for date */
-	unsigned int dowmask;			/*!< Mask for day of week (mon-sun) */
-	unsigned int minmask[24];		/*!< Mask for minute */
+	int hastime;                    /*!< If time construct exists */
+	unsigned int monthmask;         /*!< Mask for month */
+	unsigned int daymask;           /*!< Mask for date */
+	unsigned int dowmask;           /*!< Mask for day of week (sun-sat) */
+	unsigned int minmask[48];       /*!< Mask for minute */
 };
 
 int ast_build_timing(struct ast_timing *i, const char *info);
@@ -866,6 +866,8 @@ int pbx_builtin_raise_exception(struct ast_channel *chan, void *data);
 
 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
+void ast_str_substitute_variables(struct ast_str **buf, size_t maxlen, struct ast_channel *chan, const char *templ);
 
 int ast_extension_patmatch(const char *pattern, const char *data);
 
diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h
index 43d5bfc411f3b319bb11ea63aa6085117647a8d7..84782a3acd8b58dec6b9440402e65513f12b6403 100644
--- a/include/asterisk/strings.h
+++ b/include/asterisk/strings.h
@@ -23,14 +23,17 @@
 #ifndef _ASTERISK_STRINGS_H
 #define _ASTERISK_STRINGS_H
 
+#define DEBUG_OPAQUE
+
 #include <ctype.h>
 
-#include "asterisk/inline_api.h"
 #include "asterisk/utils.h"
 #include "asterisk/threadstorage.h"
 
 /* You may see casts in this header that may seem useless but they ensure this file is C++ clean */
 
+#define AS_OR(a,b)	ast_str_strlen(a) ? ast_str_buffer(a) : (b)
+
 #ifdef AST_DEVMODE
 #define ast_strlen_zero(foo)	_ast_strlen_zero(foo, __FILE__, __PRETTY_FUNCTION__, __LINE__)
 static force_inline int _ast_strlen_zero(const char *s, const char *file, const char *function, int line)
@@ -202,7 +205,6 @@ void ast_copy_string(char *dst, const char *src, size_t size),
 }
 )
 
-
 /*!
   \brief Build a string in a buffer, designed to be called repeatedly
   
@@ -338,13 +340,23 @@ int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default
  * struct ast_threadstorage pointer.
  */
 struct ast_str {
+#ifdef DEBUG_OPAQUE
+	size_t len2;
+	size_t used2;
+	struct ast_threadstorage *ts2;
+#else
 	size_t len;	/*!< The current maximum length of the string */
 	size_t used;	/*!< Amount of space used */
 	struct ast_threadstorage *ts;	/*!< What kind of storage is this ? */
+#endif
 #define DS_MALLOC	((struct ast_threadstorage *)1)
 #define DS_ALLOCA	((struct ast_threadstorage *)2)
 #define DS_STATIC	((struct ast_threadstorage *)3)	/* not supported yet */
+#ifdef DEBUG_OPAQUE
+	char str2[0];
+#else
 	char str[0];	/*!< The string buffer */
+#endif
 };
 
 /*!
@@ -366,10 +378,16 @@ struct ast_str * attribute_malloc ast_str_create(size_t init_len),
 	buf = (struct ast_str *)ast_calloc(1, sizeof(*buf) + init_len);
 	if (buf == NULL)
 		return NULL;
-	
+
+#ifdef DEBUG_OPAQUE
+	buf->len2 = init_len;
+	buf->used2 = 0;
+	buf->ts2 = DS_MALLOC;
+#else
 	buf->len = init_len;
 	buf->used = 0;
 	buf->ts = DS_MALLOC;
+#endif
 
 	return buf;
 }
@@ -382,9 +400,15 @@ AST_INLINE_API(
 void ast_str_reset(struct ast_str *buf),
 {
 	if (buf) {
+#ifdef DEBUG_OPAQUE
+		buf->used2 = 0;
+		if (buf->len2)
+			buf->str2[0] = '\0';
+#else
 		buf->used = 0;
 		if (buf->len)
 			buf->str[0] = '\0';
+#endif
 	}
 }
 )
@@ -398,12 +422,83 @@ void ast_str_trim_blanks(struct ast_str *buf),
 	if (!buf) {
 		return;
 	}
+#ifdef DEBUG_OPAQUE
+	while (buf->used2 && buf->str2[buf->used2 - 1] < 33) {
+		buf->str2[--(buf->used2)] = '\0';
+	}
+#else
 	while (buf->used && buf->str[buf->used - 1] < 33) {
 		buf->str[--(buf->used)] = '\0';
 	}
+#endif
+}
+)
+
+/*!\brief Returns the current length of the string stored within buf.
+ * \param A pointer to the ast_str string.
+ */
+AST_INLINE_API(
+size_t ast_str_strlen(struct ast_str *buf),
+{
+#ifdef DEBUG_OPAQUE
+	return buf->used2;
+#else
+	return buf->used;
+#endif
+}
+)
+
+/*!\brief Returns the current maximum length (without reallocation) of the current buffer.
+ * \param A pointer to the ast_str string.
+ */
+AST_INLINE_API(
+size_t ast_str_size(struct ast_str *buf),
+{
+#ifdef DEBUG_OPAQUE
+	return buf->len2;
+#else
+	return buf->len;
+#endif
 }
 )
 
+/*!\brief Returns the string buffer within the ast_str buf.
+ * \param A pointer to the ast_str string.
+ */
+AST_INLINE_API(
+attribute_pure char *ast_str_buffer(struct ast_str *buf),
+{
+#ifdef DEBUG_OPAQUE
+	return buf->str2;
+#else
+	return buf->str;
+#endif
+}
+)
+
+AST_INLINE_API(
+char *ast_str_truncate(struct ast_str *buf, size_t len),
+{
+#ifdef DEBUG_OPAQUE
+	if (len < 0) {
+		buf->used2 += len;
+	} else {
+		buf->used2 = len;
+	}
+	buf->str2[buf->used2] = '\0';
+	return buf->str2;
+#else
+	if (len < 0) {
+		buf->used += len;
+	} else {
+		buf->used = len;
+	}
+	buf->str[buf->used] = '\0';
+	return buf->str;
+#endif
+}
+)
+	
 /*
  * AST_INLINE_API() is a macro that takes a block of code as an argument.
  * Using preprocessor #directives in the argument is not supported by all
@@ -427,6 +522,23 @@ int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file,
 {
 	struct ast_str *old_buf = *buf;
 
+#ifdef DEBUG_OPAQUE
+	if (new_len <= (*buf)->len2) 
+		return 0;	/* success */
+	if ((*buf)->ts2 == DS_ALLOCA || (*buf)->ts2 == DS_STATIC)
+		return -1;	/* cannot extend */
+	*buf = (struct ast_str *)__ast_realloc(*buf, new_len + sizeof(struct ast_str), file, lineno, function);
+	if (*buf == NULL) {
+		*buf = old_buf;
+		return -1;
+	}
+	if ((*buf)->ts2 != DS_MALLOC) {
+		pthread_setspecific((*buf)->ts2->key, *buf);
+		_DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
+	}
+
+	(*buf)->len2 = new_len;
+#else
 	if (new_len <= (*buf)->len) 
 		return 0;	/* success */
 	if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC)
@@ -442,6 +554,7 @@ int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file,
 	}
 
 	(*buf)->len = new_len;
+#endif
 	return 0;
 }
 )
@@ -452,6 +565,23 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len),
 {
 	struct ast_str *old_buf = *buf;
 
+#ifdef DEBUG_OPAQUE
+	if (new_len <= (*buf)->len2) 
+		return 0;	/* success */
+	if ((*buf)->ts2 == DS_ALLOCA || (*buf)->ts2 == DS_STATIC)
+		return -1;	/* cannot extend */
+	*buf = (struct ast_str *)ast_realloc(*buf, new_len + sizeof(struct ast_str));
+	if (*buf == NULL) {
+		*buf = old_buf;
+		return -1;
+	}
+	if ((*buf)->ts2 != DS_MALLOC) {
+		pthread_setspecific((*buf)->ts2->key, *buf);
+		_DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
+	}
+
+	(*buf)->len2 = new_len;
+#else
 	if (new_len <= (*buf)->len) 
 		return 0;	/* success */
 	if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC)
@@ -467,11 +597,24 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len),
 	}
 
 	(*buf)->len = new_len;
+#endif
 	return 0;
 }
 )
 #endif
 
+#ifdef DEBUG_OPAQUE
+#define ast_str_alloca(init_len)			\
+	({						\
+		struct ast_str *__ast_str_buf;			\
+		__ast_str_buf = alloca(sizeof(*__ast_str_buf) + init_len);	\
+		__ast_str_buf->len2 = init_len;			\
+		__ast_str_buf->used2 = 0;				\
+		__ast_str_buf->ts2 = DS_ALLOCA;			\
+		__ast_str_buf->str2[0] = '\0';			\
+		(__ast_str_buf);					\
+	})
+#else
 #define ast_str_alloca(init_len)			\
 	({						\
 		struct ast_str *__ast_str_buf;			\
@@ -482,6 +625,7 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len),
 		__ast_str_buf->str[0] = '\0';			\
 		(__ast_str_buf);					\
 	})
+#endif
 
 /*!
  * \brief Retrieve a thread locally stored dynamic string
@@ -524,12 +668,20 @@ struct ast_str *ast_str_thread_get(struct ast_threadstorage *ts,
 	buf = (struct ast_str *)ast_threadstorage_get(ts, sizeof(*buf) + init_len);
 	if (buf == NULL)
 		return NULL;
-	
+
+#ifdef DEBUG_OPAQUE
+	if (!buf->len2) {
+		buf->len2 = init_len;
+		buf->used2 = 0;
+		buf->ts2 = ts;
+	}
+#else
 	if (!buf->len) {
 		buf->len = init_len;
 		buf->used = 0;
 		buf->ts = ts;
 	}
+#endif
 
 	return buf;
 }
@@ -544,12 +696,20 @@ struct ast_str *__ast_str_thread_get(struct ast_threadstorage *ts,
 	buf = (struct ast_str *)__ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line);
 	if (buf == NULL)
 		return NULL;
-	
+
+#ifdef DEBUG_OPAQUE
+	if (!buf->len2) {
+		buf->len2 = init_len;
+		buf->used2 = 0;
+		buf->ts2 = ts;
+	}
+#else
 	if (!buf->len) {
 		buf->len = init_len;
 		buf->used = 0;
 		buf->ts = ts;
 	}
+#endif
 
 	return buf;
 }
@@ -599,6 +759,8 @@ enum {
  */
 int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, size_t max_len,
 							   int append, const char *fmt, va_list ap);
+char *__ast_str_helper2(struct ast_str **buf, size_t max_len,
+	const char *src, size_t maxsrc, int append, int escapecommas);
 
 /*!
  * \brief Set a dynamic string from a va_list
@@ -655,6 +817,78 @@ AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struc
 }
 )
 
+/*!\brief Set a dynamic string to a non-NULL terminated substring. */
+AST_INLINE_API(char *ast_str_set_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
+{
+	return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 0);
+}
+)
+
+/*!\brief Append a non-NULL terminated substring to the end of a dynamic string. */
+AST_INLINE_API(char *ast_str_append_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
+{
+	return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 0);
+}
+)
+
+/*!\brief Set a dynamic string to a non-NULL terminated substring, with escaping of commas. */
+AST_INLINE_API(char *ast_str_set_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
+{
+	return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 1);
+}
+)
+
+/*!\brief Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas. */
+AST_INLINE_API(char *ast_str_append_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
+{
+	return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 1);
+}
+)
+
+/*!\brief Wrapper for SQLGetData to use with dynamic strings
+ * \param buf Address of the pointer to the ast_str structure.
+ * \param maxlen The maximum size of the resulting string, or 0 for no limit.
+ * \param StatementHandle The statement handle from which to retrieve data.
+ * \param ColumnNumber Column number (1-based offset) for which to retrieve data.
+ * \param TargetType The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR)
+ * \param StrLen_or_Ind A pointer to a length indicator, specifying the total length of data.
+ */
+#ifdef USE_ODBC
+#include <sql.h>
+#include <sqlext.h>
+#include <sqltypes.h>
+
+AST_INLINE_API(SQLRETURN ast_str_SQLGetData(struct ast_str **buf, size_t maxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind),
+{
+	SQLRETURN res;
+	if (maxlen == 0) {
+#ifdef DEBUG_OPAQUE
+		if (SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str2, 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
+			ast_str_make_space(buf, *StrLen_or_Ind + 1);
+		}
+		maxlen = (*buf)->len2;
+	} else if (maxlen > 0) {
+		ast_str_make_space(buf, maxlen);
+	}
+	res = SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str2, maxlen, StrLen_or_Ind);
+	(*buf)->used2 = *StrLen_or_Ind;
+#else
+		if (SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str, 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
+			ast_str_make_space(buf, *StrLen_or_Ind + 1);
+		}
+		maxlen = (*buf)->len;
+	} else if (maxlen > 0) {
+		ast_str_make_space(buf, maxlen);
+	}
+	res = SQLGetData(StatementHandle, ColumnNumber, TargetType, (*buf)->str, maxlen, StrLen_or_Ind);
+	(*buf)->used = *StrLen_or_Ind;
+#endif
+	return res;
+}
+)
+#endif /* defined(USE_ODBC) */
+
+
 /*!
  * \brief Set a dynamic string using variable arguments
  *
diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 6fb6d4b63d4e8355939b7e2e66d5dabf72d57ee2..611709cbe708f75981747ed4ea443d16719b9728 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -157,6 +157,6 @@ void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc);
 int ast_ssl_setup(struct ast_tls_config *cfg);
 
 HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *ser, void *buf, size_t count);
-HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, void *buf, size_t count);
+HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, const void *buf, size_t count);
 
 #endif /* _ASTERISK_TCPTLS_H */
diff --git a/include/asterisk/threadstorage.h b/include/asterisk/threadstorage.h
index cf6d47e324594ff90cd46e8a852ae8adf8c467c0..ab586974f4812ded001f7dc2f89cf4bb9b022f6c 100644
--- a/include/asterisk/threadstorage.h
+++ b/include/asterisk/threadstorage.h
@@ -85,7 +85,11 @@ void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len
  * \endcode
  */
 #define AST_THREADSTORAGE(name) \
-	AST_THREADSTORAGE_CUSTOM(name, NULL, ast_free_ptr) 
+	AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr, static) 
+#define AST_THREADSTORAGE_PUBLIC(name) \
+	AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr,) 
+#define AST_THREADSTORAGE_EXTERNAL(name) \
+	extern struct ast_threadstorage name
 
 /*!
  * \brief Define a thread storage variable, with custom initialization and cleanup
@@ -103,10 +107,12 @@ void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len
  * AST_THREADSTORAGE_CUSTOM(my_buf, my_init, my_cleanup);
  * \endcode
  */
+#define AST_THREADSTORAGE_CUSTOM(a,b,c)	AST_THREADSTORAGE_CUSTOM_SCOPE(a,b,c,static)
+
 #if !defined(DEBUG_THREADLOCALS)
-#define AST_THREADSTORAGE_CUSTOM(name, c_init, c_cleanup)	\
+#define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope)	\
 static void __init_##name(void);				\
-static struct ast_threadstorage name = {			\
+scope struct ast_threadstorage name = {			\
 	.once = THREADSTORAGE_ONCE_INIT,			\
 	.key_init = __init_##name,				\
 	.custom_init = c_init,					\
@@ -116,9 +122,9 @@ static void __init_##name(void)					\
 	pthread_key_create(&(name).key, c_cleanup);		\
 }
 #else /* defined(DEBUG_THREADLOCALS) */
-#define AST_THREADSTORAGE_CUSTOM(name, c_init, c_cleanup)	\
+#define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope)	\
 static void __init_##name(void);				\
-static struct ast_threadstorage name = {			\
+scope struct ast_threadstorage name = {			\
 	.once = THREADSTORAGE_ONCE_INIT,			\
 	.key_init = __init_##name,				\
 	.custom_init = c_init,					\
diff --git a/main/Makefile b/main/Makefile
index 56b964d16142f221d0c3fc6e8213af24b17ca496..54882f2456d6d6014e4d53afed7899f998304244 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -28,7 +28,8 @@ OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
 	strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
 	astobj2.o hashtab.o global_datastores.o version.o \
-	features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o
+	features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o \
+	strings.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static
diff --git a/main/app.c b/main/app.c
index aecbffaf2270ab16bada8e947a825435eb5086b4..d3d3b37841165206344c397bbfca3e21c0f0cf9b 100644
--- a/main/app.c
+++ b/main/app.c
@@ -44,6 +44,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/lock.h"
 #include "asterisk/indications.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/threadstorage.h"
+
+AST_THREADSTORAGE_PUBLIC(global_app_buf);
+
 
 #define MAX_OTHER_FORMATS 10
 
diff --git a/main/asterisk.c b/main/asterisk.c
index c002a454281d7aa3cdd865c9e63503d649f53be8..8fe421dde2368282ed84307af6dafc2535a43cd5 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -2034,7 +2034,7 @@ static char *cli_prompt(EditLine *editline)
 	if (prompt == NULL) {
 		prompt = ast_str_create(100);
 	} else if (!cli_prompt_changes) {
-		return prompt->str;
+		return ast_str_buffer(prompt);
 	} else {
 		ast_str_reset(prompt);
 	}
@@ -2132,11 +2132,7 @@ static char *cli_prompt(EditLine *editline)
 				}
 				t++;
 			} else {
-				if (prompt->used + 5 > prompt->len) {
-					ast_str_make_space(&prompt, prompt->len + 5);
-				}
-				prompt->str[prompt->used++] = *t++;
-				prompt->str[prompt->used] = '\0';
+				ast_str_append(&prompt, 0, "%c", *t);
 			}
 		}
 		if (color_used) {
@@ -2149,7 +2145,7 @@ static char *cli_prompt(EditLine *editline)
 		ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
 	}
 
-	return(prompt->str);	
+	return ast_str_buffer(prompt);	
 }
 
 static char **ast_el_strtoarr(char *buf)
diff --git a/main/cdr.c b/main/cdr.c
index f48ddf38d198dd9d7315d7a6988a325cbbf240cb..991b01a25ba77ef872f25e47258f6156a177a864 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -367,8 +367,7 @@ int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char
 	char workspace[256];
 	int total = 0, x = 0, i;
 
-	(*buf)->used = 0;
-	(*buf)->str[0] = '\0';
+	ast_str_reset(*buf);
 
 	for (; cdr; cdr = recur ? cdr->next : NULL) {
 		if (++x > 1)
@@ -776,7 +775,7 @@ void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chann)
 	}
 }
 
-void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
 {
 
 	for (; cdr; cdr = cdr->next) {
diff --git a/main/cli.c b/main/cli.c
index 063eeaae2e7ef425b445ca59bd6c304a693fee49..57f936b09dafa4047affaf570f4f156575140a9b 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -110,8 +110,9 @@ void ast_cli(int fd, const char *fmt, ...)
 	res = ast_str_set_va(&buf, 0, fmt, ap);
 	va_end(ap);
 
-	if (res != AST_DYNSTR_BUILD_FAILED)
-		ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
+	if (res != AST_DYNSTR_BUILD_FAILED) {
+		ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
+	}
 }
 
 unsigned int ast_debug_get_by_file(const char *file) 
@@ -637,9 +638,9 @@ static void print_uptimestr(int fd, struct timeval timeval, const char *prefix,
 		ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
 	}
 	x = timeval.tv_sec;
-	if (x > 0 || out->used == 0)	/* if there is nothing, print 0 seconds */
+	if (x > 0 || ast_str_strlen(out) == 0)	/* if there is nothing, print 0 seconds */
 		ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
-	ast_cli(fd, "%s: %s\n", prefix, out->str);
+	ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
 }
 
 static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
@@ -1258,7 +1259,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 {
 	struct ast_channel *c=NULL;
 	struct timeval now;
-	struct ast_str *out = ast_str_alloca(2048);
+	struct ast_str *out = ast_str_thread_get(&global_app_buf, 16);
 	char cdrtime[256];
 	char nf[256], wf[256], rf[256];
 	long elapsed_seconds=0;
@@ -1347,14 +1348,14 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
 	
 	if (pbx_builtin_serialize_variables(c, &out))
-		ast_cli(a->fd,"      Variables:\n%s\n", out->str);
+		ast_cli(a->fd,"      Variables:\n%s\n", ast_str_buffer(out));
 	if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1))
-		ast_cli(a->fd,"  CDR Variables:\n%s\n", out->str);
+		ast_cli(a->fd,"  CDR Variables:\n%s\n", ast_str_buffer(out));
 #ifdef CHANNEL_TRACE
 	trace_enabled = ast_channel_trace_is_enabled(c);
 	ast_cli(a->fd, "  Context Trace: %s\n", trace_enabled ? "Enabled" : "Disabled");
 	if (trace_enabled && ast_channel_trace_serialize(c, &out))
-		ast_cli(a->fd, "          Trace:\n%s\n", out->str);
+		ast_cli(a->fd, "          Trace:\n%s\n", ast_str_buffer(out));
 #endif
 	ast_channel_unlock(c);
 	return CLI_SUCCESS;
diff --git a/main/config.c b/main/config.c
index 5fad1c51b716ee0e6ab5b1d263116a27cfaeff8b..33a8ecb7b7119e8b2bba83ed6686f998aa8fe29b 100644
--- a/main/config.c
+++ b/main/config.c
@@ -106,19 +106,23 @@ static void  CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
 
 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)  
 { 
-	if (cb)
-		cb->used = 0;
-	if (llb)
-		llb->used = 0;
+	if (cb) {
+		ast_str_reset(cb);
+	}
+	if (llb) {
+		ast_str_reset(llb);
+	}
 }
 
-static struct ast_comment *ALLOC_COMMENT(const struct ast_str *buffer)
+static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
 { 
 	struct ast_comment *x = NULL;
-	if (buffer && buffer->used)
-		x = ast_calloc(1, sizeof(*x) + buffer->used + 1);
-	if (x)
-		strcpy(x->cmt, buffer->str);
+	if (!buffer || !ast_str_strlen(buffer)) {
+		return NULL;
+	}
+	if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
+		strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
+	}
 	return x;
 }
 
@@ -132,20 +136,21 @@ struct inclfile {
 
 static int hash_string(const void *obj, const int flags)
 {
-	char *str = ((struct inclfile*)obj)->fname;
+	char *str = ((struct inclfile *) obj)->fname;
 	int total;
 
-	for (total=0; *str; str++) {
+	for (total = 0; *str; str++) {
 		unsigned int tmp = total;
 		total <<= 1; /* multiply by 2 */
 		total += tmp; /* multiply by 3 */
 		total <<= 2; /* multiply by 12 */
 		total += tmp; /* multiply by 13 */
 
-		total += ((unsigned int)(*str));
+		total += ((unsigned int) (*str));
 	}
-	if (total < 0)
+	if (total < 0) {
 		total = -total;
+	}
 	return total;
 }
 
@@ -1125,7 +1130,8 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
 
 			ast_str_set(str, 0, "%s", replace->value);
 			ast_str_append(str, 0, "%s", c);
-			ast_variable_update(*cat, replace->name, ast_strip((*str)->str), replace->value, object);
+			ast_str_trim_blanks(*str);
+			ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
 		} else if (c) {
 			*c = 0;
 			c++;
@@ -1320,9 +1326,9 @@ static struct ast_config *config_text_file_load(const char *database, const char
 		while (!feof(f)) {
 			lineno++;
 			if (fgets(buf, sizeof(buf), f)) {
-				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && lline_buffer->used) {
-					CB_ADD(&comment_buffer, lline_buffer->str);       /* add the current lline buffer to the comment buffer */
-					lline_buffer->used = 0;        /* erase the lline buffer */
+				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
 				}
 				
 				new_buf = buf;
@@ -1331,14 +1337,14 @@ static struct ast_config *config_text_file_load(const char *database, const char
 				else
 					process_buf = buf;
 				
-				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
+				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
 					/* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
 					CB_ADD(&comment_buffer, "\n");       /* add a newline to the comment buffer */
 					continue; /* go get a new line, then */
 				}
 				
 				while ((comment_p = strchr(new_buf, COMMENT_META))) {
-					if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
+					if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
 						/* Escaped semicolons aren't comments. */
 						new_buf = comment_p + 1;
 					} else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
@@ -1403,30 +1409,30 @@ static struct ast_config *config_text_file_load(const char *database, const char
 		}
 		/* end of file-- anything in a comment buffer? */
 		if (last_cat) {
-			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
-				if (lline_buffer && lline_buffer->used) {
-					CB_ADD(&comment_buffer, lline_buffer->str);       /* add the current lline buffer to the comment buffer */
-					lline_buffer->used = 0;        /* erase the lline buffer */
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				if (lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
 				}
 				last_cat->trailing = ALLOC_COMMENT(comment_buffer);
 			}
 		} else if (last_var) {
-			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
-				if (lline_buffer && lline_buffer->used) {
-					CB_ADD(&comment_buffer, lline_buffer->str);       /* add the current lline buffer to the comment buffer */
-					lline_buffer->used = 0;        /* erase the lline buffer */
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				if (lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
 				}
 				last_var->trailing = ALLOC_COMMENT(comment_buffer);
 			}
 		} else {
-			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used) {
-				ast_debug(1, "Nothing to attach comments to, discarded: %s\n", comment_buffer->str);
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
 			}
 		}
 		if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
 			CB_RESET(comment_buffer, lline_buffer);
 
-		fclose(f);		
+		fclose(f);
 	} while (0);
 	if (comment) {
 		ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
diff --git a/main/http.c b/main/http.c
index 5c3aa789509a89a75a176ff5df14480db8d4f5e5..237ad66431cb458da07dd831d7142620f94f1c65 100644
--- a/main/http.c
+++ b/main/http.c
@@ -755,14 +755,14 @@ static void *httpd_helper_thread(void *data)
 			* append a random variable to your GET request.  Ex: 'something.html?r=109987734'
 			*/
 		if (!contentlength) {	/* opaque body ? just dump it hoping it is properly formatted */
-			fprintf(ser->f, "%s", out->str);
+			fprintf(ser->f, "%s", ast_str_buffer(out));
 		} else {
-			char *tmp = strstr(out->str, "\r\n\r\n");
+			char *tmp = strstr(ast_str_buffer(out), "\r\n\r\n");
 
 			if (tmp) {
 				fprintf(ser->f, "Content-length: %d\r\n", contentlength);
 				/* first write the header, then the body */
-				if (fwrite(out->str, 1, (tmp + 4 - out->str), ser->f) != tmp + 4 - out->str) {
+				if (fwrite(ast_str_buffer(out), 1, (tmp + 4 - ast_str_buffer(out)), ser->f) != tmp + 4 - ast_str_buffer(out)) {
 					ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
 				}
 				if (fwrite(tmp + 4, 1, contentlength, ser->f) != contentlength ) {
diff --git a/main/logger.c b/main/logger.c
index b42a21b19c8eb7c0b9b1814b05c3a76042b7e557..8a577ed38dc880f4bde2e3dd38e0204dc664a65f 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -1106,8 +1106,8 @@ void ast_log(int level, const char *file, int line, const char *function, const
 			result = ast_str_set_va(&buf, BUFSIZ, fmt, ap); /* XXX BUFSIZ ? */
 			va_end(ap);
 			if (result != AST_DYNSTR_BUILD_FAILED) {
-				term_filter_escapes(buf->str);
-				fputs(buf->str, stdout);
+				term_filter_escapes(ast_str_buffer(buf));
+				fputs(ast_str_buffer(buf), stdout);
 			}
 		}
 		return;
@@ -1140,7 +1140,7 @@ void ast_log(int level, const char *file, int line, const char *function, const
 		return;
 
 	/* Copy string over */
-	strcpy(logmsg->str, buf->str);
+	strcpy(logmsg->str, ast_str_buffer(buf));
 
 	/* Set type to be normal */
 	logmsg->type = LOGMSG_NORMAL;
@@ -1269,7 +1269,7 @@ void __ast_verbose_ap(const char *file, int line, const char *func, const char *
 	if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
 		return;
 
-	strcpy(logmsg->str, buf->str);
+	strcpy(logmsg->str, ast_str_buffer(buf));
 
 	ast_log(__LOG_VERBOSE, file, line, func, "%s", logmsg->str + 1);
 
diff --git a/main/manager.c b/main/manager.c
index 47a7f42b9ab642a7cc397c9ed02754f65b2e3091..f3cda9e8279050bbaedd69774f21d07cc25177e6 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -347,7 +347,7 @@ static char *authority_to_str(int authority, struct ast_str **res)
 	int i;
 	char *sep = "";
 
-	(*res)->used = 0;
+	ast_str_reset(*res);
 	for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
 		if (authority & perms[i].num) {
 			ast_str_append(res, 0, "%s%s", sep, perms[i].label);
@@ -355,10 +355,10 @@ static char *authority_to_str(int authority, struct ast_str **res)
 		}
 	}
 
-	if ((*res)->used == 0)	/* replace empty string with something sensible */
+	if (ast_str_strlen(*res) == 0)	/* replace empty string with something sensible */
 		ast_str_append(res, 0, "<none>");
 
-	return (*res)->str;
+	return ast_str_buffer(*res);
 }
 
 /*! Tells you if smallstr exists inside bigstr
@@ -950,10 +950,11 @@ void astman_append(struct mansession *s, const char *fmt, ...)
 	ast_str_set_va(&buf, 0, fmt, ap);
 	va_end(ap);
 
-	if (s->f != NULL)
-		send_string(s, buf->str);
-	else
+	if (s->f != NULL) {
+		send_string(s, ast_str_buffer(buf));
+	} else {
 		ast_verbose("fd == -1 in astman_append, should not happen\n");
+	}
 }
 
 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
@@ -1525,11 +1526,12 @@ static int action_createconfig(struct mansession *s, const struct message *m)
 	ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
 	ast_str_append(&filepath, 0, "%s", fn);
 
-	if ((fd = open(filepath->str, O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
+	if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
 		close(fd);
 		astman_send_ack(s, m, "New configuration file created successfully");
-	} else 
+	} else {
 		astman_send_error(s, m, strerror(errno));
+	}
 
 	return 0;
 }
@@ -1939,7 +1941,7 @@ static int action_status(struct mansession *s, const struct message *m)
 			c->accountcode,
 			c->_state,
 			ast_state2str(c->_state), c->context,
-			c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, str->str, idText);
+			c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
 		} else {
 			astman_append(s,
 			"Event: Status\r\n"
@@ -1958,7 +1960,7 @@ static int action_status(struct mansession *s, const struct message *m)
 			S_OR(c->cid.cid_num, "<unknown>"),
 			S_OR(c->cid.cid_name, "<unknown>"),
 			c->accountcode,
-			ast_state2str(c->_state), bridge, c->uniqueid, str->str, idText);
+			ast_state2str(c->_state), bridge, c->uniqueid, ast_str_buffer(str), idText);
 		}
 		ast_channel_unlock(c);
 		if (!all)
@@ -3268,7 +3270,7 @@ int __manager_event(int category, const char *event,
 
 	ast_str_append(&buf, 0, "\r\n");
 
-	append_event(buf->str, category);
+	append_event(ast_str_buffer(buf), category);
 
 	/* Wake up any sleeping sessions */
 	AST_LIST_LOCK(&sessions);
@@ -3289,7 +3291,7 @@ int __manager_event(int category, const char *event,
 
 	AST_RWLIST_RDLOCK(&manager_hooks);
 	AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
-		hook->helper(category, event, buf->str);
+		hook->helper(category, event, ast_str_buffer(buf));
 	}
 	AST_RWLIST_UNLOCK(&manager_hooks);
 
diff --git a/main/pbx.c b/main/pbx.c
index 37ab4db7e91b06a88b48a43ce63e2b127ddbe37a..8fb1393ea49c07e27c1c4cc9649ab690656cb834 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1504,7 +1504,7 @@ void log_match_char_tree(struct match_char *node, char *prefix)
 	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
 
 	if (node->next_char)
-		log_match_char_tree(node->next_char, my_prefix->str);
+		log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
 
 	if (node->alt_char)
 		log_match_char_tree(node->alt_char, prefix);
@@ -1533,7 +1533,7 @@ static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
 	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
 
 	if (node->next_char)
-		cli_match_char_tree(node->next_char, my_prefix->str, fd);
+		cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
 
 	if (node->alt_char)
 		cli_match_char_tree(node->alt_char, prefix, fd);
@@ -2525,8 +2525,8 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 				break;
 			} else if (eval) {
 				/* Substitute variables now */
-				pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len);
-				datap = tmpdata->str;
+				pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
+				datap = ast_str_buffer(tmpdata);
 			} else {
 				datap = osw;
 			}
@@ -2695,7 +2695,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 				ast_log(LOG_WARNING, "Can't evaluate switch?!");
 				continue;
 			}
-			pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
+			pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
 		}
 
 		/* equivalent of extension_match_core() at the switch level */
@@ -2705,7 +2705,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 			aswf = asw->matchmore;
 		else /* action == E_MATCH */
 			aswf = asw->exists;
-		datap = sw->eval ? tmpdata->str : sw->data;
+		datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
 		if (!aswf)
 			res = 0;
 		else {
@@ -3351,11 +3351,11 @@ int ast_func_write(struct ast_channel *chan, const char *function, const char *v
 	return -1;
 }
 
-static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
 {
 	/* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
 	char *cp4;
-	const char *tmp, *whereweare;
+	const char *tmp, *whereweare, *orig_cp2 = cp2;
 	int length, offset, offset2, isfunction;
 	char *workspace = NULL;
 	char *ltmp = NULL, *var = NULL;
@@ -3435,10 +3435,11 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
 
 			/* Substitute if necessary */
 			if (needsub) {
+				size_t used;
 				if (!ltmp)
 					ltmp = alloca(VAR_BUF_SIZE);
 
-				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
 				vars = ltmp;
 			} else {
 				vars = var;
@@ -3522,10 +3523,11 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
 
 			/* Substitute if necessary */
 			if (needsub) {
+				size_t used;
 				if (!ltmp)
 					ltmp = alloca(VAR_BUF_SIZE);
 
-				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
 				vars = ltmp;
 			} else {
 				vars = var;
@@ -3541,16 +3543,19 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
 			}
 		}
 	}
+	*used = cp2 - orig_cp2;
 }
 
 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
 {
-	pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
+	size_t used;
+	pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count, &used);
 }
 
 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
 {
-	pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
+	size_t used;
+	pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
 }
 
 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
@@ -3725,7 +3730,7 @@ static int ast_extension_state2(struct ast_exten *e)
 
 	ast_str_set(&hint, 0, "%s", ast_get_extension_app(e));
 
-	rest = hint->str;	/* One or more devices separated with a & character */
+	rest = ast_str_buffer(hint);	/* One or more devices separated with a & character */
 
 	while ( (cur = strsep(&rest, "&")) )
 		ast_devstate_aggregate_add(&agg, ast_device_state(cur));
@@ -6089,8 +6094,8 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl
 	}
 
 	pbx_builtin_serialize_variables(chan, &vars);
-	if (vars->str) {
-		ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
+	if (ast_str_strlen(vars)) {
+		ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
 	}
 	ast_channel_unlock(chan);
 	return CLI_SUCCESS;
@@ -6637,15 +6642,20 @@ static int lookup_name(const char *s, char *const names[], int max)
 {
 	int i;
 
-	if (names) {
+	if (names && *s > '9') {
 		for (i = 0; names[i]; i++) {
-			if (!strcasecmp(s, names[i]))
-				return i+1;
+			if (!strcasecmp(s, names[i])) {
+				return i;
+			}
 		}
-	} else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-		return i;
 	}
-	return 0; /* error return */
+
+	/* Allow months and weekdays to be specified as numbers, as well */
+	if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
+		/* What the array offset would have been: "1" would be at offset 0 */
+		return i - 1;
+	}
+	return -1; /* error return */
 }
 
 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
@@ -6653,131 +6663,104 @@ static int lookup_name(const char *s, char *const names[], int max)
  */
 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
 {
-	int s, e; /* start and ending position */
+	int start, end; /* start and ending position */
 	unsigned int mask = 0;
+	char *part;
 
 	/* Check for whole range */
 	if (ast_strlen_zero(src) || !strcmp(src, "*")) {
-		s = 0;
-		e = max - 1;
-	} else {
+		return (1 << max) - 1;
+	}
+
+	while ((part = strsep(&src, "&"))) {
 		/* Get start and ending position */
-		char *c = strchr(src, '-');
-		if (c)
-			*c++ = '\0';
+		char *endpart = strchr(part, '-');
+		if (endpart) {
+			*endpart++ = '\0';
+		}
 		/* Find the start */
-		s = lookup_name(src, names, max);
-		if (!s) {
-			ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
-			return 0;
+		if ((start = lookup_name(part, names, max)) < 0) {
+			ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
+			continue;
 		}
-		s--;
-		if (c) { /* find end of range */
-			e = lookup_name(c, names, max);
-			if (!e) {
-				ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
-				return 0;
+		if (endpart) { /* find end of range */
+			if ((end = lookup_name(endpart, names, max)) < 0) {
+				ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
+				continue;
 			}
-			e--;
-		} else
-			e = s;
-	}
-	/* Fill the mask. Remember that ranges are cyclic */
-	mask = 1 << e;	/* initialize with last element */
-	while (s != e) {
-		if (s >= max) {
-			s = 0;
-			mask |= (1 << s);
 		} else {
-			mask |= (1 << s);
-			s++;
+			end = start;
+		}
+		/* Fill the mask. Remember that ranges are cyclic */
+		mask |= (1 << end);   /* initialize with last element */
+		while (start != end) {
+			if (start >= max) {
+				start = 0;
+			}
+			mask |= (1 << start);
+			start++;
 		}
 	}
 	return mask;
 }
 
-/*! \brief store a bitmask of valid times, one bit each 2 minute */
+/*! \brief store a bitmask of valid times, one bit each 1 minute */
 static void get_timerange(struct ast_timing *i, char *times)
 {
-	char *e;
+	char *endpart, *part;
 	int x;
-	int s1, s2;
-	int e1, e2;
-	/*	int cth, ctm; */
+	int st_h, st_m;
+	int endh, endm;
+	int minute_start, minute_end;
 
 	/* start disabling all times, fill the fields with 0's, as they may contain garbage */
 	memset(i->minmask, 0, sizeof(i->minmask));
 
-	/* 2-minutes per bit, since the mask has only 32 bits :( */
+	/* 1-minute per bit */
 	/* Star is all times */
 	if (ast_strlen_zero(times) || !strcmp(times, "*")) {
-		for (x = 0; x < 24; x++)
+		/* 48, because each hour takes 2 integers; 30 bits each */
+		for (x = 0; x < 48; x++) {
 			i->minmask[x] = 0x3fffffff; /* 30 bits */
+		}
 		return;
 	}
 	/* Otherwise expect a range */
-	e = strchr(times, '-');
-	if (!e) {
-		ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
-		return;
-	}
-	*e++ = '\0';
-	/* XXX why skip non digits ? */
-	while (*e && !isdigit(*e))
-		e++;
-	if (!*e) {
-		ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
-		return;
-	}
-	if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
-		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
-		return;
-	}
-	if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
-		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
-		return;
-	}
-	/* XXX this needs to be optimized */
-#if 1
-	s1 = s1 * 30 + s2/2;
-	if ((s1 < 0) || (s1 >= 24*30)) {
-		ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
-		return;
-	}
-	e1 = e1 * 30 + e2/2;
-	if ((e1 < 0) || (e1 >= 24*30)) {
-		ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
-		return;
-	}
-	/* Go through the time and enable each appropriate bit */
-	for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
-		i->minmask[x/30] |= (1 << (x % 30));
-	}
-	/* Do the last one */
-	i->minmask[x/30] |= (1 << (x % 30));
-#else
-	for (cth = 0; cth < 24; cth++) {
-		/* Initialize masks to blank */
-		i->minmask[cth] = 0;
-		for (ctm = 0; ctm < 30; ctm++) {
-			if (
-			/* First hour with more than one hour */
-			      (((cth == s1) && (ctm >= s2)) &&
-			       ((cth < e1)))
-			/* Only one hour */
-			||    (((cth == s1) && (ctm >= s2)) &&
-			       ((cth == e1) && (ctm <= e2)))
-			/* In between first and last hours (more than 2 hours) */
-			||    ((cth > s1) &&
-			       (cth < e1))
-			/* Last hour with more than one hour */
-			||    ((cth > s1) &&
-			       ((cth == e1) && (ctm <= e2)))
-			)
-				i->minmask[cth] |= (1 << (ctm / 2));
+	while ((part = strsep(&times, "&"))) {
+		if (!(endpart = strchr(part, '-'))) {
+			if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
+				ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
+				continue;
+			}
+			i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
+			continue;
+		}
+		*endpart++ = '\0';
+		/* why skip non digits? Mostly to skip spaces */
+		while (*endpart && !isdigit(*endpart)) {
+			endpart++;
+		}
+		if (!*endpart) {
+			ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
+			continue;
+		}
+		if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
+			ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
+			continue;
+		}
+		if (sscanf(endpart, "%d:%d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
+			ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
+			continue;
 		}
+		minute_start = st_h * 60 + st_m;
+		minute_end = endh * 60 + endm;
+		/* Go through the time and enable each appropriate bit */
+		for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
+			i->minmask[x / 30] |= (1 << (x % 30));
+		}
+		/* Do the last one */
+		i->minmask[x / 30] |= (1 << (x % 30));
 	}
-#endif
 	/* All done */
 	return;
 }
@@ -6865,7 +6848,7 @@ int ast_check_timing(const struct ast_timing *i)
 
 	/* Now the tough part, we calculate if it fits
 	   in the right time based on min/hour */
-	if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
+	if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
 		return 0;
 
 	/* If we got this far, then we're good */
@@ -8662,8 +8645,7 @@ int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **b
 	if (!chan)
 		return 0;
 
-	(*buf)->used = 0;
-	(*buf)->str[0] = '\0';
+	ast_str_reset(*buf);
 
 	ast_channel_lock(chan);
 
diff --git a/main/strings.c b/main/strings.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fd1cac54cbcbcb193554c6f1e9c90990075be92
--- /dev/null
+++ b/main/strings.c
@@ -0,0 +1,219 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Digium, Inc.
+ *
+ * Tilghman Lesher <tlesher@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
+ *
+ * \brief String manipulation API
+ *
+ * \author Tilghman Lesher <tilghman@digium.com>
+ */
+
+/*** MAKEOPTS
+<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
+	<member name="DEBUG_OPAQUE" displayname="Change ast_str internals to detect improper usage">
+		<defaultenabled>yes</defaultenabled>
+	</member>
+</category>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/strings.h"
+#include "asterisk/pbx.h"
+
+/*!
+ * core handler for dynamic strings.
+ * This is not meant to be called directly, but rather through the
+ * various wrapper macros
+ *	ast_str_set(...)
+ *	ast_str_append(...)
+ *	ast_str_set_va(...)
+ *	ast_str_append_va(...)
+ */
+
+int __ast_str_helper(struct ast_str **buf, size_t max_len,
+	int append, const char *fmt, va_list ap)
+{
+	int res, need;
+#ifdef DEBUG_OPAQUE
+	int offset = (append && (*buf)->len2) ? (*buf)->used2 : 0;
+#else
+	int offset = (append && (*buf)->len) ? (*buf)->used : 0;
+#endif
+	va_list aq;
+
+	do {
+		if (max_len < 0) {
+#ifdef DEBUG_OPAQUE
+			max_len = (*buf)->len2;	/* don't exceed the allocated space */
+#else
+			max_len = (*buf)->len;	/* don't exceed the allocated space */
+#endif
+		}
+		/*
+		 * Ask vsnprintf how much space we need. Remember that vsnprintf
+		 * does not count the final '\0' so we must add 1.
+		 */
+		va_copy(aq, ap);
+#ifdef DEBUG_OPAQUE
+		res = vsnprintf((*buf)->str2 + offset, (*buf)->len2 - offset, fmt, aq);
+#else
+		res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, aq);
+#endif
+
+		need = res + offset + 1;
+		/*
+		 * If there is not enough space and we are below the max length,
+		 * reallocate the buffer and return a message telling to retry.
+		 */
+#ifdef DEBUG_OPAQUE
+		if (need > (*buf)->len2 && (max_len == 0 || (*buf)->len2 < max_len) ) {
+#else
+		if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
+#endif
+			if (max_len && max_len < need) {	/* truncate as needed */
+				need = max_len;
+			} else if (max_len == 0) {	/* if unbounded, give more room for next time */
+				need += 16 + need / 4;
+			}
+			if (0) {	/* debugging */
+#ifdef DEBUG_OPAQUE
+				ast_verbose("extend from %d to %d\n", (int)(*buf)->len2, need);
+#else
+				ast_verbose("extend from %d to %d\n", (int)(*buf)->len, need);
+#endif
+			}
+			if (ast_str_make_space(buf, need)) {
+#ifdef DEBUG_OPAQUE
+				ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->len2, need);
+#else
+				ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->len, need);
+#endif
+				return AST_DYNSTR_BUILD_FAILED;
+			}
+#ifdef DEBUG_OPAQUE
+			(*buf)->str2[offset] = '\0';	/* Truncate the partial write. */
+#else
+			(*buf)->str[offset] = '\0';	/* Truncate the partial write. */
+#endif
+
+			/* Restart va_copy before calling vsnprintf() again. */
+			va_end(aq);
+			continue;
+		}
+		break;
+	} while (1);
+	/* update space used, keep in mind the truncation */
+#ifdef DEBUG_OPAQUE
+	(*buf)->used2 = (res + offset > (*buf)->len2) ? (*buf)->len2 : res + offset;
+#else
+	(*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
+#endif
+
+	return res;
+}
+
+void ast_str_substitute_variables(struct ast_str **buf, size_t maxlen, struct ast_channel *chan, const char *template)
+{
+	int first = 1;
+#ifdef DEBUG_OPAQUE
+	do {
+		ast_str_make_space(buf, maxlen ? maxlen :
+			(first ? strlen(template) * 2 : (*buf)->len2 * 2));
+		pbx_substitute_variables_helper_full(chan, NULL, template, (*buf)->str2, (*buf)->len2 - 1, &((*buf)->used2));
+		first = 0;
+	} while (maxlen == 0 && (*buf)->len2 - 5 < (*buf)->used2);
+#else
+	do {
+		ast_str_make_space(buf, maxlen ? maxlen :
+			(first ? strlen(template) * 2 : (*buf)->len * 2));
+		pbx_substitute_variables_helper_full(chan, NULL, template, (*buf)->str, (*buf)->len - 1, &((*buf)->used));
+		first = 0;
+	} while (maxlen == 0 && (*buf)->len - 5 < (*buf)->used);
+#endif
+}
+
+char *__ast_str_helper2(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc, int append, int escapecommas)
+{
+	int dynamic = 0;
+#ifdef DEBUG_OPAQUE
+	char *ptr = append ? &((*buf)->str2[(*buf)->used2]) : (*buf)->str2;
+#else
+	char *ptr = append ? &((*buf)->str[(*buf)->used]) : (*buf)->str;
+#endif
+
+	if (!maxlen) {
+		dynamic = 1;
+#ifdef DEBUG_OPAQUE
+		maxlen = (*buf)->len2;
+#else
+		maxlen = (*buf)->len;
+#endif
+	}
+
+	while (*src && maxsrc && maxlen && (!escapecommas || (maxlen - 1))) {
+		if (escapecommas && (*src == '\\' || *src == ',')) {
+			*ptr++ = '\\';
+			maxlen--;
+#ifdef DEBUG_OPAQUE
+			(*buf)->used2++;
+#else
+			(*buf)->used++;
+#endif
+		}
+		*ptr++ = *src++;
+		maxsrc--;
+		maxlen--;
+#ifdef DEBUG_OPAQUE
+		(*buf)->used2++;
+#else
+		(*buf)->used++;
+#endif
+		if (dynamic && (!maxlen || (escapecommas && !(maxlen - 1)))) {
+#ifdef DEBUG_OPAQUE
+			size_t old = (*buf)->len2;
+			if (ast_str_make_space(buf, (*buf)->len2 * 2)) {
+				/* If the buffer can't be extended, end it. */
+				break;
+			}
+#else
+			size_t old = (*buf)->len;
+			if (ast_str_make_space(buf, (*buf)->len * 2)) {
+				/* If the buffer can't be extended, end it. */
+				break;
+			}
+#endif
+			/* What we extended the buffer by */
+			maxlen = old;
+		}
+	}
+	if (__builtin_expect(!(maxsrc && maxlen), 0)) {
+		ptr--;
+	}
+	*ptr = '\0';
+#ifdef DEBUG_OPAQUE
+	(*buf)->used2--;
+	return (*buf)->str2;
+#else
+	(*buf)->used--;
+	return (*buf)->str;
+#endif
+}
+
diff --git a/main/tcptls.c b/main/tcptls.c
index b93c53baeebb417aa35f08fce7f39f16ca0d81bc..b1c615aea2f491107737512241a2bebd650c8e1e 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -97,7 +97,7 @@ HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *tcptls_session
 	return read(tcptls_session->fd, buf, count);
 }
 
-HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count)
+HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count)
 {
 	if (tcptls_session->fd == -1) {
 		ast_log(LOG_ERROR, "server_write called with an fd of -1\n");
diff --git a/main/translate.c b/main/translate.c
index 35c1968df3b92fc28883c32a8b292551b239ae69..5d4fd0ace61ca98a797c17d547b577acf867dbbe 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -598,7 +598,7 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
 			}
 		}
 		ast_str_append(&out, -1, "\n");
-		ast_cli(a->fd, "%s", out->str);			
+		ast_cli(a->fd, "%s", ast_str_buffer(out));			
 	}
 	AST_RWLIST_UNLOCK(&translators);
 	return CLI_SUCCESS;
diff --git a/main/utils.c b/main/utils.c
index 71a4dcc004496e2977f58c5b3f720bf9be000f02..6651f928149cb8a5497bc194ffd81ff7ce9583e5 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1587,66 +1587,6 @@ int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
 		return -1;
 }
 
-/*!
- * core handler for dynamic strings.
- * This is not meant to be called directly, but rather through the
- * various wrapper macros
- *	ast_str_set(...)
- *	ast_str_append(...)
- *	ast_str_set_va(...)
- *	ast_str_append_va(...)
- */
-
-int __ast_str_helper(struct ast_str **buf, size_t max_len,
-	int append, const char *fmt, va_list ap)
-{
-	int res, need;
-	int offset = (append && (*buf)->len) ? (*buf)->used : 0;
-	va_list aq;
-
-	do {
-		if (max_len < 0) {
-			max_len = (*buf)->len;	/* don't exceed the allocated space */
-		}
-		/*
-		 * Ask vsnprintf how much space we need. Remember that vsnprintf
-		 * does not count the final '\0' so we must add 1.
-		 */
-		va_copy(aq, ap);
-		res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, aq);
-
-		need = res + offset + 1;
-		/*
-		 * If there is not enough space and we are below the max length,
-		 * reallocate the buffer and return a message telling to retry.
-		 */
-		if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
-			if (max_len && max_len < need) {	/* truncate as needed */
-				need = max_len;
-			} else if (max_len == 0) {	/* if unbounded, give more room for next time */
-				need += 16 + need / 4;
-			}
-			if (0) {	/* debugging */
-				ast_verbose("extend from %d to %d\n", (int)(*buf)->len, need);
-			}
-			if (ast_str_make_space(buf, need)) {
-				ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->len, need);
-				return AST_DYNSTR_BUILD_FAILED;
-			}
-			(*buf)->str[offset] = '\0';	/* Truncate the partial write. */
-
-			/* Restart va_copy before calling vsnprintf() again. */
-			va_end(aq);
-			continue;
-		}
-		break;
-	} while (1);
-	/* update space used, keep in mind the truncation */
-	(*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
-
-	return res;
-}
-
 void ast_enable_packet_fragmentation(int sock)
 {
 #if defined(HAVE_IP_MTU_DISCOVER)
diff --git a/main/xmldoc.c b/main/xmldoc.c
index 3185a3a5683366c46569b7a322a9fc735ecd89eb..1cd3a0909478f5012674d2676526ebe52c947d52 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -268,8 +268,7 @@ static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff)
 				backspace = xmldoc_foundspace_backward(text, i, maxdiff);
 				if (backspace) {
 					needtobreak = 1;
-					tmp->used -= backspace;
-					tmp->str[tmp->used] = '\0';
+					ast_str_truncate(tmp, -backspace);
 					i -= backspace + 1;
 					continue;
 				}
@@ -300,7 +299,7 @@ static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff)
 		ast_str_append(&tmp, 0, "%c", text[i]);
 	}
 
-	ret = ast_strdup(tmp->str);
+	ret = ast_strdup(ast_str_buffer(tmp));
 	ast_free(tmp);
 
 	return ret;
@@ -403,7 +402,7 @@ char *ast_xmldoc_printable(const char *bwinput, int withcolors)
 	}
 
 	/* Wrap the text, notice that string wrap will avoid cutting an ESC sequence. */
-	wrapped = xmldoc_string_wrap(colorized->str, xmldoc_text_columns, xmldoc_max_diff);
+	wrapped = xmldoc_string_wrap(ast_str_buffer(colorized), xmldoc_text_columns, xmldoc_max_diff);
 
 	ast_free(colorized);
 
@@ -881,7 +880,7 @@ static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
 
 	ast_str_append(&paramname, 0, "}");
 
-	ret = ast_strdup(paramname->str);
+	ret = ast_strdup(ast_str_buffer(paramname));
 	ast_free(paramname);
 
 	return ret;
@@ -978,7 +977,7 @@ static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *nam
 	}
 
 	/* return a common string. */
-	ret = ast_strdup(syntax->str);
+	ret = ast_strdup(ast_str_buffer(syntax));
 	ast_free(syntax);
 
 	return ret;
@@ -1084,9 +1083,9 @@ static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const
 			if (tmpstr) {
 				if (strcasecmp(ast_xml_node_get_name(tmp), "text")) {
 					ast_str_append(buffer, 0, "<%s>%s</%s>", ast_xml_node_get_name(tmp),
-							tmpstr->str, ast_xml_node_get_name(tmp));
+							ast_str_buffer(tmpstr), ast_xml_node_get_name(tmp));
 				} else {
-					ast_str_append(buffer, 0, "%s", tmpstr->str);
+					ast_str_append(buffer, 0, "%s", ast_str_buffer(tmpstr));
 				}
 				ast_free(tmpstr);
 				ret = 2;
@@ -1245,8 +1244,8 @@ static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, st
 			/* Cleanup text. */
 			xmldoc_string_cleanup(tmptext, &cleanstr, 1);
 			ast_xml_free_text(tmptext);
-			if (cleanstr && cleanstr->used > 0) {
-				ast_str_append(buffer, 0, ":%s", cleanstr->str);
+			if (cleanstr && ast_str_strlen(cleanstr) > 0) {
+				ast_str_append(buffer, 0, ":%s", ast_str_buffer(cleanstr));
 			}
 			ast_free(cleanstr);
 		}
@@ -1381,7 +1380,7 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name)
 		ast_xml_free_text(content);
 	}
 
-	output = ast_strdup(outputstr->str);
+	output = ast_strdup(ast_str_buffer(outputstr));
 	ast_free(outputstr);
 
 	return output;
@@ -1631,13 +1630,13 @@ char *ast_xmldoc_build_arguments(const char *type, const char *name)
 		xmldoc_parse_parameter(node, "", &ret);
 	}
 
-	if (ret->used > 0) {
+	if (ast_str_strlen(ret) > 0) {
 		/* remove last '\n' */
-		if (ret->str[ret->used - 1] == '\n') {
-			ret->str[ret->used - 1] = '\0';
-			ret->used--;
+		char *buf = ast_str_buffer(ret);
+		if (buf[ast_str_strlen(ret) - 1] == '\n') {
+			ast_str_truncate(ret, -1);
 		}
-		retstr = ast_strdup(ret->str);
+		retstr = ast_strdup(ast_str_buffer(ret));
 	}
 	ast_free(ret);
 
@@ -1677,9 +1676,9 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
 		}
 		/* remove last '\n' */
 		/* XXX Don't modify ast_str internals manually */
-		if (ret->str[ret->used-1] == '\n') {
-			ret->str[ret->used-1] = '\0';
-			ret->used--;
+		tmpstr = ast_str_buffer(ret);
+		if (tmpstr[ast_str_strlen(ret) - 1] == '\n') {
+			ast_str_truncate(ret, -1);
 		}
 	}
 	return ret;
@@ -1720,8 +1719,8 @@ static char *xmldoc_build_field(const char *type, const char *name, const char *
 	}
 
 	formatted = xmldoc_get_formatted(node, raw, raw);
-	if (formatted->used > 0) {
-		ret = ast_strdup(formatted->str);
+	if (ast_str_strlen(formatted) > 0) {
+		ret = ast_strdup(ast_str_buffer(formatted));
 	}
 	ast_free(formatted);
 
diff --git a/res/res_agi.c b/res/res_agi.c
index cfdd48e39d2058e9ee3f7a65358141e94b4b2d06..bda3e79a4bf5ac21f92e0495463103caa66dfc3a 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -377,13 +377,13 @@ int ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...)
 
 	if (agidebug) {
 		if (chan) {
-			ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
+			ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
 		} else {
-			ast_verbose("AGI Tx >> %s", buf->str);
+			ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
 		}
 	}
 
-	return ast_carefulwrite(fd, buf->str, buf->used, 100);
+	return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
 }
 
 /* linked list of AGI commands ready to be executed by Async AGI */
diff --git a/res/res_clialiases.c b/res/res_clialiases.c
index 1ea302401107bbdc81c9bd5ba65a6bd9d5cc7b02..156212f6b3cd6e8048010e9412ae53959007c1c5 100644
--- a/res/res_clialiases.c
+++ b/res/res_clialiases.c
@@ -101,7 +101,7 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_
 		if (!ast_strlen_zero(a->word)) {
 			struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1);
 			ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line);
-			generator = ast_cli_generator(real_cmd->str, a->word, a->n);
+			generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n);
 		} else {
 			generator = ast_cli_generator(alias->real_cmd, a->word, a->n);
 		}
@@ -121,7 +121,7 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_
 			ast_str_append(&real_cmd, 0, " %s", a->argv[i - 1]);
 		}
 
-		ast_cli_command(a->fd, real_cmd->str);
+		ast_cli_command(a->fd, ast_str_buffer(real_cmd));
 	} else {
 		ast_cli_command(a->fd, alias->real_cmd);
 	}
diff --git a/res/res_config_curl.c b/res/res_config_curl.c
index b159c768d52dcd39c6d1d4214e7cadc8a0211599..1d259c845d20e344f3a64d301838fc6bb07c4f54 100644
--- a/res/res_config_curl.c
+++ b/res/res_config_curl.c
@@ -88,7 +88,7 @@ static struct ast_variable *realtime_curl(const char *url, const char *unused, v
 	va_end(ap);
 
 	ast_str_append(&query, 0, ")}");
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	/* Remove any trailing newline characters */
 	if ((stringp = strchr(buffer, '\r')) || (stringp = strchr(buffer, '\n')))
@@ -170,7 +170,7 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
 	ast_str_append(&query, 0, ")}");
 
 	/* Do the CURL query */
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	if (!(cfg = ast_config_new()))
 		goto exit_multi;
@@ -258,7 +258,7 @@ static int update_curl(const char *url, const char *unused, const char *keyfield
 	va_end(ap);
 
 	ast_str_append(&query, 0, ")}");
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	/* Line oriented output */
 	stringp = buffer;
@@ -321,7 +321,7 @@ static int update2_curl(const char *url, const char *unused, va_list ap)
 
 	ast_str_append(&query, 0, ")}");
 	/* TODO: Make proxies work */
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	/* Line oriented output */
 	stringp = buffer;
@@ -385,7 +385,7 @@ static int store_curl(const char *url, const char *unused, va_list ap)
 	va_end(ap);
 
 	ast_str_append(&query, 0, ")}");
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	stringp = buffer;
 	while (*stringp <= ' ')
@@ -452,7 +452,7 @@ static int destroy_curl(const char *url, const char *unused, const char *keyfiel
 	va_end(ap);
 
 	ast_str_append(&query, 0, ")}");
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	/* Line oriented output */
 	stringp = buffer;
@@ -511,7 +511,7 @@ static int require_curl(const char *url, const char *unused, va_list ap)
 	va_end(ap);
 
 	ast_str_append(&query, 0, ")}");
-	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, sizeof(buffer));
 	return atoi(buffer);
 }
 
@@ -544,7 +544,7 @@ static struct ast_config *config_curl(const char *url, const char *unused, const
 	ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
 
 	/* Do the CURL query */
-	pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
+	pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
 
 	/* Line oriented output */
 	stringp = buffer;
diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c
index 8fbfef897cb8f26fd5e93d7990cc7d48fc084f09..7ff9015f2c19e060aa39ec14697e0dec839e5736 100644
--- a/res/res_config_ldap.c
+++ b/res/res_config_ldap.c
@@ -789,7 +789,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 	do {
 		/* freeing ldap_result further down */
 		result = ldap_search_ext_s(ldapConn, clean_basedn,
-				  LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
+				  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
 				  &ldap_result_msg);
 		if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
 			ast_log(LOG_DEBUG, "Failed to query database. Try %d/10\n",
@@ -808,7 +808,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 
 	if (result != LDAP_SUCCESS) {
 		ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
-		ast_log(LOG_WARNING, "Query: %s\n", filter->str);
+		ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
 		ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
 	} else {
 		/* this is where we create the variables from the search result 
@@ -818,7 +818,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 			vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
 		} else {
 			ast_debug(1, "Could not find any entry matching %s in base dn %s.\n",
-				filter->str, clean_basedn);
+				ast_str_buffer(filter), clean_basedn);
 		}
 
 		ldap_msgfree(ldap_result_msg);
@@ -1246,7 +1246,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 	do {
 		/* freeing ldap_result further down */
 		result = ldap_search_ext_s(ldapConn, clean_basedn,
-				  LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
+				  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
 				  &ldap_result_msg);
 		if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
 			ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
@@ -1266,7 +1266,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 
 	if (result != LDAP_SUCCESS) {
 		ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
-		ast_log(LOG_WARNING, "Query: %s\n", filter->str);
+		ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
 		ast_log(LOG_WARNING, "Query Failed because: %s\n",
 			ldap_err2string(result));
 
@@ -1433,7 +1433,7 @@ static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
 	do {
 		/* freeing ldap_result further down */
 		result = ldap_search_ext_s(ldapConn, clean_basedn,
-				  LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
+				  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
 				  &ldap_result_msg);
 		if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
 			ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
@@ -1453,7 +1453,7 @@ static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
 
 	if (result != LDAP_SUCCESS) {
 		ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
-		ast_log(LOG_WARNING, "Query: %s\n", filter->str);
+		ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
 		ast_log(LOG_WARNING, "Query Failed because: %s\n",
 			ldap_err2string(result));
 
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index a815a9de9605174ca5b10f7c35d29269d2c5028c..8de431475dea371c80964692b20ac97d09b1cb71 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -555,9 +555,9 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
 	/* Done with the table metadata */
 	ast_odbc_release_table(tableptr);
 
-	res = SQLPrepare(stmt, (unsigned char *)sql->str, SQL_NTS);
+	res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql->str);
+		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		return NULL;
 	}
@@ -606,7 +606,7 @@ static int update2_odbc(const char *database, const char *table, va_list ap)
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		/* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
 		sql = ast_str_thread_get(&sql_buf, 16);
-		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", sql->str);
+		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
 		return -1;
 	}
 
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index a22f03a6d92ca2bb58b09d2573c89b465868fdfe..877901243c26b515f5bdd10feaee50f92d671caa 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -94,10 +94,10 @@ static struct ast_cli_entry cli_realtime[] = {
 #define ESCAPE_STRING(buffer, stringname) \
 	do { \
 		int len; \
-		if ((len = strlen(stringname)) > (buffer->len - 1) / 2) { \
+		if ((len = strlen(stringname)) > (ast_str_size(buffer) - 1) / 2) { \
 			ast_str_make_space(&buffer, len * 2 + 1); \
 		} \
-		PQescapeStringConn(pgsqlConn, buffer->str, stringname, len, &pgresult); \
+		PQescapeStringConn(pgsqlConn, ast_str_buffer(buffer), stringname, len, &pgresult); \
 	} while (0)
 
 static void destroy_table(struct tables *table)
@@ -137,7 +137,7 @@ static struct tables *find_table(const char *tablename)
 
 	/* Not found, scan the table */
 	ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", tablename);
-	result = PQexec(pgsqlConn, sql->str);
+	result = PQexec(pgsqlConn, ast_str_buffer(sql));
 	ast_debug(1, "Query of table structure complete.  Now retrieving results.\n");
 	if (PQresultStatus(result) != PGRES_TUPLES_OK) {
 		pgerror = PQresultErrorMessage(result);
@@ -260,7 +260,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, escapebuf->str);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (!strchr(newparam, ' '))
@@ -275,7 +275,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, escapebuf->str);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
 	}
 	va_end(ap);
 
@@ -286,10 +286,10 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 		return NULL;
 	}
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return NULL;
@@ -300,7 +300,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -308,7 +308,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 		}
 	}
 
-	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
 
 	if ((num_rows = PQntuples(result)) > 0) {
 		int i = 0;
@@ -410,7 +410,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, escapebuf->str);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (!strchr(newparam, ' '))
@@ -425,7 +425,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, escapebuf->str);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
 	}
 
 	if (initfield) {
@@ -441,10 +441,10 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		return NULL;
 	}
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return NULL;
@@ -455,7 +455,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -463,7 +463,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		}
 	}
 
-	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
 
 	if ((num_rows = PQntuples(result)) > 0) {
 		int numFields = PQnfields(result);
@@ -570,7 +570,7 @@ static int update_pgsql(const char *database, const char *tablename, const char
 		release_table(table);
 		return -1;
 	}
-	ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, escapebuf->str);
+	ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
 
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
@@ -588,7 +588,7 @@ static int update_pgsql(const char *database, const char *tablename, const char
 			return -1;
 		}
 
-		ast_str_append(&sql, 0, ", %s = '%s'", newparam, escapebuf->str);
+		ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
 	}
 	va_end(ap);
 	release_table(table);
@@ -600,9 +600,9 @@ static int update_pgsql(const char *database, const char *tablename, const char
 		return -1;
 	}
 
-	ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, escapebuf->str);
+	ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));
 
-	ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
 	ast_mutex_lock(&pgsql_lock);
@@ -611,10 +611,10 @@ static int update_pgsql(const char *database, const char *tablename, const char
 		return -1;
 	}
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		ast_free(sql);
@@ -626,7 +626,7 @@ static int update_pgsql(const char *database, const char *tablename, const char
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -696,7 +696,7 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
 			ast_free(sql);
 			return -1;
 		}
-		ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, escapebuf->str);
+		ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
 		first = 0;
 	}
 
@@ -730,13 +730,13 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
 			return -1;
 		}
 
-		ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, escapebuf->str);
+		ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
 	}
 	release_table(table);
 
-	ast_str_append(&sql, 0, " %s", where->str);
+	ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
 
-	ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
 
 	/* We now have our complete statement; connect to the server and execute it. */
 	ast_mutex_lock(&pgsql_lock);
@@ -745,10 +745,10 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
 		return -1;
 	}
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return -1;
@@ -759,7 +759,7 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -823,25 +823,25 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 	ESCAPE_STRING(buf, newparam);
-	ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, buf->str);
+	ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
 	ESCAPE_STRING(buf, newval);
-	ast_str_set(&sql2, 0, ") VALUES ('%s'", buf->str);
+	ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		ESCAPE_STRING(buf, newparam);
-		ast_str_append(&sql1, 0, ", %s", buf->str);
+		ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
 		ESCAPE_STRING(buf, newval);
-		ast_str_append(&sql2, 0, ", '%s'", buf->str);
+		ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
 	}
 	va_end(ap);
-	ast_str_append(&sql1, 0, "%s)", sql2->str);
+	ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
 
-	ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", sql1->str);
+	ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));
 
-	if (!(result = PQexec(pgsqlConn, sql1->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return -1;
@@ -852,7 +852,7 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -918,21 +918,21 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
 
 	ESCAPE_STRING(buf1, keyfield);
 	ESCAPE_STRING(buf2, lookup);
-	ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, buf1->str, buf2->str);
+	ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		ESCAPE_STRING(buf1, newparam);
 		ESCAPE_STRING(buf2, newval);
-		ast_str_append(&sql, 0, " AND %s = '%s'", buf1->str, buf2->str);
+		ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
 	}
 	va_end(ap);
 
-	ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return -1;
@@ -943,7 +943,7 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -992,7 +992,7 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
 			"WHERE filename='%s' and commented=0"
 			"ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);
 
-	ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", sql->str);
+	ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
 	ast_mutex_lock(&pgsql_lock);
@@ -1001,10 +1001,10 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
 		return NULL;
 	}
 
-	if (!(result = PQexec(pgsqlConn, sql->str))) {
+	if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database);
-		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
 		ast_mutex_unlock(&pgsql_lock);
 		return NULL;
@@ -1015,7 +1015,7 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
 			&& result_status != PGRES_NONFATAL_ERROR) {
 			ast_log(LOG_WARNING,
 					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
+			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
 			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
 						PQresultErrorMessage(result), PQresStatus(result_status));
 			ast_mutex_unlock(&pgsql_lock);
@@ -1163,16 +1163,16 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap
 				ast_mutex_lock(&pgsql_lock);
 				if (!pgsql_reconnect(database)) {
 					ast_mutex_unlock(&pgsql_lock);
-					ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
+					ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
 					ast_free(sql);
 					continue;
 				}
 
 				ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
-				result = PQexec(pgsqlConn, sql->str);
+				result = PQexec(pgsqlConn, ast_str_buffer(sql));
 				ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
 				if (PQresultStatus(result) != PGRES_COMMAND_OK) {
-					ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
+					ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
 				}
 				PQclear(result);
 				ast_mutex_unlock(&pgsql_lock);
@@ -1399,9 +1399,9 @@ static int pgsql_reconnect(const char *database)
 		if (!ast_strlen_zero(dbpass))
 			ast_str_append(&connInfo, 0, " password=%s", dbpass);
 
-		ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
-		pgsqlConn = PQconnectdb(connInfo->str);
-		ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
+		ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
+		pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
+		ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
 		ast_free(connInfo);
 		connInfo = NULL;
 
diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c
index 756de0cd568269d4c238008639fcc5c43298c088..114aa803bd1c2dc68352bdb1a0f3f524d4f693a4 100644
--- a/res/res_config_sqlite.c
+++ b/res/res_config_sqlite.c
@@ -789,6 +789,7 @@ static int cdr_handler(struct ast_cdr *cdr)
 	struct sqlite_cache_tables *tbl = find_table(cdr_table);
 	struct sqlite_cache_columns *col;
 	struct ast_str *sql1 = ast_str_create(160), *sql2 = ast_str_create(16);
+	int first = 1;
 
 	if (!tbl) {
 		ast_log(LOG_WARNING, "No such table: %s\n", cdr_table);
@@ -805,33 +806,31 @@ static int cdr_handler(struct ast_cdr *cdr)
 				continue;
 			}
 			if (sscanf(tmp, "%d", &scannum) == 1) {
-				ast_str_append(&sql1, 0, "%s,", col->name);
-				ast_str_append(&sql2, 0, "%d,", scannum);
+				ast_str_append(&sql1, 0, "%s%s", first ? "" : ",", col->name);
+				ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", scannum);
 			}
 		} else {
 			ast_cdr_getvar(cdr, col->name, &tmp, workspace, sizeof(workspace), 0, 0);
 			if (!tmp) {
 				continue;
 			}
-			ast_str_append(&sql1, 0, "%s,", col->name);
+			ast_str_append(&sql1, 0, "%s%s", first ? "" : ",", col->name);
 			tmp = sqlite_mprintf("%Q", tmp);
-			ast_str_append(&sql2, 0, "%s,", tmp);
+			ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", tmp);
 			sqlite_freemem(tmp);
 		}
 	}
 	release_table(tbl);
 
-	sql1->str[--sql1->used] = '\0';
-	sql2->str[--sql2->used] = '\0';
-	ast_str_append(&sql1, 0, "%s)", sql2->str);
+	ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
 	ast_free(sql2);
 
-	ast_debug(1, "SQL query: %s\n", sql1->str);
+	ast_debug(1, "SQL query: %s\n", ast_str_buffer(sql1));
 
 	ast_mutex_lock(&mutex);
 
 	RES_CONFIG_SQLITE_BEGIN
-		error = sqlite_exec(db, sql1->str, NULL, NULL, &errormsg);
+		error = sqlite_exec(db, ast_str_buffer(sql1), NULL, NULL, &errormsg);
 	RES_CONFIG_SQLITE_END(error)
 
 	ast_mutex_unlock(&mutex);
@@ -1413,13 +1412,13 @@ static int realtime_update2_handler(const char *database, const char *table,
 		first = 0;
 	}
 
-	ast_str_append(&sql, 0, " %s", where->str);
-	ast_debug(1, "SQL query: %s\n", sql->str);
+	ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
+	ast_debug(1, "SQL query: %s\n", ast_str_buffer(sql));
 
 	ast_mutex_lock(&mutex);
 
 	RES_CONFIG_SQLITE_BEGIN
-		error = sqlite_exec(db, sql->str, NULL, NULL, &errormsg);
+		error = sqlite_exec(db, ast_str_buffer(sql), NULL, NULL, &errormsg);
 	RES_CONFIG_SQLITE_END(error)
 
 	if (!error) {
diff --git a/res/res_http_post.c b/res/res_http_post.c
index 4a31567203d51a6082c3218e15f7d21eb47a8ba3..26daf7ad8887447016f515591863638f85ce230f 100644
--- a/res/res_http_post.c
+++ b/res/res_http_post.c
@@ -390,7 +390,7 @@ static struct ast_str *http_post_callback(struct ast_tcptls_session_instance *se
 				      NULL, "The was an error parsing the request.");
 	}
 
-	if (!(message_count = process_message(message, post_dir->str))) {
+	if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) {
 		ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
 		g_object_unref(message);
 		return ast_http_error((*status = 400),
diff --git a/utils/Makefile b/utils/Makefile
index 3a280dcad1d4b6e7285b5bf345c4320d5b6d6e42..a9067802c5086f3b4256741ccafc1dc982a4e043 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -77,7 +77,7 @@ clean:
 	rm -f *.s *.i
 	rm -f md5.c strcompat.c ast_expr2.c ast_expr2f.c pbx_ael.c pval.c hashtab.c
 	rm -f aelparse.c aelbison.c conf2ael
-	rm -f utils.c threadstorage.c sha1.c astobj2.c hashtest2 hashtest refcounter
+	rm -f utils.c strings.c threadstorage.c sha1.c astobj2.c hashtest2 hashtest refcounter
 
 md5.c: $(ASTTOPDIR)/main/md5.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
@@ -149,6 +149,11 @@ utils.c: $(ASTTOPDIR)/main/utils.c
 	$(CMD_PREFIX) cp "$<" "$@"
 utils.o: ASTCFLAGS+=-DSTANDALONE
 
+strings.c: $(ASTTOPDIR)/main/strings.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+strings.o: ASTCFLAGS+=-DSTANDALONE
+
 sha1.c: $(ASTTOPDIR)/main/sha1.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
 	$(CMD_PREFIX) cp "$<" "$@"
@@ -160,12 +165,12 @@ threadstorage.c: $(ASTTOPDIR)/main/threadstorage.c
 threadstorage.o: ASTCFLAGS+=-DSTANDALONE
 
 hashtest2.o: ASTCFLAGS+=-O0 -DSTANDALONE
-hashtest2: hashtest2.o md5.o utils.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
+hashtest2: hashtest2.o md5.o utils.o strings.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
 
-hashtest: hashtest.o md5.o hashtab.o utils.o sha1.o strcompat.o threadstorage.o clicompat.o
+hashtest: hashtest.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
 hashtest.o: ASTCFLAGS+=-O0 -DSTANDALONE
 
-refcounter: refcounter.o md5.o hashtab.o utils.o sha1.o strcompat.o threadstorage.o clicompat.o
+refcounter: refcounter.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
 refcounter.o: ASTCFLAGS+=-O0 -DSTANDALONE
 
 extconf.o: extconf.c
diff --git a/utils/check_expr.c b/utils/check_expr.c
index ab1cee19a707da9fd185b9dcc6956c649c3fe846..1d3fcfd0e0478c6b849764971f4781831cb2ee5b 100644
--- a/utils/check_expr.c
+++ b/utils/check_expr.c
@@ -27,57 +27,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define AST_API_MODULE 1
 #include "asterisk/lock.h"
 
-#include "asterisk/strings.h"
-
-/* I included this from utils.c, so as not to have everything in that .c
-   file included */
-/*!
- * core handler for dynamic strings.
- * This is not meant to be called directly, but rather through the
- * various wrapper macros
- *	ast_str_set(...)
- *	ast_str_append(...)
- *	ast_str_set_va(...)
- *	ast_str_append_va(...)
- */
-int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, size_t max_len,
-	int append, const char *fmt, va_list ap)
-{
-	int res, need;
-	int offset = (append && (*buf)->len) ? (*buf)->used : 0;
-
-	if (max_len < 0)
-		max_len = (*buf)->len;	/* don't exceed the allocated space */
-	/*
-	 * Ask vsnprintf how much space we need. Remember that vsnprintf
-	 * does not count the final '\0' so we must add 1.
-	 */
-	res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
-
-	need = res + offset + 1;
-	/*
-	 * If there is not enough space and we are below the max length,
-	 * reallocate the buffer and return a message telling to retry.
-	 */
-	if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
-		if (max_len && max_len < need)	/* truncate as needed */
-			need = max_len;
-		else if (max_len == 0)	/* if unbounded, give more room for next time */
-			need += 16 + need/4;
-		if (ast_str_make_space(buf, need)) {
-			return AST_DYNSTR_BUILD_FAILED;
-		}
-		(*buf)->str[offset] = '\0';	/* Truncate the partial write. */
-
-		/* va_end() and va_start() must be done before calling
-		 * vsnprintf() again. */
-		return AST_DYNSTR_BUILD_RETRY;
-	}
-	/* update space used, keep in mind the truncation */
-	(*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
-
-	return res;
-}
 #ifndef DEBUG_THREADS
 enum ast_lock_type {
 	        AST_MUTEX,
diff --git a/utils/hashtest.c b/utils/hashtest.c
index 7ff7a55b2d2ce5280c5575123971b3c10dc6adc0..16c5e1d9b18caa2d023b02525c8c56faa06ed9bb 100644
--- a/utils/hashtest.c
+++ b/utils/hashtest.c
@@ -50,6 +50,11 @@ int64_t ast_mark(int prof_id, int x)
 }
 #endif
 
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
+{
+}
+
 struct ht_element 
 {
 	char *key;
diff --git a/utils/hashtest2.c b/utils/hashtest2.c
index 3b0c626997fc4d755c2101ec32a34815079d3f4a..a9fdf661b6b68f784d5da76fdef095e4a7a41a48 100644
--- a/utils/hashtest2.c
+++ b/utils/hashtest2.c
@@ -59,6 +59,11 @@ struct ht_element
 	char *val;
 };
 
+char *pbx_substitute_variables_helper_full(struct ast_channel *chan, struct varshead *head, const char *cp1, char *cp2, int maxlen, size_t *used);
+char *pbx_substitute_variables_helper_full(struct ast_channel *chan, struct varshead *head, const char *cp1, char *cp2, int maxlen, size_t *used)
+{
+	return NULL;
+}
 
 static int hash_string(const void *obj, const int flags)
 {
diff --git a/utils/refcounter.c b/utils/refcounter.c
index 4712c26b6cb111e55c0db7c06957098d84a34abd..ddd5055d01e6b801e886c3d3e90912e8f21262fc 100644
--- a/utils/refcounter.c
+++ b/utils/refcounter.c
@@ -69,6 +69,11 @@ struct rc_obj /* short for refcounted object */
 	struct rc_hist *last;
 };
 
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
+{
+}
+
 static unsigned int hashtab_hash_rc(const void *obj)
 {
 	const struct rc_obj *rc = obj;