diff --git a/res/res_fax.c b/res/res_fax.c index bfd4a51abe..460dc1f52b 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -466,6 +466,51 @@ static int update_modem_bits(enum ast_fax_modems *bits, const char *value) return 0; } +static char *ast_fax_caps_to_str(enum ast_fax_capabilities caps, char *buf, size_t bufsize) +{ + char *out = buf; + size_t size = bufsize; + int first = 1; + + if (caps & AST_FAX_TECH_SEND) { + if (!first) { + ast_build_string(&buf, &size, ","); + } + ast_build_string(&buf, &size, "SEND"); + first = 0; + } + if (caps & AST_FAX_TECH_RECEIVE) { + if (!first) { + ast_build_string(&buf, &size, ","); + } + ast_build_string(&buf, &size, "RECEIVE"); + first = 0; + } + if (caps & AST_FAX_TECH_AUDIO) { + if (!first) { + ast_build_string(&buf, &size, ","); + } + ast_build_string(&buf, &size, "AUDIO"); + first = 0; + } + if (caps & AST_FAX_TECH_T38) { + if (!first) { + ast_build_string(&buf, &size, ","); + } + ast_build_string(&buf, &size, "T38"); + first = 0; + } + if (caps & AST_FAX_TECH_MULTI_DOC) { + if (!first) { + ast_build_string(&buf, &size, ","); + } + ast_build_string(&buf, &size, "MULTI_DOC"); + first = 0; + } + + return out; +} + static int ast_fax_modem_to_str(enum ast_fax_modems bits, char *tbuf, size_t bufsize) { int count = 0; @@ -685,6 +730,7 @@ static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_detail { struct ast_fax_session *s; struct fax_module *faxmod; + char caps[128] = ""; if (!(s = ao2_alloc(sizeof(*s), destroy_session))) { return NULL; @@ -708,7 +754,7 @@ static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_detail AST_RWLIST_UNLOCK(&faxmodules); if (!faxmod) { - ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (0x%X)\n", details->caps); + ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (%s)\n", ast_fax_caps_to_str(details->caps, caps, sizeof(caps))); ao2_ref(s, -1); return NULL; } @@ -734,6 +780,7 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d { struct ast_fax_session *s = NULL; struct fax_module *faxmod; + char caps[128] = ""; if (reserved) { s = reserved; @@ -798,7 +845,7 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d AST_RWLIST_UNLOCK(&faxmodules); if (!faxmod) { - ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (0x%X)\n", details->caps); + ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (%s)\n", ast_fax_caps_to_str(details->caps, caps, sizeof(caps))); ao2_ref(s, -1); return NULL; } @@ -1295,9 +1342,10 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det set_channel_variables(chan, details); - ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1); if (!strcasecmp(details->result, "FAILED")) { ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); + } else { + ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1); } if (fax) { @@ -1497,9 +1545,14 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + /* if we ran receivefax then we attempted to receive a fax, even if we + * never start a fax session */ + ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1); + /* 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))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); 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"); @@ -1512,6 +1565,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) set_channel_variables(chan, details); if (details->maxrate < details->minrate) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "maxrate is less than minrate"); set_channel_variables(chan, details); @@ -1521,6 +1575,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) } if (check_modem_rate(details->modems, details->minrate)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_fax_modem_to_str(details->modems, modems, sizeof(modems)); ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); @@ -1531,6 +1586,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) } if (check_modem_rate(details->modems, details->maxrate)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_fax_modem_to_str(details->modems, modems, sizeof(modems)); ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); @@ -1541,6 +1597,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) } if (ast_strlen_zero(data)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -1553,6 +1610,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (!ast_strlen_zero(args.options) && ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -1560,6 +1618,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) return -1; } if (ast_strlen_zero(args.filename)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -1570,6 +1629,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) /* check for unsupported FAX application options */ if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -1577,13 +1637,12 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) ao2_ref(details, -1); return -1; } - - ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1); pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems"); pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Error before FAX transmission started."); if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(args.filename) + 1))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "MEMORY_ERROR"); ast_string_field_set(details, resultstr, "error allocating memory"); set_channel_variables(chan, details); @@ -1615,6 +1674,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) } if (!(s = fax_session_reserve(details))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, resultstr, "error reserving fax session"); set_channel_variables(chan, details); ast_log(LOG_ERROR, "Unable to reserve FAX session.\n"); @@ -1625,6 +1685,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) /* make sure the channel is up */ if (chan->_state != AST_STATE_UP) { if (ast_answer(chan)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, resultstr, "error answering channel"); set_channel_variables(chan, details); ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name); @@ -1635,6 +1696,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) } if (set_fax_t38_caps(chan, details)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); set_channel_variables(chan, details); @@ -1645,6 +1707,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) if (details->caps & AST_FAX_TECH_T38) { if (receivefax_t38_init(chan, details)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); set_channel_variables(chan, details); @@ -1949,9 +2012,14 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + /* if we ran sendfax then we attempted to send a fax, even if we never + * start a fax session */ + ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1); + /* 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))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); 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"); @@ -1964,6 +2032,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) set_channel_variables(chan, details); if (details->maxrate < details->minrate) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "maxrate is less than minrate"); set_channel_variables(chan, details); @@ -1973,6 +2042,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (check_modem_rate(details->modems, details->minrate)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_fax_modem_to_str(details->modems, modems, sizeof(modems)); ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); @@ -1983,6 +2053,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (check_modem_rate(details->modems, details->maxrate)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_fax_modem_to_str(details->modems, modems, sizeof(modems)); ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); @@ -1993,6 +2064,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (ast_strlen_zero(data)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -2006,6 +2078,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (!ast_strlen_zero(args.options) && ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -2013,6 +2086,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) return -1; } if (ast_strlen_zero(args.filenames)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -2023,6 +2097,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) /* check for unsupported FAX application options */ if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "INVALID_ARGUMENTS"); ast_string_field_set(details, resultstr, "invalid arguments"); set_channel_variables(chan, details); @@ -2031,12 +2106,11 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) return -1; } - ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1); - file_count = 0; filenames = args.filenames; while ((c = strsep(&filenames, "&"))) { if (access(c, (F_OK | R_OK)) < 0) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "FILE_ERROR"); ast_string_field_set(details, resultstr, "error reading file"); set_channel_variables(chan, details); @@ -2046,6 +2120,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(c) + 1))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "MEMORY_ERROR"); ast_string_field_set(details, resultstr, "error allocating memory"); set_channel_variables(chan, details); @@ -2090,6 +2165,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (!(s = fax_session_reserve(details))) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, resultstr, "error reserving fax session"); set_channel_variables(chan, details); ast_log(LOG_ERROR, "Unable to reserve FAX session.\n"); @@ -2100,6 +2176,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) /* make sure the channel is up */ if (chan->_state != AST_STATE_UP) { if (ast_answer(chan)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, resultstr, "error answering channel"); set_channel_variables(chan, details); ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name); @@ -2110,6 +2187,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) } if (set_fax_t38_caps(chan, details)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); set_channel_variables(chan, details); @@ -2120,6 +2198,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) if (details->caps & AST_FAX_TECH_T38) { if (sendfax_t38_init(chan, details)) { + ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1); ast_string_field_set(details, error, "T38_NEG_ERROR"); ast_string_field_set(details, resultstr, "error negotiating T.38"); set_channel_variables(chan, details);