Merge "pbx_spool: Gracefully handle long lines in call files" into 13

This commit is contained in:
Joshua Colp
2017-03-07 17:20:31 -06:00
committed by Gerrit Code Review

View File

@@ -163,33 +163,24 @@ static struct outgoing *new_outgoing(const char *fn)
return o; return o;
} }
static int apply_outgoing(struct outgoing *o, FILE *f) static void parse_line(char *line, unsigned int lineno, struct outgoing *o)
{ {
char buf[256]; char *c;
char *c, *c2;
int lineno = 0;
struct ast_variable *var, *last = o->vars;
while (last && last->next) {
last = last->next;
}
while(fgets(buf, sizeof(buf), f)) {
lineno++;
/* Trim comments */ /* Trim comments */
c = buf; c = line;
while ((c = strchr(c, '#'))) { while ((c = strchr(c, '#'))) {
if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t')) if ((c == line) || (*(c-1) == ' ') || (*(c-1) == '\t')) {
*c = '\0'; *c = '\0';
else break;
}
c++; c++;
} }
c = buf; c = line;
while ((c = strchr(c, ';'))) { while ((c = strchr(c, ';'))) {
if ((c > buf) && (c[-1] == '\\')) { if ((c > line) && (c[-1] == '\\')) {
memmove(c - 1, c, strlen(c) + 1); memmove(c - 1, c, strlen(c) + 1);
c++;
} else { } else {
*c = '\0'; *c = '\0';
break; break;
@@ -197,21 +188,22 @@ static int apply_outgoing(struct outgoing *o, FILE *f)
} }
/* Trim trailing white space */ /* Trim trailing white space */
ast_trim_blanks(buf); ast_trim_blanks(line);
if (ast_strlen_zero(buf)) { if (ast_strlen_zero(line)) {
continue; return;
} }
c = strchr(buf, ':'); c = strchr(line, ':');
if (!c) { if (!c) {
ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, o->fn); ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, o->fn);
continue; return;
} }
*c = '\0'; *c = '\0';
c = ast_skip_blanks(c + 1); c = ast_skip_blanks(c + 1);
#if 0 #if 0
printf("'%s' is '%s' at line %d\n", buf, c, lineno); printf("'%s' is '%s' at line %d\n", line, c, lineno);
#endif #endif
if (!strcasecmp(buf, "channel")) { if (!strcasecmp(line, "channel")) {
char *c2;
if ((c2 = strchr(c, '/'))) { if ((c2 = strchr(c, '/'))) {
*c2 = '\0'; *c2 = '\0';
c2++; c2++;
@@ -220,82 +212,122 @@ static int apply_outgoing(struct outgoing *o, FILE *f)
} else { } else {
ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->fn); ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->fn);
} }
} else if (!strcasecmp(buf, "callerid")) { } else if (!strcasecmp(line, "callerid")) {
char cid_name[80] = {0}, cid_num[80] = {0}; char cid_name[80] = {0}, cid_num[80] = {0};
ast_callerid_split(c, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); ast_callerid_split(c, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
ast_string_field_set(o, cid_num, cid_num); ast_string_field_set(o, cid_num, cid_num);
ast_string_field_set(o, cid_name, cid_name); ast_string_field_set(o, cid_name, cid_name);
} else if (!strcasecmp(buf, "application")) { } else if (!strcasecmp(line, "application")) {
ast_string_field_set(o, app, c); ast_string_field_set(o, app, c);
} else if (!strcasecmp(buf, "data")) { } else if (!strcasecmp(line, "data")) {
ast_string_field_set(o, data, c); ast_string_field_set(o, data, c);
} else if (!strcasecmp(buf, "maxretries")) { } else if (!strcasecmp(line, "maxretries")) {
if (sscanf(c, "%30d", &o->maxretries) != 1) { if (sscanf(c, "%30d", &o->maxretries) != 1) {
ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, o->fn); ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, o->fn);
o->maxretries = 0; o->maxretries = 0;
} }
} else if (!strcasecmp(buf, "codecs")) { } else if (!strcasecmp(line, "codecs")) {
ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1); ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1);
} else if (!strcasecmp(buf, "context")) { } else if (!strcasecmp(line, "context")) {
ast_string_field_set(o, context, c); ast_string_field_set(o, context, c);
} else if (!strcasecmp(buf, "extension")) { } else if (!strcasecmp(line, "extension")) {
ast_string_field_set(o, exten, c); ast_string_field_set(o, exten, c);
} else if (!strcasecmp(buf, "priority")) { } else if (!strcasecmp(line, "priority")) {
if ((sscanf(c, "%30d", &o->priority) != 1) || (o->priority < 1)) { if ((sscanf(c, "%30d", &o->priority) != 1) || (o->priority < 1)) {
ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, o->fn); ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, o->fn);
o->priority = 1; o->priority = 1;
} }
} else if (!strcasecmp(buf, "retrytime")) { } else if (!strcasecmp(line, "retrytime")) {
if ((sscanf(c, "%30d", &o->retrytime) != 1) || (o->retrytime < 1)) { if ((sscanf(c, "%30d", &o->retrytime) != 1) || (o->retrytime < 1)) {
ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, o->fn); ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, o->fn);
o->retrytime = 300; o->retrytime = 300;
} }
} else if (!strcasecmp(buf, "waittime")) { } else if (!strcasecmp(line, "waittime")) {
if ((sscanf(c, "%30d", &o->waittime) != 1) || (o->waittime < 1)) { if ((sscanf(c, "%30d", &o->waittime) != 1) || (o->waittime < 1)) {
ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, o->fn); ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, o->fn);
o->waittime = 45; o->waittime = 45;
} }
} else if (!strcasecmp(buf, "retry")) { } else if (!strcasecmp(line, "retry")) {
o->retries++; o->retries++;
} else if (!strcasecmp(buf, "startretry")) { } else if (!strcasecmp(line, "startretry")) {
if (sscanf(c, "%30ld", &o->callingpid) != 1) { if (sscanf(c, "%30ld", &o->callingpid) != 1) {
ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n");
o->callingpid = 0; o->callingpid = 0;
} }
} else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) { } else if (!strcasecmp(line, "endretry") || !strcasecmp(line, "abortretry")) {
o->callingpid = 0; o->callingpid = 0;
o->retries++; o->retries++;
} else if (!strcasecmp(buf, "delayedretry")) { } else if (!strcasecmp(line, "delayedretry")) {
} else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) { } else if (!strcasecmp(line, "setvar") || !strcasecmp(line, "set")) {
c2 = c; char *c2 = c;
strsep(&c2, "="); strsep(&c2, "=");
if (c2) { if (c2) {
var = ast_variable_new(c, c2, o->fn); struct ast_variable *var = ast_variable_new(c, c2, o->fn);
if (var) { if (var) {
/* Always insert at the end, because some people want to treat the spool file as a script */ /*
if (last) { * Always insert at the end, because some people
last->next = var; * want to treat the spool file as a script
*/
struct ast_variable **tail = &o->vars;
while (*tail) {
tail = &(*tail)->next;
}
*tail = var;
}
} else { } else {
o->vars = var; ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", line, line);
} }
last = var; } else if (!strcasecmp(line, "account")) {
}
} else
ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", buf, buf);
} else if (!strcasecmp(buf, "account")) {
ast_string_field_set(o, account, c); ast_string_field_set(o, account, c);
} else if (!strcasecmp(buf, "alwaysdelete")) { } else if (!strcasecmp(line, "alwaysdelete")) {
ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE); ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE);
} else if (!strcasecmp(buf, "archive")) { } else if (!strcasecmp(line, "archive")) {
ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE); ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE);
} else if (!strcasecmp(buf, "early_media")) { } else if (!strcasecmp(line, "early_media")) {
ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_EARLY_MEDIA); ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_EARLY_MEDIA);
} else { } else {
ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, o->fn); ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", line, lineno, o->fn);
}
}
#define LINE_BUFFER_SIZE 1024
static int apply_outgoing(struct outgoing *o, FILE *f)
{
char buf[LINE_BUFFER_SIZE];
unsigned int lineno = 0;
while (fgets(buf, sizeof(buf), f)) {
size_t len = strlen(buf);
lineno++;
if (buf[len - 1] == '\n' || feof(f)) {
/* We have a line, parse it */
parse_line(buf, lineno, o);
continue;
}
/* Crazy long line, skip it */
ast_log(LOG_WARNING, "Skipping extremely long line at line %d of %s\n", lineno, o->fn);
/* Consume the rest of the problematic line */
while (fgets(buf, sizeof(buf), f)) {
len = strlen(buf);
if (buf[len - 1] == '\n' || feof(f)) {
break;
} }
} }
if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { }
ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", o->fn);
if (ast_strlen_zero(o->tech)
|| ast_strlen_zero(o->dest)
|| (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
ast_log(LOG_WARNING, "At least one of app or extension must be specified, "
"along with tech and dest in file %s\n", o->fn);
return -1; return -1;
} }
return 0; return 0;