diff --git a/res/res_fax.c b/res/res_fax.c index 8695414eafb7605f32c4e2d90e4515a081941c09..5f2704110b3da1960d8f2b5f8ed85e2da0330bce 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -769,7 +769,6 @@ static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_de } ast_channel_lock(chan); - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", status); if (details->option.statusevents) { struct manager_event_info info; @@ -797,13 +796,28 @@ static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_de return 0; } +/*! \brief Set fax related channel variables. */ +static void set_channel_variables(struct ast_channel *chan, struct ast_fax_session_details *details) +{ + char buf[10]; + pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL)); + pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL)); + pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL)); + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", S_OR(details->remotestationid, NULL)); + pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL)); + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL)); + + snprintf(buf, sizeof(buf), "%d", details->pages_transferred); + pbx_builtin_setvar_helper(chan, "FAXPAGES", buf); +} + #define GENERIC_FAX_EXEC_ERROR(fax, chan, errorstr, reason) \ do { \ ast_log(LOG_ERROR, "channel '%s' FAX session '%d' failure, reason: '%s' (%s)\n", chan->name, fax->id, reason, errorstr); \ - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", reason); \ - if (ast_strlen_zero(fax->details->result)) ast_string_field_set(fax->details, result, "FAILED"); \ - if (ast_strlen_zero(fax->details->resultstr)) ast_string_field_set(fax->details, resultstr, reason); \ - if (ast_strlen_zero(fax->details->error)) ast_string_field_set(fax->details, error, errorstr); \ + ast_string_field_set(fax->details, result, S_OR(fax->details->result, "FAILED")); \ + ast_string_field_set(fax->details, resultstr, S_OR(fax->details->resultstr, reason)); \ + ast_string_field_set(fax->details, error, S_OR(fax->details->error, errorstr)); \ + set_channel_variables(chan, fax->details); \ res = ms = -1; \ } while (0) @@ -934,7 +948,6 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det int res = 0, chancount; unsigned int expected_frametype = -1; union ast_frame_subclass expected_framesubclass = { .integer = -1 }; - char tbuf[10]; unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED); struct ast_control_t38_parameters t38_parameters; const char *tempvar; @@ -1009,13 +1022,12 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det ast_string_field_set(details, result, ""); ast_string_field_set(details, resultstr, ""); ast_string_field_set(details, error, ""); + set_channel_variables(chan, details); if (fax->tech->start_session(fax) < 0) { GENERIC_FAX_EXEC_ERROR(fax, chan, "INIT_ERROR", "failed to start FAX session"); } - pbx_builtin_setvar_helper(chan, "FAXSTATUS", NULL); - pbx_builtin_setvar_helper(chan, "FAXERROR", NULL); report_fax_status(chan, details, "FAX Transmission In Progress"); ast_debug(5, "channel %s will wait on FAX fd %d\n", chan->name, fax->fd); @@ -1036,6 +1048,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det * send the FAX stack silence so the modems can finish their session without * any problems */ ast_log(LOG_NOTICE, "Channel '%s' did not return a frame; probably hung up.\n", chan->name); + GENERIC_FAX_EXEC_ERROR(fax, chan, "HANGUP", "remote end hungup"); c = NULL; chancount = 0; timeout -= (1000 - ms); @@ -1129,9 +1142,12 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det if (ms && (ofd < 0)) { if ((errno == 0) || (errno == EINTR)) { timeout -= (1000 - ms); + if (timeout <= 0) + GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out"); continue; } else { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name); + GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data"); res = ms; break; } @@ -1139,6 +1155,8 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det /* nothing happened */ if (timeout > 0) { timeout -= 1000; + if (timeout <= 0) + GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out"); continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the FAX transmission.\n", chan->name); @@ -1150,15 +1168,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det } ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", chan->name, timeout, ms, res); - pbx_builtin_setvar_helper(chan, "FAXSTATUS", details->result); - pbx_builtin_setvar_helper(chan, "FAXERROR", details->error); - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", details->resultstr); - pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", details->remotestationid); - pbx_builtin_setvar_helper(chan, "FAXBITRATE", details->transfer_rate); - pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", details->resolution); - - snprintf(tbuf, sizeof(tbuf), "%d", details->pages_transferred); - pbx_builtin_setvar_helper(chan, "FAXPAGES", tbuf); + set_channel_variables(chan, details); ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1); if (!strcasecmp(details->result, "FAILED")) { @@ -1354,40 +1364,49 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) struct ast_flags opts = { 0, }; struct manager_event_info info; + /* initialize output channel variables */ + pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED"); + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL); + pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); + pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + /* Get a FAX session details structure from the channel's FAX datastore and create one if * it does not already exist. */ if (!(details = find_or_create_details(chan))) { + pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR"); + pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory"); ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n"); return -1; } + set_channel_variables(chan, details); if (ast_strlen_zero(data)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax); + ao2_ref(details, -1); return -1; } parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); - - /* initialize output channel variables */ - pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED"); - pbx_builtin_setvar_helper(chan, "FAXERROR", "Application Problems"); - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Invalid application arguments."); - pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL); - pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); - pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); - pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); if (!ast_strlen_zero(args.options) && ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) { + ast_string_field_set(details, error, "INVALID_ARGUMENTS"); + ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); + ao2_ref(details, -1); return -1; } if (ast_strlen_zero(args.filename)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax); + ao2_ref(details, -1); return -1; } @@ -1395,7 +1414,9 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s does not support polling\n", app_receivefax); + ao2_ref(details, -1); return -1; } @@ -1403,6 +1424,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (chan->_state != AST_STATE_UP) { if (ast_answer(chan)) { ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name); + ao2_ref(details, -1); return -1; } } @@ -1415,6 +1437,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(args.filename) + 1))) { ast_string_field_set(details, error, "MEMORY_ERROR"); ast_string_field_set(details, resultstr, "error allocating memory"); + set_channel_variables(chan, details); ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n"); ao2_ref(details, -1); return -1; @@ -1445,6 +1468,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (set_fax_t38_caps(chan, details)) { ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); + set_channel_variables(chan, details); ao2_ref(details, -1); return -1; } @@ -1453,6 +1477,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (receivefax_t38_init(chan, details)) { ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); + set_channel_variables(chan, details); ao2_ref(details, -1); ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name); return -1; @@ -1744,39 +1769,50 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) struct ast_flags opts = { 0, }; struct manager_event_info info; + /* initialize output channel variables */ + pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED"); + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL); + pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); + pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + /* Get a requirement structure and set it. This structure is used * to tell the FAX technology module about the higher level FAX session */ if (!(details = find_or_create_details(chan))) { + pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR"); + pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory"); ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n"); return -1; } + set_channel_variables(chan, details); + if (ast_strlen_zero(data)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax); + ao2_ref(details, -1); return -1; } parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); - /* initialize output channel variables */ - pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED"); - pbx_builtin_setvar_helper(chan, "FAXERROR", "Application Problems"); - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Invalid application arguments."); - pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL); - pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); - pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); - pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); if (!ast_strlen_zero(args.options) && ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) { + ast_string_field_set(details, error, "INVALID_ARGUMENTS"); + ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); + ao2_ref(details, -1); return -1; } if (ast_strlen_zero(args.filenames)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax); + ao2_ref(details, -1); return -1; } @@ -1784,7 +1820,9 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) { ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); + set_channel_variables(chan, details); ast_log(LOG_WARNING, "%s does not support polling\n", app_sendfax); + ao2_ref(details, -1); return -1; } @@ -1792,14 +1830,12 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (chan->_state != AST_STATE_UP) { if (ast_answer(chan)) { ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name); + ao2_ref(details, -1); return -1; } } ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1); - - pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems"); - pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Error before FAX transmission started."); file_count = 0; filenames = args.filenames; @@ -1807,6 +1843,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (access(c, (F_OK | R_OK)) < 0) { ast_string_field_set(details, error, "FILE_ERROR"); ast_string_field_set(details, resultstr, "error reading file"); + set_channel_variables(chan, details); ast_log(LOG_ERROR, "access failure. Verify '%s' exists and check permissions.\n", args.filenames); ao2_ref(details, -1); return -1; @@ -1815,6 +1852,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(c) + 1))) { ast_string_field_set(details, error, "MEMORY_ERROR"); ast_string_field_set(details, resultstr, "error allocating memory"); + set_channel_variables(chan, details); ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n"); ao2_ref(details, -1); return -1; @@ -1858,6 +1896,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (set_fax_t38_caps(chan, details)) { ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); + set_channel_variables(chan, details); ao2_ref(details, -1); return -1; } @@ -1866,6 +1905,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (sendfax_t38_init(chan, details)) { ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); + set_channel_variables(chan, details); ao2_ref(details, -1); ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name); return -1;