Wed Jan 27 20:02:47 2016

Asterisk developer's documentation


res_fax.c File Reference

Generic FAX Resource for FAX technology resource modules. More...

#include "asterisk.h"
#include "asterisk/io.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/strings.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/astobj2.h"
#include "asterisk/res_fax.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/manager.h"
#include "asterisk/dsp.h"
#include "asterisk/indications.h"
#include "asterisk/ast_version.h"

Go to the source code of this file.

Data Structures

struct  ast_fax_debug_info
struct  debug_info_history
struct  fax_module
 registered FAX technology modules are put into this list More...
struct  fax_options
struct  faxmodules
struct  manager_event_info

Defines

#define FAX_MAXBUCKETS   10
 maximum buckets for res_fax ao2 containers
#define GENERIC_FAX_EXEC_ERROR(fax, chan, errorstr, reason)
#define GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason)
#define GENERIC_FAX_EXEC_SET_VARS(fax, chan, errorstr, reason)
#define RES_FAX_MAXRATE   14400
#define RES_FAX_MINRATE   4800
#define RES_FAX_MODEM   (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)
#define RES_FAX_STATUSEVENTS   0
#define RES_FAX_TIMEOUT   10000

Enumerations

enum  {
  OPT_CALLEDMODE = (1 << 0), OPT_CALLERMODE = (1 << 1), OPT_DEBUG = (1 << 2), OPT_STATUS = (1 << 3),
  OPT_ALLOWAUDIO = (1 << 5), OPT_REQUEST_T38 = (1 << 6)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int acf_faxopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 FAXOPT read function returns the contents of a FAX option.
static int acf_faxopt_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 FAXOPT write function modifies the contents of a FAX option.
static char * ast_fax_caps_to_str (enum ast_fax_capabilities caps, char *buf, size_t bufsize)
void ast_fax_log (int level, const char *file, const int line, const char *function, const char *msg)
 Log message at FAX or recommended level.
unsigned int ast_fax_maxrate (void)
 get the maxiumum supported fax rate
unsigned int ast_fax_minrate (void)
 get the minimum supported fax rate
static int ast_fax_modem_to_str (enum ast_fax_modems bits, char *tbuf, size_t bufsize)
const char * ast_fax_state_to_str (enum ast_fax_state state)
 convert a ast_fax_state to a string
int ast_fax_tech_register (struct ast_fax_tech *tech)
 register a FAX technology module
void ast_fax_tech_unregister (struct ast_fax_tech *tech)
 unregister a FAX technology module
static int check_modem_rate (enum ast_fax_modems modems, unsigned int rate)
static char * cli_fax_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 enable FAX debugging
static char * cli_fax_show_capabilities (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 display registered FAX capabilities
static char * cli_fax_show_session (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 display details of a specified fax session
static char * cli_fax_show_sessions (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 display fax sessions
static char * cli_fax_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 display global defaults and settings
static char * cli_fax_show_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 display fax stats
static char * cli_fax_show_version (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void debug_check_frame_for_silence (struct ast_fax_session *s, unsigned int c2s, struct ast_frame *frame)
static void destroy_callback (void *data)
static void destroy_session (void *session)
 destroy a FAX session structure
static void destroy_session_details (void *details)
 destroy a FAX session details structure
static int disable_t38 (struct ast_channel *chan)
static unsigned int fax_rate_str_to_int (const char *ratestr)
 convert a rate string to a rate
static struct ast_fax_sessionfax_session_new (struct ast_fax_session_details *details, struct ast_channel *chan, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
 create a FAX session
static void fax_session_release (struct ast_fax_session *s, struct ast_fax_tech_token *token)
static struct ast_fax_sessionfax_session_reserve (struct ast_fax_session_details *details, struct ast_fax_tech_token **token)
static char * fax_session_tab_complete (struct ast_cli_args *a)
 fax session tab completion
static struct
ast_fax_session_details
find_details (struct ast_channel *chan)
 returns a reference counted pointer to a fax datastore, if it exists
static struct
ast_fax_session_details
find_or_create_details (struct ast_channel *chan)
 returns a reference counted details structure from the channel's fax datastore. If the datastore does not exist it will be created
static char * generate_filenames_string (struct ast_fax_session_details *details, char *prefix, char *separator)
static int generic_fax_exec (struct ast_channel *chan, struct ast_fax_session_details *details, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
 this is the generic FAX session handling function
static void get_general_options (struct fax_options *options)
static void get_manager_event_info (struct ast_channel *chan, struct manager_event_info *info)
static int load_module (void)
 load res_fax
static int receivefax_exec (struct ast_channel *chan, const char *data)
 initiate a receive FAX session
static int receivefax_t38_init (struct ast_channel *chan, struct ast_fax_session_details *details)
static int reload_module (void)
static int report_fax_status (struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
 send a FAX status manager event
static int sendfax_exec (struct ast_channel *chan, const char *data)
 initiate a send FAX session
static int sendfax_t38_init (struct ast_channel *chan, struct ast_fax_session_details *details)
static int session_cmp_cb (void *obj, void *arg, int flags)
 compare callback for ao2
static struct
ast_fax_session_details
session_details_new (void)
 create a FAX session details structure
static int session_hash_cb (const void *obj, const int flags)
 hash callback for ao2
static void set_channel_variables (struct ast_channel *chan, struct ast_fax_session_details *details)
 Set fax related channel variables.
static int set_config (int reload)
 configure res_fax
static int set_fax_t38_caps (struct ast_channel *chan, struct ast_fax_session_details *details)
static void set_general_options (const struct fax_options *options)
static void t38_parameters_ast_to_fax (struct ast_fax_t38_parameters *dst, const struct ast_control_t38_parameters *src)
static void t38_parameters_fax_to_ast (struct ast_control_t38_parameters *dst, const struct ast_fax_t38_parameters *src)
static int unload_module (void)
 unload res_fax
static int update_modem_bits (enum ast_fax_modems *bits, const char *value)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Generic FAX Applications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_APP_DEPEND, }
struct ast_custom_function acf_faxopt
 FAXOPT dialplan function.
static const char app_receivefax [] = "ReceiveFAX"
static const char app_sendfax [] = "SendFAX"
static struct ast_module_infoast_module_info = &__mod_info
static const char * config = "res_fax.conf"
static struct fax_options default_options
static struct ast_cli_entry fax_cli []
static struct ast_datastore_info fax_datastore
static struct ast_app_option fax_exec_options [128] = { [ 'a' ] = { .flag = OPT_CALLEDMODE }, [ 'c' ] = { .flag = OPT_CALLERMODE }, [ 'd' ] = { .flag = OPT_DEBUG }, [ 'f' ] = { .flag = OPT_ALLOWAUDIO }, [ 's' ] = { .flag = OPT_STATUS }, [ 'z' ] = { .flag = OPT_REQUEST_T38 }, }
static int fax_logger_level = -1
struct {
   int   active_sessions
   struct ao2_container *   container
   int   fax_complete
   int   fax_failures
   int   fax_rx_attempts
   int   fax_tx_attempts
   int   nextsessionname
   int   reserved_sessions
faxregistry
 The faxregistry is used to manage information and statistics for all FAX sessions.
static struct fax_options general_options
static int global_fax_debug = 0
static ast_rwlock_t options_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 }
static struct
ast_control_t38_parameters 
our_t38_parameters

Detailed Description

Generic FAX Resource for FAX technology resource modules.

Author:
Dwayne M. Hubbard <dhubbard@digium.com>
Kevin P. Fleming <kpfleming@digium.com>

A generic FAX resource module that provides SendFAX and ReceiveFAX applications. This module requires FAX technology modules, like res_fax_spandsp, to register with it so it can use the technology modules to perform the actual FAX transmissions.

Definition in file res_fax.c.


Define Documentation

#define FAX_MAXBUCKETS   10

maximum buckets for res_fax ao2 containers

Definition at line 216 of file res_fax.c.

Referenced by load_module().

#define GENERIC_FAX_EXEC_ERROR ( fax,
chan,
errorstr,
reason   ) 
Value:
do {  \
      ast_log(LOG_ERROR, "channel '%s' FAX session '%u' failure, reason: '%s' (%s)\n", chan->name, fax->id, reason, errorstr); \
      GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason); \
   } while (0)

Definition at line 1031 of file res_fax.c.

Referenced by generic_fax_exec().

#define GENERIC_FAX_EXEC_ERROR_QUIET ( fax,
chan,
errorstr,
reason   ) 
Value:
do {  \
      GENERIC_FAX_EXEC_SET_VARS(fax, chan, errorstr, reason); \
   } while (0)

Definition at line 1026 of file res_fax.c.

#define GENERIC_FAX_EXEC_SET_VARS ( fax,
chan,
errorstr,
reason   ) 

Definition at line 1015 of file res_fax.c.

Referenced by generic_fax_exec().

#define RES_FAX_MAXRATE   14400

Definition at line 248 of file res_fax.c.

#define RES_FAX_MINRATE   4800

Definition at line 247 of file res_fax.c.

#define RES_FAX_MODEM   (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)

Definition at line 250 of file res_fax.c.

#define RES_FAX_STATUSEVENTS   0

Definition at line 249 of file res_fax.c.

#define RES_FAX_TIMEOUT   10000

Definition at line 218 of file res_fax.c.

Referenced by generic_fax_exec().


Enumeration Type Documentation

anonymous enum
Enumerator:
OPT_CALLEDMODE 
OPT_CALLERMODE 
OPT_DEBUG 
OPT_STATUS 
OPT_ALLOWAUDIO 
OPT_REQUEST_T38 

Definition at line 279 of file res_fax.c.

00279      {
00280    OPT_CALLEDMODE  = (1 << 0),
00281    OPT_CALLERMODE  = (1 << 1),
00282    OPT_DEBUG       = (1 << 2),
00283    OPT_STATUS      = (1 << 3),
00284    OPT_ALLOWAUDIO  = (1 << 5),
00285    OPT_REQUEST_T38 = (1 << 6),
00286 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2968 of file res_fax.c.

static void __unreg_module ( void   )  [static]

Definition at line 2968 of file res_fax.c.

static int acf_faxopt_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

FAXOPT read function returns the contents of a FAX option.

Definition at line 2774 of file res_fax.c.

References ao2_ref, ast_copy_string(), ast_fax_modem_to_str(), ast_free, AST_LIST_EMPTY, AST_LIST_FIRST, ast_log(), ast_fax_session_details::documents, ast_fax_session_details::ecm, find_details(), generate_filenames_string(), ast_fax_session_details::id, LOG_ERROR, LOG_WARNING, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, ast_fax_session_details::option, and ast_fax_session_details::pages_transferred.

02775 {
02776    struct ast_fax_session_details *details = find_details(chan);
02777    int res = 0;
02778    char *filenames;
02779 
02780    if (!details) {
02781       ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02782       return -1;
02783    }
02784    if (!strcasecmp(data, "ecm")) {
02785       ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
02786    } else if (!strcasecmp(data, "error")) {
02787       ast_copy_string(buf, details->error, len);
02788    } else if (!strcasecmp(data, "filename")) {
02789       if (AST_LIST_EMPTY(&details->documents)) {
02790          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02791          res = -1;
02792       } else {
02793          ast_copy_string(buf, AST_LIST_FIRST(&details->documents)->filename, len);
02794       }
02795    } else if (!strcasecmp(data, "filenames")) {
02796       if (AST_LIST_EMPTY(&details->documents)) {
02797          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02798          res = -1;
02799       } else if ((filenames = generate_filenames_string(details, "", ","))) {
02800          ast_copy_string(buf, filenames, len);
02801          ast_free(filenames);
02802       } else {
02803          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s), there was an error generating the filenames list.\n", chan->name, data);
02804          res = -1;
02805       }
02806    } else if (!strcasecmp(data, "headerinfo")) {
02807       ast_copy_string(buf, details->headerinfo, len);
02808    } else if (!strcasecmp(data, "localstationid")) {
02809       ast_copy_string(buf, details->localstationid, len);
02810    } else if (!strcasecmp(data, "maxrate")) {
02811       snprintf(buf, len, "%u", details->maxrate);
02812    } else if (!strcasecmp(data, "minrate")) {
02813       snprintf(buf, len, "%u", details->minrate);
02814    } else if (!strcasecmp(data, "pages")) {
02815       snprintf(buf, len, "%u", details->pages_transferred);
02816    } else if (!strcasecmp(data, "rate")) {
02817       ast_copy_string(buf, details->transfer_rate, len);
02818    } else if (!strcasecmp(data, "remotestationid")) {
02819       ast_copy_string(buf, details->remotestationid, len);
02820    } else if (!strcasecmp(data, "resolution")) {
02821       ast_copy_string(buf, details->resolution, len);
02822    } else if (!strcasecmp(data, "sessionid")) {
02823       snprintf(buf, len, "%u", details->id);
02824    } else if (!strcasecmp(data, "status")) {
02825       ast_copy_string(buf, details->result, len);
02826    } else if (!strcasecmp(data, "statusstr")) {
02827       ast_copy_string(buf, details->resultstr, len);
02828    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02829       ast_fax_modem_to_str(details->modems, buf, len);
02830    } else {
02831       ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", chan->name, data);
02832       res = -1;
02833    }
02834    ao2_ref(details, -1);
02835 
02836    return res;
02837 }

static int acf_faxopt_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

FAXOPT write function modifies the contents of a FAX option.

Definition at line 2840 of file res_fax.c.

References ao2_ref, ast_debug, ast_false(), ast_fax_maxrate(), ast_fax_minrate(), AST_FAX_OPTFLAG_FALSE, AST_FAX_OPTFLAG_TRUE, ast_log(), ast_skip_blanks(), ast_string_field_set, ast_true(), ast_fax_session_details::ecm, fax_rate_str_to_int(), find_or_create_details(), LOG_WARNING, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, ast_fax_session_details::option, and update_modem_bits().

02841 {
02842    int res = 0;
02843    struct ast_fax_session_details *details;
02844 
02845    if (!(details = find_or_create_details(chan))) {
02846       ast_log(LOG_WARNING, "channel '%s' can't set FAXOPT(%s) to '%s' because it failed to create a datastore.\n", chan->name, data, value);
02847       return -1;
02848    }
02849    ast_debug(3, "channel '%s' setting FAXOPT(%s) to '%s'\n", chan->name, data, value);
02850 
02851    if (!strcasecmp(data, "ecm")) {
02852       const char *val = ast_skip_blanks(value);
02853       if (ast_true(val)) {
02854          details->option.ecm = AST_FAX_OPTFLAG_TRUE;
02855       } else if (ast_false(val)) {
02856          details->option.ecm = AST_FAX_OPTFLAG_FALSE;
02857       } else {
02858          ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
02859       }
02860    } else if (!strcasecmp(data, "headerinfo")) {
02861       ast_string_field_set(details, headerinfo, value);
02862    } else if (!strcasecmp(data, "localstationid")) {
02863       ast_string_field_set(details, localstationid, value);
02864    } else if (!strcasecmp(data, "maxrate")) {
02865       details->maxrate = fax_rate_str_to_int(value);
02866       if (!details->maxrate) {
02867          details->maxrate = ast_fax_maxrate();
02868       }
02869    } else if (!strcasecmp(data, "minrate")) {
02870       details->minrate = fax_rate_str_to_int(value);
02871       if (!details->minrate) {
02872          details->minrate = ast_fax_minrate();
02873       }
02874    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02875       update_modem_bits(&details->modems, value);
02876    } else {
02877       ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", chan->name, data, value);
02878       res = -1;
02879    }
02880 
02881    ao2_ref(details, -1);
02882 
02883    return res;
02884 }

static char* ast_fax_caps_to_str ( enum ast_fax_capabilities  caps,
char *  buf,
size_t  bufsize 
) [static]

Definition at line 494 of file res_fax.c.

References ast_build_string(), AST_FAX_TECH_AUDIO, AST_FAX_TECH_MULTI_DOC, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, AST_FAX_TECH_T38, and first.

Referenced by fax_session_new(), and fax_session_reserve().

00495 {
00496    char *out = buf;
00497    size_t size = bufsize;
00498    int first = 1;
00499 
00500    if (caps & AST_FAX_TECH_SEND) {
00501       if (!first) {
00502          ast_build_string(&buf, &size, ",");
00503       }
00504       ast_build_string(&buf, &size, "SEND");
00505       first = 0;
00506    }
00507    if (caps & AST_FAX_TECH_RECEIVE) {
00508       if (!first) {
00509          ast_build_string(&buf, &size, ",");
00510       }
00511       ast_build_string(&buf, &size, "RECEIVE");
00512       first = 0;
00513    }
00514    if (caps & AST_FAX_TECH_AUDIO) {
00515       if (!first) {
00516          ast_build_string(&buf, &size, ",");
00517       }
00518       ast_build_string(&buf, &size, "AUDIO");
00519       first = 0;
00520    }
00521    if (caps & AST_FAX_TECH_T38) {
00522       if (!first) {
00523          ast_build_string(&buf, &size, ",");
00524       }
00525       ast_build_string(&buf, &size, "T38");
00526       first = 0;
00527    }
00528    if (caps & AST_FAX_TECH_MULTI_DOC) {
00529       if (!first) {
00530          ast_build_string(&buf, &size, ",");
00531       }
00532       ast_build_string(&buf, &size, "MULTI_DOC");
00533       first = 0;
00534    }
00535 
00536    return out;
00537 }

void ast_fax_log ( int  level,
const char *  file,
const int  line,
const char *  function,
const char *  msg 
)

Log message at FAX or recommended level.

The first four parameters can be represented with Asterisk's LOG_* levels. In other words, this function may be called like

ast_fax_log(LOG_DEBUG, msg);

Definition at line 680 of file res_fax.c.

References ast_log(), and ast_log_dynamic_level.

Referenced by spandsp_log().

00681 {
00682    if (fax_logger_level != -1) {
00683       ast_log_dynamic_level(fax_logger_level, "%s", msg);
00684    } else {
00685       ast_log(level, file, line, function, "%s", msg);
00686    }
00687 }

unsigned int ast_fax_maxrate ( void   ) 

get the maxiumum supported fax rate

Definition at line 444 of file res_fax.c.

References get_general_options(), and fax_options::maxrate.

Referenced by acf_faxopt_write().

00445 {
00446    struct fax_options options;
00447    get_general_options(&options);
00448 
00449    return options.maxrate;
00450 }

unsigned int ast_fax_minrate ( void   ) 

get the minimum supported fax rate

Definition at line 452 of file res_fax.c.

References get_general_options(), and fax_options::minrate.

Referenced by acf_faxopt_write().

00453 {
00454    struct fax_options options;
00455    get_general_options(&options);
00456 
00457    return options.minrate;
00458 }

static int ast_fax_modem_to_str ( enum ast_fax_modems  bits,
char *  tbuf,
size_t  bufsize 
) [static]

Definition at line 539 of file res_fax.c.

References AST_FAX_MODEM_V17, AST_FAX_MODEM_V27, AST_FAX_MODEM_V29, and AST_FAX_MODEM_V34.

Referenced by acf_faxopt_read(), cli_fax_show_settings(), receivefax_exec(), sendfax_exec(), and set_config().

00540 {
00541    int count = 0;
00542 
00543    if (bits & AST_FAX_MODEM_V17) {
00544       strcat(tbuf, "V17");
00545       count++;
00546    }
00547    if (bits & AST_FAX_MODEM_V27) {
00548       if (count) {
00549          strcat(tbuf, ",");
00550       }
00551       strcat(tbuf, "V27");
00552       count++;
00553    }
00554    if (bits & AST_FAX_MODEM_V29) {
00555       if (count) {
00556          strcat(tbuf, ",");
00557       }
00558       strcat(tbuf, "V29");
00559       count++;
00560    }
00561    if (bits & AST_FAX_MODEM_V34) {
00562       if (count) {
00563          strcat(tbuf, ",");
00564       }
00565       strcat(tbuf, "V34");
00566       count++;
00567    }
00568 
00569    return 0;
00570 }

const char* ast_fax_state_to_str ( enum ast_fax_state  state  ) 

convert a ast_fax_state to a string

convert an ast_fax_state to a string

Definition at line 657 of file res_fax.c.

References AST_FAX_STATE_ACTIVE, AST_FAX_STATE_COMPLETE, AST_FAX_STATE_INACTIVE, AST_FAX_STATE_INITIALIZED, AST_FAX_STATE_OPEN, AST_FAX_STATE_RESERVED, AST_FAX_STATE_UNINITIALIZED, ast_log(), and LOG_WARNING.

Referenced by cli_fax_show_sessions(), spandsp_fax_cli_show_session(), and spandsp_fax_write().

00658 {
00659    switch (state) {
00660    case AST_FAX_STATE_UNINITIALIZED:
00661       return "Uninitialized";
00662    case AST_FAX_STATE_INITIALIZED:
00663       return "Initialized";
00664    case AST_FAX_STATE_OPEN:
00665       return "Open";
00666    case AST_FAX_STATE_ACTIVE:
00667       return "Active";
00668    case AST_FAX_STATE_COMPLETE:
00669       return "Complete";
00670    case AST_FAX_STATE_RESERVED:
00671       return "Reserved";
00672    case AST_FAX_STATE_INACTIVE:
00673       return "Inactive";
00674    default:
00675       ast_log(LOG_WARNING, "unhandled FAX state: %u\n", state);
00676       return "Unknown";
00677    }
00678 }

int ast_fax_tech_register ( struct ast_fax_tech tech  ) 

register a FAX technology module

register a fax technology

Definition at line 616 of file res_fax.c.

References ast_calloc, ast_module_ref(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_fax_tech::description, fax_module::tech, and ast_fax_tech::type.

Referenced by load_module().

00617 {
00618    struct fax_module *fax;
00619 
00620    if (!(fax = ast_calloc(1, sizeof(*fax)))) {
00621       return -1;
00622    }
00623    fax->tech = tech;
00624    AST_RWLIST_WRLOCK(&faxmodules);
00625    AST_RWLIST_INSERT_TAIL(&faxmodules, fax, list);
00626    AST_RWLIST_UNLOCK(&faxmodules);
00627    ast_module_ref(ast_module_info->self);
00628 
00629    ast_verb(3, "Registered handler for '%s' (%s)\n", fax->tech->type, fax->tech->description);
00630 
00631    return 0;
00632 }

void ast_fax_tech_unregister ( struct ast_fax_tech tech  ) 

unregister a FAX technology module

unregister a fax technology

Definition at line 635 of file res_fax.c.

References ast_free, ast_module_unref(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, fax_module::tech, and ast_fax_tech::type.

Referenced by unload_module().

00636 {
00637    struct fax_module *fax;
00638 
00639    ast_verb(3, "Unregistering FAX module type '%s'\n", tech->type);
00640 
00641    AST_RWLIST_WRLOCK(&faxmodules);
00642    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&faxmodules, fax, list) {
00643       if (fax->tech != tech) {
00644          continue;
00645       }
00646       AST_RWLIST_REMOVE_CURRENT(list);
00647       ast_module_unref(ast_module_info->self);
00648       ast_free(fax);
00649       ast_verb(4, "Unregistered FAX module type '%s'\n", tech->type);
00650       break;   
00651    }
00652    AST_RWLIST_TRAVERSE_SAFE_END;
00653    AST_RWLIST_UNLOCK(&faxmodules);
00654 }

static int check_modem_rate ( enum ast_fax_modems  modems,
unsigned int  rate 
) [static]

Definition at line 572 of file res_fax.c.

References AST_FAX_MODEM_V17, AST_FAX_MODEM_V27, AST_FAX_MODEM_V29, and AST_FAX_MODEM_V34.

Referenced by receivefax_exec(), sendfax_exec(), and set_config().

00573 {
00574    switch (rate) {
00575    case 2400:
00576       if (!(modems & (AST_FAX_MODEM_V34))) {
00577          return 1;
00578       }
00579       break;
00580    case 4800:
00581       if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
00582          return 1;
00583       }
00584       break;
00585    case 7200:
00586       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
00587          return 1;
00588       }
00589       break;
00590    case 9600:
00591       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
00592          return 1;
00593       }
00594       break;
00595    case 12000:
00596    case 14400:
00597       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
00598          return 1;
00599       }
00600       break;
00601    case 28800:
00602    case 33600:
00603       if (!(modems & AST_FAX_MODEM_V34)) {
00604          return 1;
00605       }
00606       break;
00607    default:
00608       /* this should never happen */
00609       return 1;
00610    }
00611 
00612    return 0;
00613 }

static char* cli_fax_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

enable FAX debugging

Definition at line 2421 of file res_fax.c.

References ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, global_fax_debug, and ast_cli_entry::usage.

02422 {
02423    int flag;
02424    const char *what;
02425 
02426    switch (cmd) {
02427    case CLI_INIT:
02428       e->command = "fax set debug {on|off}";
02429       e->usage = 
02430          "Usage: fax set debug { on | off }\n"
02431          "       Enable/Disable FAX debugging on new FAX sessions.  The basic FAX debugging will result in\n"
02432          "       additional events sent to manager sessions with 'call' class permissions.  When\n"
02433          "       verbosity is greater than '5' events will be displayed to the console and audio versus\n"
02434          "       energy analysis will be performed and displayed to the console.\n";
02435       return NULL;
02436    case CLI_GENERATE:
02437       return NULL;
02438    }
02439 
02440    what = a->argv[e->args-1];      /* guaranteed to exist */
02441    if (!strcasecmp(what, "on")) {
02442       flag = 1;
02443    } else if (!strcasecmp(what, "off")) {
02444       flag = 0;
02445    } else {
02446       return CLI_SHOWUSAGE;
02447    }
02448 
02449    global_fax_debug = flag;
02450    ast_cli(a->fd, "\n\nFAX Debug %s\n\n", (flag) ? "Enabled" : "Disabled");
02451 
02452    return CLI_SUCCESS;
02453 }

static char* cli_fax_show_capabilities ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

display registered FAX capabilities

Definition at line 2456 of file res_fax.c.

References ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, ast_fax_tech::cli_show_capabilities, CLI_SUCCESS, ast_cli_entry::command, ast_fax_tech::description, ast_cli_args::fd, fax_module::tech, ast_fax_tech::type, and ast_cli_entry::usage.

02457 {
02458    struct fax_module *fax;
02459    unsigned int num_modules = 0;
02460    
02461    switch (cmd) {
02462    case CLI_INIT:
02463       e->command = "fax show capabilities";
02464       e->usage = 
02465          "Usage: fax show capabilities\n"
02466          "       Shows the capabilities of the registered FAX technology modules\n";
02467       return NULL;
02468    case CLI_GENERATE:
02469       return NULL;
02470    }
02471 
02472    ast_cli(a->fd, "\n\nRegistered FAX Technology Modules:\n\n");
02473    AST_RWLIST_RDLOCK(&faxmodules);
02474    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02475       ast_cli(a->fd, "%-15s : %s\n%-15s : %s\n%-15s : ", "Type", fax->tech->type, "Description", fax->tech->description, "Capabilities");
02476       fax->tech->cli_show_capabilities(a->fd);
02477       num_modules++;
02478    }
02479    AST_RWLIST_UNLOCK(&faxmodules);
02480    ast_cli(a->fd, "%u registered modules\n\n", num_modules);
02481 
02482    return CLI_SUCCESS;
02483 }

static char* cli_fax_show_session ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

display details of a specified fax session

Definition at line 2524 of file res_fax.c.

References ao2_find, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_log(), CLI_GENERATE, CLI_INIT, ast_fax_tech::cli_show_session, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, fax_session_tab_complete(), faxregistry, ast_cli_args::fd, ast_fax_session::id, LOG_ERROR, OBJ_POINTER, RESULT_SUCCESS, ast_fax_session::tech, and ast_cli_entry::usage.

02525 {
02526    struct ast_fax_session *s, tmp;
02527 
02528    switch (cmd) {
02529    case CLI_INIT:
02530       e->command = "fax show session";
02531       e->usage =
02532          "Usage: fax show session <session number>\n"
02533          "       Shows status of the named FAX session\n";
02534       return NULL;
02535    case CLI_GENERATE:
02536       return fax_session_tab_complete(a);
02537    }
02538 
02539    if (a->argc != 4) {
02540       return CLI_SHOWUSAGE;
02541    }
02542 
02543    if (sscanf(a->argv[3], "%u", &tmp.id) != 1) {
02544       ast_log(LOG_ERROR, "invalid session id: '%s'\n", a->argv[3]);
02545       return RESULT_SUCCESS;
02546    }
02547 
02548    ast_cli(a->fd, "\nFAX Session Details:\n--------------------\n\n");
02549    s = ao2_find(faxregistry.container, &tmp, OBJ_POINTER);
02550    if (s) {
02551       s->tech->cli_show_session(s, a->fd);
02552       ao2_ref(s, -1);
02553    }
02554    ast_cli(a->fd, "\n\n");
02555 
02556    return CLI_SUCCESS;
02557 }

static char* cli_fax_show_sessions ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

display fax sessions

Definition at line 2593 of file res_fax.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), ast_fax_state_to_str(), AST_FAX_TECH_AUDIO, AST_FAX_TECH_SEND, ast_free, ast_log(), ast_fax_session_details::caps, ast_fax_session::channame, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_fax_session::details, faxregistry, ast_cli_args::fd, generate_filenames_string(), ast_fax_session::id, LOG_ERROR, session_count, ast_fax_session::state, ast_fax_session::tech, ast_fax_tech::type, and ast_cli_entry::usage.

02594 {
02595    struct ast_fax_session *s;
02596    struct ao2_iterator i;
02597    int session_count;
02598    char *filenames;
02599 
02600    switch (cmd) {
02601    case CLI_INIT:
02602       e->command = "fax show sessions";
02603       e->usage =
02604          "Usage: fax show sessions\n"
02605          "       Shows the current FAX sessions\n";
02606       return NULL;
02607    case CLI_GENERATE:
02608       return NULL;
02609    }
02610 
02611    ast_cli(a->fd, "\nCurrent FAX Sessions:\n\n");
02612    ast_cli(a->fd, "%-20.20s %-10.10s %-10.10s %-5.5s %-10.10s %-15.15s %-30.30s\n",
02613       "Channel", "Tech", "FAXID", "Type", "Operation", "State", "File(s)");
02614    i = ao2_iterator_init(faxregistry.container, 0);
02615    while ((s = ao2_iterator_next(&i))) {
02616       ao2_lock(s);
02617 
02618       if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
02619          ast_log(LOG_ERROR, "Error printing filenames for 'fax show sessions' command\n");
02620          ao2_unlock(s);
02621          ao2_ref(s, -1);
02622          ao2_iterator_destroy(&i);
02623          return CLI_FAILURE;
02624       }
02625 
02626       ast_cli(a->fd, "%-20.20s %-10.10s %-10u %-5.5s %-10.10s %-15.15s %-30s\n",
02627          s->channame, s->tech->type, s->id,
02628          (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
02629          (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
02630          ast_fax_state_to_str(s->state), filenames);
02631 
02632       ast_free(filenames);
02633       ao2_unlock(s);
02634       ao2_ref(s, -1);
02635    }
02636    ao2_iterator_destroy(&i);
02637    session_count = ao2_container_count(faxregistry.container);
02638    ast_cli(a->fd, "\n%d FAX sessions\n\n", session_count);
02639 
02640    return CLI_SUCCESS;
02641 }

static char* cli_fax_show_settings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

display global defaults and settings

Definition at line 2486 of file res_fax.c.

References ast_cli(), ast_fax_modem_to_str(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, ast_fax_tech::cli_show_settings, CLI_SUCCESS, ast_cli_entry::command, ast_fax_tech::description, fax_options::ecm, ast_cli_args::fd, get_general_options(), fax_options::maxrate, fax_options::minrate, fax_options::modems, fax_options::statusevents, fax_module::tech, ast_fax_tech::type, and ast_cli_entry::usage.

02487 {
02488    struct fax_module *fax;
02489    char modems[128] = "";
02490    struct fax_options options;
02491 
02492    switch (cmd) {
02493    case CLI_INIT:
02494       e->command = "fax show settings";
02495       e->usage =
02496          "Usage: fax show settings\n"
02497          "       Show the global settings and defaults of both the FAX core and technology modules\n";
02498       return NULL;
02499    case CLI_GENERATE:
02500       return NULL;
02501    }
02502 
02503    get_general_options(&options);
02504 
02505    ast_cli(a->fd, "FAX For Asterisk Settings:\n");
02506    ast_cli(a->fd, "\tECM: %s\n", options.ecm ? "Enabled" : "Disabled");
02507    ast_cli(a->fd, "\tStatus Events: %s\n",  options.statusevents ? "On" : "Off");
02508    ast_cli(a->fd, "\tMinimum Bit Rate: %u\n", options.minrate);
02509    ast_cli(a->fd, "\tMaximum Bit Rate: %u\n", options.maxrate);
02510    ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02511    ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
02512    ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
02513    AST_RWLIST_RDLOCK(&faxmodules);
02514    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02515       ast_cli(a->fd, "%s (%s) Settings:\n", fax->tech->type, fax->tech->description);
02516       fax->tech->cli_show_settings(a->fd);
02517    }
02518    AST_RWLIST_UNLOCK(&faxmodules);
02519 
02520    return CLI_SUCCESS;
02521 }

static char* cli_fax_show_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

display fax stats

Definition at line 2560 of file res_fax.c.

References ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, ast_fax_tech::cli_show_stats, CLI_SUCCESS, ast_cli_entry::command, faxregistry, ast_cli_args::fd, fax_module::tech, and ast_cli_entry::usage.

02561 {
02562    struct fax_module *fax;
02563    
02564    switch (cmd) {
02565    case CLI_INIT:
02566       e->command = "fax show stats";
02567       e->usage =
02568          "Usage: fax show stats\n"
02569          "       Shows a statistical summary of FAX transmissions\n";
02570       return NULL;
02571    case CLI_GENERATE:
02572       return NULL;
02573    }
02574 
02575    ast_cli(a->fd, "\nFAX Statistics:\n---------------\n\n");
02576    ast_cli(a->fd, "%-20.20s : %d\n", "Current Sessions", faxregistry.active_sessions);
02577    ast_cli(a->fd, "%-20.20s : %d\n", "Reserved Sessions", faxregistry.reserved_sessions);
02578    ast_cli(a->fd, "%-20.20s : %d\n", "Transmit Attempts", faxregistry.fax_tx_attempts);
02579    ast_cli(a->fd, "%-20.20s : %d\n", "Receive Attempts", faxregistry.fax_rx_attempts);
02580    ast_cli(a->fd, "%-20.20s : %d\n", "Completed FAXes", faxregistry.fax_complete);
02581    ast_cli(a->fd, "%-20.20s : %d\n", "Failed FAXes", faxregistry.fax_failures);
02582    AST_RWLIST_RDLOCK(&faxmodules);
02583    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02584       fax->tech->cli_show_stats(a->fd);
02585    }
02586    AST_RWLIST_UNLOCK(&faxmodules);
02587    ast_cli(a->fd, "\n\n");
02588 
02589    return CLI_SUCCESS;
02590 }

static char* cli_fax_show_version ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2389 of file res_fax.c.

References ast_cli_args::argc, ast_cli(), ast_get_version(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_fax_tech::description, ast_cli_args::fd, fax_module::tech, ast_cli_entry::usage, and ast_fax_tech::version.

02390 {
02391    struct fax_module *fax;
02392 
02393    switch(cmd) {
02394    case CLI_INIT:
02395       e->command = "fax show version";
02396       e->usage =
02397          "Usage: fax show version\n"
02398          "       Show versions of FAX For Asterisk components.\n";
02399       return NULL;
02400    case CLI_GENERATE:
02401       return NULL;
02402    }
02403 
02404    if (a->argc != 3) {
02405       return CLI_SHOWUSAGE;
02406    }
02407 
02408    ast_cli(a->fd, "FAX For Asterisk Components:\n");
02409    ast_cli(a->fd, "\tApplications: %s\n", ast_get_version());
02410    AST_RWLIST_RDLOCK(&faxmodules);
02411    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02412       ast_cli(a->fd, "\t%s: %s\n", fax->tech->description, fax->tech->version);
02413    }
02414    AST_RWLIST_UNLOCK(&faxmodules);
02415    ast_cli(a->fd, "\n");
02416 
02417    return CLI_SUCCESS;
02418 }

static void debug_check_frame_for_silence ( struct ast_fax_session s,
unsigned int  c2s,
struct ast_frame frame 
) [static]

Definition at line 303 of file res_fax.c.

References ast_dsp_reset(), ast_dsp_silence(), ast_tvnow(), ast_tvsub(), ast_verb, ast_fax_debug_info::base_tv, ast_fax_session::channame, debug_info_history::consec_frames, debug_info_history::consec_ms, ast_fax_session::debug_info, ast_fax_debug_info::dsp, ast_fax_session::id, ast_fax_debug_info::s2c, ast_frame::samples, and debug_info_history::silence.

Referenced by generic_fax_exec().

00304 {  
00305    struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
00306    int dspsilence;
00307    unsigned int last_consec_frames, last_consec_ms;
00308    unsigned char wassil;
00309    struct timeval diff;
00310 
00311    diff = ast_tvsub(ast_tvnow(), s->debug_info->base_tv);
00312 
00313    ast_dsp_reset(s->debug_info->dsp);
00314    ast_dsp_silence(s->debug_info->dsp, frame, &dspsilence);
00315 
00316    wassil = history->silence;
00317    history->silence = (dspsilence != 0) ? 1 : 0;
00318    if (history->silence != wassil) {
00319       last_consec_frames = history->consec_frames;
00320       last_consec_ms = history->consec_ms;
00321       history->consec_frames = 0;
00322       history->consec_ms = 0;
00323 
00324       if ((last_consec_frames != 0)) {
00325          ast_verb(6, "Channel '%s' fax session '%u', [ %.3ld.%.6ld ], %s sent %u frames (%u ms) of %s.\n",
00326              s->channame, s->id, (long) diff.tv_sec, (long int) diff.tv_usec,
00327              (c2s) ? "channel" : "stack", last_consec_frames, last_consec_ms,
00328              (wassil) ? "silence" : "energy");
00329       }
00330    }
00331 
00332    history->consec_frames++;
00333    history->consec_ms += (frame->samples / 8);
00334 }

static void destroy_callback ( void *  data  )  [static]

Definition at line 336 of file res_fax.c.

References ao2_ref.

00337 {
00338    if (data) {
00339       ao2_ref(data, -1);
00340    }
00341 }

static void destroy_session ( void *  session  )  [static]

destroy a FAX session structure

Definition at line 727 of file res_fax.c.

References ao2_ref, ast_atomic_fetchadd_int(), ast_dsp_free(), AST_FAX_STATE_INACTIVE, ast_free, ast_module_unref(), ast_smoother_free(), ast_fax_session::chan_uniqueid, ast_fax_session::channame, ast_fax_session::debug_info, ast_fax_tech::destroy_session, ast_fax_session::details, ast_fax_debug_info::dsp, fax_session_release(), faxregistry, ast_fax_tech::module, ast_fax_session::smoother, ast_fax_session::state, ast_fax_session::tech, and ast_fax_session::tech_pvt.

Referenced by fax_session_new(), and fax_session_reserve().

00728 {
00729    struct ast_fax_session *s = session;
00730 
00731    if (s->tech) {
00732       fax_session_release(s, NULL);
00733       if (s->tech_pvt) {
00734          s->tech->destroy_session(s);
00735       }
00736       ast_module_unref(s->tech->module);
00737    }
00738 
00739    if (s->details) {
00740       ao2_ref(s->details, -1);
00741    }
00742    
00743    if (s->debug_info) {
00744       ast_dsp_free(s->debug_info->dsp);
00745       ast_free(s->debug_info);
00746    }
00747 
00748    if (s->smoother) {
00749       ast_smoother_free(s->smoother);
00750    }
00751 
00752    if (s->state != AST_FAX_STATE_INACTIVE) {
00753       ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
00754    }
00755 
00756    ast_free(s->channame);
00757    ast_free(s->chan_uniqueid);
00758 }

static void destroy_session_details ( void *  details  )  [static]

destroy a FAX session details structure

Definition at line 371 of file res_fax.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_fax_session_details::documents, and fax_module::next.

Referenced by session_details_new().

00372 {
00373    struct ast_fax_session_details *d = details;
00374    struct ast_fax_document *doc;
00375    
00376    while ((doc = AST_LIST_REMOVE_HEAD(&d->documents, next))) {
00377       ast_free(doc);
00378    }
00379    ast_string_field_free_memory(d); 
00380 }

static int disable_t38 ( struct ast_channel chan  )  [static]

Definition at line 1092 of file res_fax.c.

References AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FRAME_CONTROL, ast_frfree, ast_indicate_data(), ast_log(), ast_read(), ast_remaining_ms(), AST_T38_REFUSED, AST_T38_REQUEST_TERMINATE, AST_T38_TERMINATED, ast_tvnow(), ast_waitfor(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_frame::ptr, ast_control_t38_parameters::request_response, and ast_frame::subclass.

Referenced by receivefax_exec(), sendfax_exec(), and transmit_t38().

01093 {
01094    int timeout_ms;
01095    struct ast_frame *frame = NULL;
01096    struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
01097    struct timeval start;
01098    int ms;
01099 
01100    ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
01101    if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
01102       ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01103       return -1;
01104    }
01105 
01106    /* wait up to five seconds for negotiation to complete */
01107    timeout_ms = 5000;
01108    start = ast_tvnow();
01109    while ((ms = ast_remaining_ms(start, timeout_ms))) {
01110       ms = ast_waitfor(chan, ms);
01111 
01112       if (ms == 0) {
01113          break;
01114       }
01115       if (ms < 0) {
01116          ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01117          return -1;
01118       }
01119 
01120       if (!(frame = ast_read(chan))) {
01121          return -1;
01122       }
01123       if ((frame->frametype == AST_FRAME_CONTROL) &&
01124           (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01125           (frame->datalen == sizeof(t38_parameters))) {
01126          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01127 
01128          switch (parameters->request_response) {
01129          case AST_T38_TERMINATED:
01130             ast_debug(1, "Shut down T.38 on %s\n", chan->name);
01131             break;
01132          case AST_T38_REFUSED:
01133             ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", chan->name);
01134             ast_frfree(frame);
01135             return -1;
01136          default:
01137             ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", chan->name);
01138             ast_frfree(frame);
01139             return -1;
01140          }
01141          ast_frfree(frame);
01142          break;
01143       }
01144       ast_frfree(frame);
01145    }
01146 
01147    if (ms == 0) { /* all done, nothing happened */
01148       ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
01149    }
01150 
01151    return 0;
01152 }

static unsigned int fax_rate_str_to_int ( const char *  ratestr  )  [static]

convert a rate string to a rate

Definition at line 690 of file res_fax.c.

References ast_log(), LOG_ERROR, and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

00691 {
00692    int rate;
00693 
00694    if (sscanf(ratestr, "%d", &rate) != 1) {
00695       ast_log(LOG_ERROR, "failed to sscanf '%s' to rate\n", ratestr);
00696       return 0;
00697    }
00698    switch (rate) {
00699    case 2400:
00700    case 4800:
00701    case 7200:
00702    case 9600:
00703    case 12000:
00704    case 14400:
00705    case 28800:
00706    case 33600:
00707       return rate;
00708    default:
00709       ast_log(LOG_WARNING, "ignoring invalid rate '%s'.  Valid options are {2400 | 4800 | 7200 | 9600 | 12000 | 14400 | 28800 | 33600}\n", ratestr);
00710       return 0;
00711    }
00712 }

static struct ast_fax_session* fax_session_new ( struct ast_fax_session_details details,
struct ast_channel chan,
struct ast_fax_session reserved,
struct ast_fax_tech_token *  token 
) [static, read]

create a FAX session

Definition at line 810 of file res_fax.c.

References ao2_alloc, ao2_link, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_debug, ast_dsp_new(), ast_dsp_set_threshold(), ast_fax_caps_to_str(), AST_FAX_STATE_RESERVED, AST_FAX_STATE_UNINITIALIZED, AST_FAX_TECH_AUDIO, ast_free, ast_log(), ast_module_ref(), ast_module_unref(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_fax_tech::caps, ast_fax_session_details::caps, ast_fax_session::chan, ast_fax_session::chan_uniqueid, ast_fax_session::channame, ast_fax_session_details::debug, ast_fax_session::debug_info, ast_fax_tech::description, destroy_session(), ast_fax_session::details, ast_fax_debug_info::dsp, fax_session_release(), faxregistry, ast_fax_session::id, ast_fax_session_details::id, LOG_ERROR, ast_fax_tech::module, ast_fax_tech::new_session, ast_fax_session_details::option, ast_fax_session::state, ast_fax_session::tech, fax_module::tech, and ast_fax_session::tech_pvt.

Referenced by generic_fax_exec().

00811 {
00812    struct ast_fax_session *s = NULL;
00813    struct fax_module *faxmod;
00814    char caps[128] = "";
00815 
00816    if (reserved) {
00817       s = reserved;
00818       ao2_ref(reserved, +1);
00819 
00820       if (s->state == AST_FAX_STATE_RESERVED) {
00821          ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00822          s->state = AST_FAX_STATE_UNINITIALIZED;
00823       }
00824    }
00825 
00826    if (!s && !(s = ao2_alloc(sizeof(*s), destroy_session))) {
00827       return NULL;
00828    }
00829 
00830    ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
00831    s->state = AST_FAX_STATE_UNINITIALIZED;
00832 
00833    if (details->option.debug && (details->caps & AST_FAX_TECH_AUDIO)) {
00834       if (!(s->debug_info = ast_calloc(1, sizeof(*(s->debug_info))))) {
00835          fax_session_release(s, token);
00836          ao2_ref(s, -1);
00837          return NULL;
00838       }
00839       if (!(s->debug_info->dsp = ast_dsp_new())) {
00840          ast_free(s->debug_info);
00841          s->debug_info = NULL;
00842          fax_session_release(s, token);
00843          ao2_ref(s, -1);
00844          return NULL;
00845       }
00846       ast_dsp_set_threshold(s->debug_info->dsp, 128);
00847    }  
00848 
00849    if (!(s->channame = ast_strdup(chan->name))) {
00850       fax_session_release(s, token);
00851       ao2_ref(s, -1);
00852       return NULL;
00853    }
00854 
00855    if (!(s->chan_uniqueid = ast_strdup(chan->uniqueid))) {
00856       fax_session_release(s, token);
00857       ao2_ref(s, -1);
00858       return NULL;
00859    }
00860 
00861    s->chan = chan;
00862    s->details = details;
00863    ao2_ref(s->details, 1);
00864 
00865    details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
00866 
00867    if (!token) {
00868       /* locate a FAX technology module that can handle said requirements */
00869       AST_RWLIST_RDLOCK(&faxmodules);
00870       AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00871          if ((faxmod->tech->caps & details->caps) != details->caps) {
00872             continue;
00873          }
00874          ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
00875          ast_module_ref(faxmod->tech->module);
00876          if (reserved) {
00877             /* Balance module ref from reserved session */
00878             ast_module_unref(reserved->tech->module);
00879          }
00880          s->tech = faxmod->tech;
00881          break;
00882       }
00883       AST_RWLIST_UNLOCK(&faxmodules);
00884 
00885       if (!faxmod) {
00886          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)));
00887          ao2_ref(s, -1);
00888          return NULL;
00889       }
00890    }
00891 
00892    if (!(s->tech_pvt = s->tech->new_session(s, token))) {
00893       ast_log(LOG_ERROR, "FAX session failed to initialize.\n");
00894       ao2_ref(s, -1);
00895       return NULL;
00896    }
00897    /* link the session to the session container */
00898    if (!(ao2_link(faxregistry.container, s))) {
00899       ast_log(LOG_ERROR, "failed to add FAX session '%u' to container.\n", s->id);
00900       ao2_ref(s, -1);
00901       return NULL;
00902    }
00903    ast_debug(4, "channel '%s' using FAX session '%u'\n", s->channame, s->id);
00904 
00905    return s;
00906 }

static void fax_session_release ( struct ast_fax_session s,
struct ast_fax_tech_token *  token 
) [static]

Definition at line 714 of file res_fax.c.

References ast_atomic_fetchadd_int(), AST_FAX_STATE_INACTIVE, AST_FAX_STATE_RESERVED, faxregistry, ast_fax_tech::release_token, ast_fax_session::state, and ast_fax_session::tech.

Referenced by destroy_session(), fax_session_new(), receivefax_exec(), and sendfax_exec().

00715 {
00716    if (token) {
00717       s->tech->release_token(token);
00718    }
00719 
00720    if (s->state == AST_FAX_STATE_RESERVED) {
00721       ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00722       s->state = AST_FAX_STATE_INACTIVE;
00723    }
00724 }

static struct ast_fax_session* fax_session_reserve ( struct ast_fax_session_details details,
struct ast_fax_tech_token **  token 
) [static, read]

Definition at line 760 of file res_fax.c.

References ao2_alloc, ao2_ref, ast_atomic_fetchadd_int(), ast_debug, ast_fax_caps_to_str(), AST_FAX_STATE_INACTIVE, AST_FAX_STATE_RESERVED, ast_log(), ast_module_ref(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_fax_session_details::caps, ast_fax_tech::caps, ast_fax_tech::description, destroy_session(), faxregistry, LOG_ERROR, ast_fax_tech::module, ast_fax_tech::reserve_session, ast_fax_session::state, ast_fax_session::tech, and fax_module::tech.

Referenced by receivefax_exec(), and sendfax_exec().

00761 {
00762    struct ast_fax_session *s;
00763    struct fax_module *faxmod;
00764    char caps[128] = "";
00765 
00766    if (!(s = ao2_alloc(sizeof(*s), destroy_session))) {
00767       return NULL;
00768    }
00769 
00770    s->state = AST_FAX_STATE_INACTIVE;
00771 
00772    /* locate a FAX technology module that can handle said requirements
00773     * Note: the requirements have not yet been finalized as T.38
00774     * negotiation has not yet occured. */
00775    AST_RWLIST_RDLOCK(&faxmodules);
00776    AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00777       if ((faxmod->tech->caps & details->caps) != details->caps) {
00778          continue;
00779       }
00780       ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
00781       ast_module_ref(faxmod->tech->module);
00782       s->tech = faxmod->tech;
00783       break;
00784    }
00785    AST_RWLIST_UNLOCK(&faxmodules);
00786 
00787    if (!faxmod) {
00788       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)));
00789       ao2_ref(s, -1);
00790       return NULL;
00791    }
00792 
00793    if (!s->tech->reserve_session) {
00794       ast_debug(1, "Selected FAX technology module (%s) does not support reserving sessions.\n", s->tech->description);
00795       return s;
00796    }
00797 
00798    if (!(*token = s->tech->reserve_session(s))) {
00799       ao2_ref(s, -1);
00800       return NULL;
00801    }
00802 
00803    s->state = AST_FAX_STATE_RESERVED;
00804    ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, 1);
00805 
00806    return s;
00807 }

static char* fax_session_tab_complete ( struct ast_cli_args a  )  [static]

fax session tab completion

Definition at line 2361 of file res_fax.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, faxregistry, ast_fax_session::id, ast_cli_args::n, name, ast_cli_args::pos, and ast_cli_args::word.

Referenced by cli_fax_show_session().

02362 {
02363    int tklen;
02364    int wordnum = 0;
02365    char *name = NULL;
02366    struct ao2_iterator i;
02367    struct ast_fax_session *s;
02368    char tbuf[5];
02369 
02370    if (a->pos != 3) {
02371       return NULL;
02372    }
02373 
02374    tklen = strlen(a->word);
02375    i = ao2_iterator_init(faxregistry.container, 0);
02376    while ((s = ao2_iterator_next(&i))) {
02377       snprintf(tbuf, sizeof(tbuf), "%u", s->id);
02378       if (!strncasecmp(a->word, tbuf, tklen) && ++wordnum > a->n) {
02379          name = ast_strdup(tbuf);
02380          ao2_ref(s, -1);
02381          break;
02382       }
02383       ao2_ref(s, -1);
02384    }
02385    ao2_iterator_destroy(&i);
02386    return name;
02387 }

static struct ast_fax_session_details* find_details ( struct ast_channel chan  )  [static, read]

returns a reference counted pointer to a fax datastore, if it exists

Definition at line 349 of file res_fax.c.

References ao2_ref, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_log(), ast_datastore::data, fax_datastore, and LOG_WARNING.

Referenced by acf_faxopt_read(), and find_or_create_details().

00350 {
00351    struct ast_fax_session_details *details;
00352    struct ast_datastore *datastore;
00353 
00354    ast_channel_lock(chan); 
00355    if (!(datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL))) {
00356       ast_channel_unlock(chan);  
00357       return NULL;
00358    }
00359    if (!(details = datastore->data)) {
00360       ast_log(LOG_WARNING, "Huh?  channel '%s' has a FAX datastore without data!\n", chan->name);
00361       ast_channel_unlock(chan);
00362       return NULL;
00363    }
00364    ao2_ref(details, 1); 
00365    ast_channel_unlock(chan);  
00366 
00367    return details;
00368 }

static struct ast_fax_session_details* find_or_create_details ( struct ast_channel chan  )  [static, read]

returns a reference counted details structure from the channel's fax datastore. If the datastore does not exist it will be created

Definition at line 417 of file res_fax.c.

References ao2_ref, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), ast_datastore::data, fax_datastore, find_details(), LOG_WARNING, and session_details_new().

Referenced by acf_faxopt_write(), receivefax_exec(), and sendfax_exec().

00418 {
00419    struct ast_fax_session_details *details;
00420    struct ast_datastore *datastore;
00421 
00422    if ((details = find_details(chan))) {
00423       return details;
00424    }
00425    /* channel does not have one so we must create one */
00426    if (!(details = session_details_new())) {
00427       ast_log(LOG_WARNING, "channel '%s' can't get a FAX details structure for the datastore!\n", chan->name);
00428       return NULL;
00429    }
00430    if (!(datastore = ast_datastore_alloc(&fax_datastore, NULL))) {
00431       ao2_ref(details, -1);
00432       ast_log(LOG_WARNING, "channel '%s' can't get a datastore!\n", chan->name);
00433       return NULL;
00434    }
00435    /* add the datastore to the channel and increment the refcount */
00436    datastore->data = details;
00437    ao2_ref(details, 1);
00438    ast_channel_lock(chan);
00439    ast_channel_datastore_add(chan, datastore);
00440    ast_channel_unlock(chan);
00441    return details;
00442 }

static char* generate_filenames_string ( struct ast_fax_session_details details,
char *  prefix,
char *  separator 
) [static]

Definition at line 927 of file res_fax.c.

References ast_build_string(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_TRAVERSE, ast_malloc, ast_fax_session_details::documents, ast_fax_document::filename, first, and fax_module::next.

Referenced by acf_faxopt_read(), cli_fax_show_sessions(), report_fax_status(), and sendfax_exec().

00928 {
00929    char *filenames, *c;
00930    size_t size = 0;
00931    int first = 1;
00932    struct ast_fax_document *doc;
00933 
00934    /* don't process empty lists */
00935    if (AST_LIST_EMPTY(&details->documents)) {
00936       return NULL;
00937    }
00938 
00939    /* Calculate the total length of all of the file names */
00940    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00941       size += strlen(separator) + strlen(prefix) + strlen(doc->filename);
00942    }
00943    size += 1; /* add space for the terminating null */
00944 
00945    if (!(filenames = ast_malloc(size))) {
00946       return NULL;
00947    }
00948    c = filenames;
00949 
00950    ast_build_string(&c, &size, "%s%s", prefix, AST_LIST_FIRST(&details->documents)->filename);
00951    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00952       if (first) {
00953          first = 0;
00954          continue;
00955       }
00956 
00957       ast_build_string(&c, &size, "%s%s%s", separator, prefix, doc->filename);
00958    }
00959 
00960    return filenames;
00961 }

static int generic_fax_exec ( struct ast_channel chan,
struct ast_fax_session_details details,
struct ast_fax_session reserved,
struct ast_fax_tech_token *  token 
) [static]

this is the generic FAX session handling function

Definition at line 1162 of file res_fax.c.

References ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_atomic_fetchadd_int(), ast_channel_get_t38_state(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FAX_TECH_AUDIO, AST_FAX_TECH_T38, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_MODEM, AST_FRAME_VOICE, ast_frfree, ast_indicate_data(), ast_log(), AST_MODEM_T38, ast_read(), ast_remaining_ms(), ast_set_read_format(), ast_set_write_format(), ast_smoother_feed, ast_smoother_free(), ast_smoother_new(), ast_smoother_read(), ast_string_field_set, ast_strlen_zero(), AST_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, ast_tvnow(), ast_verb, ast_waitfor_nandfds(), ast_write(), ast_fax_debug_info::base_tv, ast_fax_tech::cancel_session, ast_fax_session_details::caps, chancount, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, debug_check_frame_for_silence(), ast_fax_session::debug_info, errno, f, fax_session_new(), faxregistry, ast_fax_session::fd, ast_fax_session::frames_received, ast_fax_session::frames_sent, ast_frame::frametype, ast_fax_tech::generate_silence, GENERIC_FAX_EXEC_ERROR, GENERIC_FAX_EXEC_SET_VARS, ast_fax_session::id, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_fax_session_details::our_t38_parameters, pbx_builtin_getvar_helper(), ast_frame::ptr, ast_fax_tech::read, ast_channel::readformat, report_fax_status(), ast_control_t38_parameters::request_response, RES_FAX_TIMEOUT, set_channel_variables(), ast_fax_session::smoother, ast_fax_tech::start_session, ast_frame::subclass, ast_fax_tech::switch_to_t38, t38_parameters_ast_to_fax(), t38_parameters_fax_to_ast(), T38_STATE_NEGOTIATED, ast_fax_session::tech, ast_fax_session_details::their_t38_parameters, ast_fax_tech::write, and ast_channel::writeformat.

Referenced by receivefax_exec(), and sendfax_exec().

01163 {
01164    int ms;
01165    int timeout = RES_FAX_TIMEOUT;
01166    int chancount;
01167    unsigned int expected_frametype = -1;
01168    union ast_frame_subclass expected_framesubclass = { .integer = -1 };
01169    unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
01170    struct ast_control_t38_parameters t38_parameters;
01171    const char *tempvar;
01172    struct ast_fax_session *fax = NULL;
01173    struct ast_frame *frame = NULL;
01174    struct ast_channel *c = chan;
01175    unsigned int orig_write_format = 0, orig_read_format = 0;
01176    int remaining_time;
01177    struct timeval start;
01178 
01179    chancount = 1;
01180 
01181    /* create the FAX session */
01182    if (!(fax = fax_session_new(details, chan, reserved, token))) {
01183       ast_log(LOG_ERROR, "Can't create a FAX session, FAX attempt failed.\n");
01184       report_fax_status(chan, details, "No Available Resource");
01185       return -1;
01186    }
01187 
01188    ast_channel_lock(chan);
01189    /* update session details */  
01190    if (ast_strlen_zero(details->headerinfo) && (tempvar = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"))) {
01191       ast_string_field_set(details, headerinfo, tempvar);
01192    }
01193    if (ast_strlen_zero(details->localstationid)) {
01194       tempvar = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
01195       ast_string_field_set(details, localstationid, tempvar ? tempvar : "unknown");
01196    }
01197    ast_channel_unlock(chan);
01198 
01199    report_fax_status(chan, details, "Allocating Resources");
01200 
01201    if (details->caps & AST_FAX_TECH_AUDIO) {
01202       expected_frametype = AST_FRAME_VOICE;;
01203       expected_framesubclass.codec = AST_FORMAT_SLINEAR;
01204       orig_write_format = chan->writeformat;
01205       if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01206          ast_log(LOG_ERROR, "channel '%s' failed to set write format to signed linear'.\n", chan->name);
01207          ao2_lock(faxregistry.container);
01208          ao2_unlink(faxregistry.container, fax);
01209          ao2_unlock(faxregistry.container);
01210          ao2_ref(fax, -1);
01211          ast_channel_unlock(chan);
01212          return -1;
01213       }
01214       orig_read_format = chan->readformat;
01215       if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01216          ast_log(LOG_ERROR, "channel '%s' failed to set read format to signed linear.\n", chan->name);
01217          ao2_lock(faxregistry.container);
01218          ao2_unlink(faxregistry.container, fax);
01219          ao2_unlock(faxregistry.container);
01220          ao2_ref(fax, -1);
01221          ast_channel_unlock(chan);
01222          return -1;
01223       }
01224       if (fax->smoother) {
01225          ast_smoother_free(fax->smoother);
01226          fax->smoother = NULL;
01227       }
01228       if (!(fax->smoother = ast_smoother_new(320))) {
01229          ast_log(LOG_WARNING, "Channel '%s' FAX session '%u' failed to obtain a smoother.\n", chan->name, fax->id);
01230       }
01231    } else {
01232       expected_frametype = AST_FRAME_MODEM;
01233       expected_framesubclass.codec = AST_MODEM_T38;
01234    }
01235 
01236    if (fax->debug_info) {
01237       fax->debug_info->base_tv = ast_tvnow();
01238    }
01239 
01240    /* reset our result fields just in case the fax tech driver wants to
01241     * set custom error messages */
01242    ast_string_field_set(details, result, "");
01243    ast_string_field_set(details, resultstr, "");
01244    ast_string_field_set(details, error, "");
01245    set_channel_variables(chan, details);
01246 
01247    if (fax->tech->start_session(fax) < 0) {
01248       GENERIC_FAX_EXEC_ERROR(fax, chan, "INIT_ERROR", "failed to start FAX session");
01249    }
01250 
01251    report_fax_status(chan, details, "FAX Transmission In Progress");
01252 
01253    ast_debug(5, "channel %s will wait on FAX fd %d\n", chan->name, fax->fd);
01254 
01255    /* handle frames for the session */
01256    remaining_time = timeout;
01257    start = ast_tvnow();
01258    while (remaining_time > 0) {
01259       struct ast_channel *ready_chan;
01260       int ofd, exception;
01261 
01262       ms = 1000;
01263       errno = 0;
01264       ready_chan = ast_waitfor_nandfds(&c, chancount, &fax->fd, 1, &exception, &ofd, &ms);
01265       if (ready_chan) {
01266          if (!(frame = ast_read(chan))) {
01267             /* the channel is probably gone, so lets stop polling on it and let the
01268              * FAX session complete before we exit the application.  if needed,
01269              * send the FAX stack silence so the modems can finish their session without
01270              * any problems */
01271             ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", chan->name);
01272             GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
01273             c = NULL;
01274             chancount = 0;
01275             remaining_time = ast_remaining_ms(start, timeout);
01276             fax->tech->cancel_session(fax);
01277             if (fax->tech->generate_silence) {
01278                fax->tech->generate_silence(fax);
01279             }
01280             continue;
01281          }
01282 
01283          if ((frame->frametype == AST_FRAME_CONTROL) &&
01284              (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01285              (frame->datalen == sizeof(t38_parameters))) {
01286             unsigned int was_t38 = t38negotiated;
01287             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01288             
01289             switch (parameters->request_response) {
01290             case AST_T38_REQUEST_NEGOTIATE:
01291                /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01292                 * do T.38 as well
01293                 */
01294                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01295                t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01296                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01297                break;
01298             case AST_T38_NEGOTIATED:
01299                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01300                t38negotiated = 1;
01301                break;
01302             default:
01303                break;
01304             }
01305             if (t38negotiated && !was_t38) {
01306                fax->tech->switch_to_t38(fax);
01307                details->caps &= ~AST_FAX_TECH_AUDIO;
01308                expected_frametype = AST_FRAME_MODEM;
01309                expected_framesubclass.codec = AST_MODEM_T38;
01310                if (fax->smoother) {
01311                   ast_smoother_free(fax->smoother);
01312                   fax->smoother = NULL;
01313                }
01314                
01315                report_fax_status(chan, details, "T.38 Negotiated");
01316                
01317                ast_verb(3, "Channel '%s' switched to T.38 FAX session '%u'.\n", chan->name, fax->id);
01318             }
01319          } else if ((frame->frametype == expected_frametype) &&
01320                (!memcmp(&frame->subclass, &expected_framesubclass, sizeof(frame->subclass)))) {
01321             struct ast_frame *f;
01322             
01323             if (fax->smoother) {
01324                /* push the frame into a smoother */
01325                if (ast_smoother_feed(fax->smoother, frame) < 0) {
01326                   GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "Failed to feed the smoother");
01327                }
01328                while ((f = ast_smoother_read(fax->smoother)) && (f->data.ptr)) {
01329                   if (fax->debug_info) {
01330                      debug_check_frame_for_silence(fax, 1, f);
01331                   }
01332                   /* write the frame to the FAX stack */
01333                   fax->tech->write(fax, f);
01334                   fax->frames_received++;
01335                   if (f != frame) {
01336                      ast_frfree(f);
01337                   }
01338                }
01339             } else {
01340                /* write the frame to the FAX stack */
01341                fax->tech->write(fax, frame);
01342                fax->frames_received++;
01343             }
01344             start = ast_tvnow();
01345          }
01346          ast_frfree(frame);
01347       } else if (ofd == fax->fd) {
01348          /* read a frame from the FAX stack and send it out the channel.
01349           * the FAX stack will return a NULL if the FAX session has already completed */
01350          if (!(frame = fax->tech->read(fax))) {
01351             break;
01352          }
01353 
01354          if (fax->debug_info && (frame->frametype == AST_FRAME_VOICE)) {
01355             debug_check_frame_for_silence(fax, 0, frame);
01356          }
01357 
01358          ast_write(chan, frame);
01359          fax->frames_sent++;
01360          ast_frfree(frame);
01361          start = ast_tvnow();
01362       } else {
01363          if (ms && (ofd < 0)) {
01364             if ((errno == 0) || (errno == EINTR)) {
01365                remaining_time = ast_remaining_ms(start, timeout);
01366                if (remaining_time <= 0)
01367                   GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
01368                continue;
01369             } else {
01370                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
01371                GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data");
01372                break;
01373             }
01374          } else {
01375             /* nothing happened */
01376             remaining_time = ast_remaining_ms(start, timeout);
01377             if (remaining_time <= 0) {
01378                GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
01379                break;
01380             }
01381          }
01382       }
01383    }
01384    ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", chan->name, timeout, remaining_time);
01385 
01386    set_channel_variables(chan, details);
01387 
01388    if (!strcasecmp(details->result, "FAILED")) {
01389       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01390    } else {
01391       ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1);
01392    }
01393 
01394    if (fax) {
01395       ao2_lock(faxregistry.container);
01396       ao2_unlink(faxregistry.container, fax);
01397       ao2_unlock(faxregistry.container);
01398       ao2_ref(fax, -1);
01399    }
01400 
01401    /* if the channel is still alive, and we changed its read/write formats,
01402     * restore them now
01403     */
01404    if (chancount) {
01405       if (orig_read_format) {
01406          ast_set_read_format(chan, orig_read_format);
01407       }
01408       if (orig_write_format) {
01409          ast_set_write_format(chan, orig_write_format);
01410       }
01411    }
01412 
01413    /* return the chancount so the calling function can determine if the channel hungup during this FAX session or not */
01414    return chancount;
01415 }

static void get_general_options ( struct fax_options options  )  [static]
static void get_manager_event_info ( struct ast_channel chan,
struct manager_event_info info 
) [static]

Definition at line 908 of file res_fax.c.

References manager_event_info::cid, manager_event_info::context, manager_event_info::exten, and pbx_substitute_variables_helper().

Referenced by receivefax_exec(), report_fax_status(), and sendfax_exec().

00909 {
00910    pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
00911    pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
00912    pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
00913 }

static int load_module ( void   )  [static]

load res_fax

Definition at line 2920 of file res_fax.c.

References acf_faxopt, ao2_container_alloc, ao2_ref, ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_log(), ast_logger_register_level(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, ast_unregister_application(), config, fax_cli, FAX_MAXBUCKETS, faxregistry, LOG_ERROR, LOG_WARNING, receivefax_exec(), sendfax_exec(), session_cmp_cb(), session_hash_cb(), and set_config().

02921 {
02922    int res;
02923 
02924    /* initialize the registry */
02925    faxregistry.active_sessions = 0;
02926    faxregistry.reserved_sessions = 0;
02927    if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
02928       return AST_MODULE_LOAD_DECLINE;
02929    }
02930    
02931    if (set_config(0) < 0) {
02932       ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
02933       ao2_ref(faxregistry.container, -1);
02934       return AST_MODULE_LOAD_DECLINE;
02935    }
02936 
02937    /* register CLI operations and applications */
02938    if (ast_register_application_xml(app_sendfax, sendfax_exec) < 0) {
02939       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_sendfax);
02940       ao2_ref(faxregistry.container, -1);
02941       return AST_MODULE_LOAD_DECLINE;
02942    }
02943    if (ast_register_application_xml(app_receivefax, receivefax_exec) < 0) {
02944       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_receivefax);
02945       ast_unregister_application(app_sendfax);
02946       ao2_ref(faxregistry.container, -1);
02947       return AST_MODULE_LOAD_DECLINE;
02948    }
02949    ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
02950    res = ast_custom_function_register(&acf_faxopt);   
02951    fax_logger_level = ast_logger_register_level("FAX");
02952 
02953    return res;
02954 }

static int receivefax_exec ( struct ast_channel chan,
const char *  data 
) [static]

initiate a receive FAX session

Definition at line 1579 of file res_fax.c.

References ast_channel::_state, ast_fax_session_details::allow_audio, ao2_ref, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_calloc, ast_channel_get_t38_state(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_DECLARE_APP_ARGS, ast_fax_modem_to_str(), AST_FAX_OPTFLAG_TRUE, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_T38, AST_LIST_INSERT_TAIL, ast_log(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_verb, ast_fax_session_details::caps, check_modem_rate(), manager_event_info::cid, manager_event_info::context, ast_fax_session_details::debug, disable_t38(), ast_fax_session_details::documents, EVENT_FLAG_CALL, manager_event_info::exten, fax_exec_options, fax_session_release(), fax_session_reserve(), faxregistry, ast_fax_document::filename, find_or_create_details(), generic_fax_exec(), get_manager_event_info(), global_fax_debug, LOG_ERROR, LOG_WARNING, manager_event, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, fax_module::next, OPT_ALLOWAUDIO, OPT_CALLEDMODE, OPT_CALLERMODE, OPT_DEBUG, OPT_STATUS, ast_fax_session_details::option, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), receivefax_t38_init(), S_OR, ast_fax_session_details::send_ced, set_channel_variables(), set_fax_t38_caps(), ast_fax_session_details::statusevents, T38_STATE_NEGOTIATED, and T38_STATE_UNAVAILABLE.

Referenced by load_module().

01580 {
01581    char *parse, modems[128] = "";
01582    int channel_alive;
01583    struct ast_fax_session_details *details;
01584    struct ast_fax_session *s;
01585    struct ast_fax_tech_token *token = NULL;
01586    struct ast_fax_document *doc;
01587    AST_DECLARE_APP_ARGS(args,
01588       AST_APP_ARG(filename);
01589       AST_APP_ARG(options);
01590    );
01591    struct ast_flags opts = { 0, };
01592    struct manager_event_info info;
01593 
01594    /* initialize output channel variables */
01595    pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
01596    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL);
01597    pbx_builtin_setvar_helper(chan, "FAXPAGES", "0");
01598    pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL);
01599    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL);
01600 
01601    /* if we ran receivefax then we attempted to receive a fax, even if we
01602     * never start a fax session */
01603    ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1);
01604 
01605    /* Get a FAX session details structure from the channel's FAX datastore and create one if
01606     * it does not already exist. */
01607    if (!(details = find_or_create_details(chan))) {
01608       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01609       pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR");
01610       pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory");
01611       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
01612       return -1;
01613    }
01614 
01615    ast_string_field_set(details, result, "FAILED");
01616    ast_string_field_set(details, resultstr, "error starting fax session");
01617    ast_string_field_set(details, error, "INIT_ERROR");
01618    set_channel_variables(chan, details);
01619 
01620    if (details->maxrate < details->minrate) {
01621       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01622       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01623       ast_string_field_set(details, resultstr, "maxrate is less than minrate");
01624       set_channel_variables(chan, details);
01625       ast_log(LOG_ERROR, "maxrate %u is less than minrate %u\n", details->maxrate, details->minrate);
01626       ao2_ref(details, -1);
01627       return -1;
01628    }
01629 
01630    if (check_modem_rate(details->modems, details->minrate)) {
01631       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01632       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
01633       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %u\n", modems, details->minrate);
01634       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01635       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
01636       set_channel_variables(chan, details);
01637       ao2_ref(details, -1);
01638       return -1;
01639    }
01640 
01641    if (check_modem_rate(details->modems, details->maxrate)) {
01642       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01643       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
01644       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %u\n", modems, details->maxrate);
01645       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01646       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
01647       set_channel_variables(chan, details);
01648       ao2_ref(details, -1);
01649       return -1;
01650    }
01651 
01652    if (ast_strlen_zero(data)) {
01653       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01654       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01655       ast_string_field_set(details, resultstr, "invalid arguments");
01656       set_channel_variables(chan, details);
01657       ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
01658       ao2_ref(details, -1);
01659       return -1;
01660    }
01661    parse = ast_strdupa(data);
01662    AST_STANDARD_APP_ARGS(args, parse);
01663 
01664    if (!ast_strlen_zero(args.options) &&
01665        ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
01666       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01667       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01668       ast_string_field_set(details, resultstr, "invalid arguments");
01669       set_channel_variables(chan, details);
01670       ao2_ref(details, -1);
01671       return -1;
01672    }
01673    if (ast_strlen_zero(args.filename)) {
01674       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01675       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01676       ast_string_field_set(details, resultstr, "invalid arguments");
01677       set_channel_variables(chan, details);
01678       ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
01679       ao2_ref(details, -1);
01680       return -1;
01681    }
01682 
01683    /* check for unsupported FAX application options */
01684    if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) {
01685       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01686       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01687       ast_string_field_set(details, resultstr, "invalid arguments");
01688       set_channel_variables(chan, details);
01689       ast_log(LOG_WARNING, "%s does not support polling\n", app_receivefax);
01690       ao2_ref(details, -1);
01691       return -1;
01692    }
01693 
01694    pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems");
01695    pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Error before FAX transmission started.");
01696 
01697    if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(args.filename) + 1))) {
01698       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01699       ast_string_field_set(details, error, "MEMORY_ERROR");
01700       ast_string_field_set(details, resultstr, "error allocating memory");
01701       set_channel_variables(chan, details);
01702       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
01703       ao2_ref(details, -1);
01704       return -1;
01705    }
01706 
01707    strcpy(doc->filename, args.filename);
01708    AST_LIST_INSERT_TAIL(&details->documents, doc, next);
01709 
01710    ast_verb(3, "Channel '%s' receiving FAX '%s'\n", chan->name, args.filename);
01711 
01712    details->caps = AST_FAX_TECH_RECEIVE;
01713    details->option.send_ced = AST_FAX_OPTFLAG_TRUE;
01714 
01715    /* check for debug */
01716    if (ast_test_flag(&opts, OPT_DEBUG) || global_fax_debug) {
01717       details->option.debug = AST_FAX_OPTFLAG_TRUE;
01718    }
01719 
01720    /* check for request for status events */
01721    if (ast_test_flag(&opts, OPT_STATUS)) {
01722       details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
01723    }
01724 
01725    if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
01726        ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
01727       details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
01728    }
01729 
01730    if (!(s = fax_session_reserve(details, &token))) {
01731       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01732       ast_string_field_set(details, resultstr, "error reserving fax session");
01733       set_channel_variables(chan, details);
01734       ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
01735       ao2_ref(details, -1);
01736       return -1;
01737    }
01738 
01739    /* make sure the channel is up */
01740    if (chan->_state != AST_STATE_UP) {
01741       if (ast_answer(chan)) {
01742          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01743          ast_string_field_set(details, resultstr, "error answering channel");
01744          set_channel_variables(chan, details);
01745          ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
01746          fax_session_release(s, token);
01747          ao2_ref(s, -1);
01748          ao2_ref(details, -1);
01749          return -1;
01750       }
01751    }
01752 
01753    if (set_fax_t38_caps(chan, details)) {
01754       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01755       ast_string_field_set(details, error, "T38_NEG_ERROR");
01756       ast_string_field_set(details, resultstr, "error negotiating T.38");
01757       set_channel_variables(chan, details);
01758       fax_session_release(s, token);
01759       ao2_ref(s, -1);
01760       ao2_ref(details, -1);
01761       return -1;
01762    }
01763 
01764    if (details->caps & AST_FAX_TECH_T38) {
01765       if (receivefax_t38_init(chan, details)) {
01766          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01767          ast_string_field_set(details, error, "T38_NEG_ERROR");
01768          ast_string_field_set(details, resultstr, "error negotiating T.38");
01769          set_channel_variables(chan, details);
01770          fax_session_release(s, token);
01771          ao2_ref(s, -1);
01772          ao2_ref(details, -1);
01773          ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
01774          return -1;
01775       }
01776    }
01777 
01778    if ((channel_alive = generic_fax_exec(chan, details, s, token)) < 0) {
01779       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01780    }
01781 
01782    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01783       if (disable_t38(chan)) {
01784          ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
01785       }
01786    }
01787 
01788    /* send out the AMI completion event */
01789    ast_channel_lock(chan);
01790 
01791    get_manager_event_info(chan, &info);
01792    manager_event(EVENT_FLAG_CALL,
01793             "ReceiveFAX", 
01794             "Channel: %s\r\n"
01795             "Context: %s\r\n"
01796             "Exten: %s\r\n"
01797             "CallerID: %s\r\n"
01798             "RemoteStationID: %s\r\n"
01799             "LocalStationID: %s\r\n"
01800             "PagesTransferred: %s\r\n"
01801             "Resolution: %s\r\n"
01802             "TransferRate: %s\r\n"
01803             "FileName: %s\r\n",
01804             chan->name,
01805             info.context,
01806             info.exten,
01807             info.cid,
01808             S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
01809             S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
01810             S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
01811             S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
01812             S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
01813             args.filename);
01814    ast_channel_unlock(chan);
01815 
01816    ao2_ref(s, -1);
01817    ao2_ref(details, -1);
01818 
01819    /* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
01820    return (!channel_alive) ? -1 : 0;
01821 }

static int receivefax_t38_init ( struct ast_channel chan,
struct ast_fax_session_details details 
) [static]

Definition at line 1417 of file res_fax.c.

References ast_fax_session_details::allow_audio, ast_channel_get_t38_state(), AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FAX_OPTFLAG_TRUE, AST_FAX_TECH_AUDIO, AST_FAX_TECH_T38, AST_FRAME_CONTROL, ast_frfree, ast_indicate_data(), ast_log(), ast_playtones_start(), ast_playtones_stop(), ast_read(), ast_remaining_ms(), AST_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, ast_tvnow(), ast_waitfor(), ast_fax_session_details::caps, ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_fax_session_details::option, our_t38_parameters, ast_fax_session_details::our_t38_parameters, ast_frame::ptr, report_fax_status(), ast_control_t38_parameters::request_response, ast_frame::subclass, t38_parameters_ast_to_fax(), t38_parameters_fax_to_ast(), T38_STATE_NEGOTIATED, T38_STATE_NEGOTIATING, and ast_fax_session_details::their_t38_parameters.

Referenced by receivefax_exec().

01418 {
01419    int timeout_ms;
01420    struct ast_frame *frame = NULL;
01421    struct ast_control_t38_parameters t38_parameters;
01422    struct timeval start;
01423    int ms;
01424 
01425    t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
01426 
01427    /* don't send any audio if we've already received a T.38 reinvite */
01428    if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
01429       /* generate 3 seconds of CED */
01430       if (ast_playtones_start(chan, 1024, "!2100/3000", 1)) {
01431          ast_log(LOG_ERROR, "error generating CED tone on %s\n", chan->name);
01432          return -1;
01433       }
01434 
01435       timeout_ms = 3000;
01436       start = ast_tvnow();
01437       while ((ms = ast_remaining_ms(start, timeout_ms))) {
01438          ms = ast_waitfor(chan, ms);
01439 
01440          if (ms < 0) {
01441             ast_log(LOG_ERROR, "error while generating CED tone on %s\n", chan->name);
01442             ast_playtones_stop(chan);
01443             return -1;
01444          }
01445 
01446          if (ms == 0) { /* all done, nothing happened */
01447             break;
01448          }
01449 
01450          if (!(frame = ast_read(chan))) {
01451             ast_log(LOG_ERROR, "error reading frame while generating CED tone on %s\n", chan->name);
01452             ast_playtones_stop(chan);
01453             return -1;
01454          }
01455 
01456          if ((frame->frametype == AST_FRAME_CONTROL) &&
01457              (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01458              (frame->datalen == sizeof(t38_parameters))) {
01459             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01460 
01461             switch (parameters->request_response) {
01462             case AST_T38_REQUEST_NEGOTIATE:
01463                /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01464                 * do T.38 as well
01465                 */
01466                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01467                t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01468                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01469                ast_playtones_stop(chan);
01470                break;
01471             case AST_T38_NEGOTIATED:
01472                ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01473                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01474                details->caps &= ~AST_FAX_TECH_AUDIO;
01475                report_fax_status(chan, details, "T.38 Negotiated");
01476                break;
01477             default:
01478                break;
01479             }
01480          }
01481          ast_frfree(frame);
01482       }
01483 
01484       ast_playtones_stop(chan);
01485    }
01486 
01487    /* if T.38 was negotiated, we are done initializing */
01488    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01489       return 0;
01490    }
01491 
01492    /* request T.38 */
01493    ast_debug(1, "Negotiating T.38 for receive on %s\n", chan->name);
01494 
01495    /* wait up to five seconds for negotiation to complete */
01496    timeout_ms = 5000;
01497 
01498    /* set parameters based on the session's parameters */
01499    t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01500    t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
01501    if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
01502       return -1;
01503    }
01504 
01505    start = ast_tvnow();
01506    while ((ms = ast_remaining_ms(start, timeout_ms))) {
01507       int break_loop = 0;
01508 
01509       ms = ast_waitfor(chan, ms);
01510       if (ms < 0) {
01511          ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01512          return -1;
01513       }
01514       if (ms == 0) { /* all done, nothing happened */
01515          ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
01516          details->caps &= ~AST_FAX_TECH_T38;
01517          break;
01518       }
01519 
01520       if (!(frame = ast_read(chan))) {
01521          ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01522          return -1;
01523       }
01524 
01525       if ((frame->frametype == AST_FRAME_CONTROL) &&
01526             (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01527             (frame->datalen == sizeof(t38_parameters))) {
01528          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01529 
01530          switch (parameters->request_response) {
01531          case AST_T38_REQUEST_NEGOTIATE:
01532             t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01533             t38_parameters.request_response = AST_T38_NEGOTIATED;
01534             ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01535             break;
01536          case AST_T38_NEGOTIATED:
01537             ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01538             t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01539             details->caps &= ~AST_FAX_TECH_AUDIO;
01540             report_fax_status(chan, details, "T.38 Negotiated");
01541             break_loop = 1;
01542             break;
01543          case AST_T38_REFUSED:
01544             ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
01545             details->caps &= ~AST_FAX_TECH_T38;
01546             break_loop = 1;
01547             break;
01548          default:
01549             ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
01550             details->caps &= ~AST_FAX_TECH_T38;
01551             break_loop = 1;
01552             break;
01553          }
01554       }
01555       ast_frfree(frame);
01556       if (break_loop) {
01557          break;
01558       }
01559    }
01560 
01561    /* if T.38 was negotiated, we are done initializing */
01562    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01563       return 0;
01564    }
01565 
01566    /* if we made it here, then T.38 failed, check the 'f' flag */
01567    if (details->option.allow_audio != AST_FAX_OPTFLAG_TRUE) {
01568       ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
01569       return -1;
01570    }
01571 
01572    /* ok, audio fallback is allowed */
01573    details->caps |= AST_FAX_TECH_AUDIO;
01574 
01575    return 0;
01576 }

static int reload_module ( void   )  [static]

Definition at line 2956 of file res_fax.c.

References set_config().

02957 {
02958    set_config(1);
02959    return 0;
02960 }

static int report_fax_status ( struct ast_channel chan,
struct ast_fax_session_details details,
const char *  status 
) [static]

send a FAX status manager event

Definition at line 964 of file res_fax.c.

References ast_channel_lock, ast_channel_unlock, AST_FAX_TECH_RECEIVE, ast_free, ast_fax_session_details::caps, manager_event_info::cid, manager_event_info::context, EVENT_FLAG_CALL, manager_event_info::exten, generate_filenames_string(), get_manager_event_info(), manager_event, ast_fax_session_details::option, and ast_fax_session_details::statusevents.

Referenced by generic_fax_exec(), receivefax_t38_init(), and sendfax_t38_init().

00965 {
00966    char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
00967    if (!filenames) {
00968       return 1;
00969    }
00970 
00971    ast_channel_lock(chan);
00972    if (details->option.statusevents) {
00973       struct manager_event_info info;
00974 
00975       get_manager_event_info(chan, &info);
00976       manager_event(EVENT_FLAG_CALL,
00977                (details->caps & AST_FAX_TECH_RECEIVE) ? "ReceiveFAXStatus" : "SendFAXStatus",
00978                "Status: %s\r\n"
00979                "Channel: %s\r\n"
00980                "Context: %s\r\n"
00981                "Exten: %s\r\n"
00982                "CallerID: %s\r\n"
00983                "LocalStationID: %s\r\n"
00984                "%s\r\n",
00985                status,
00986                chan->name,
00987                info.context,
00988                info.exten,
00989                info.cid,
00990                details->localstationid,
00991                filenames);
00992    }
00993    ast_channel_unlock(chan);
00994    ast_free(filenames);
00995 
00996    return 0;
00997 }

static int sendfax_exec ( struct ast_channel chan,
const char *  data 
) [static]

initiate a send FAX session

Definition at line 2067 of file res_fax.c.

References ast_channel::_state, ast_fax_session_details::allow_audio, ao2_ref, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_calloc, ast_channel_get_t38_state(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_DECLARE_APP_ARGS, ast_fax_modem_to_str(), AST_FAX_OPTFLAG_TRUE, AST_FAX_TECH_MULTI_DOC, AST_FAX_TECH_SEND, AST_FAX_TECH_T38, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_verb, ast_fax_session_details::caps, check_modem_rate(), manager_event_info::cid, manager_event_info::context, ast_fax_session_details::debug, disable_t38(), ast_fax_session_details::documents, EVENT_FLAG_CALL, manager_event_info::exten, fax_exec_options, fax_session_release(), fax_session_reserve(), faxregistry, ast_fax_document::filename, find_or_create_details(), generate_filenames_string(), generic_fax_exec(), get_manager_event_info(), global_fax_debug, LOG_ERROR, LOG_WARNING, manager_event, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, fax_module::next, OPT_ALLOWAUDIO, OPT_CALLEDMODE, OPT_CALLERMODE, OPT_DEBUG, OPT_REQUEST_T38, OPT_STATUS, ast_fax_session_details::option, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_fax_session_details::request_t38, S_OR, ast_fax_session_details::send_cng, sendfax_t38_init(), set_channel_variables(), set_fax_t38_caps(), ast_fax_session_details::statusevents, T38_STATE_NEGOTIATED, and T38_STATE_UNAVAILABLE.

Referenced by load_module().

02068 {
02069    char *parse, *filenames, *c, modems[128] = "";
02070    int channel_alive, file_count;
02071    struct ast_fax_session_details *details;
02072    struct ast_fax_session *s;
02073    struct ast_fax_tech_token *token = NULL;
02074    struct ast_fax_document *doc;
02075    AST_DECLARE_APP_ARGS(args,
02076       AST_APP_ARG(filenames);
02077       AST_APP_ARG(options);
02078    );
02079    struct ast_flags opts = { 0, };
02080    struct manager_event_info info;
02081 
02082    /* initialize output channel variables */
02083    pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
02084    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL);
02085    pbx_builtin_setvar_helper(chan, "FAXPAGES", "0");
02086    pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL);
02087    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL);
02088 
02089    /* if we ran sendfax then we attempted to send a fax, even if we never
02090     * start a fax session */
02091    ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1);
02092 
02093    /* Get a requirement structure and set it.  This structure is used
02094     * to tell the FAX technology module about the higher level FAX session */
02095    if (!(details = find_or_create_details(chan))) {
02096       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02097       pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR");
02098       pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory");
02099       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
02100       return -1;
02101    }
02102 
02103    ast_string_field_set(details, result, "FAILED");
02104    ast_string_field_set(details, resultstr, "error starting fax session");
02105    ast_string_field_set(details, error, "INIT_ERROR");
02106    set_channel_variables(chan, details);
02107 
02108    if (details->maxrate < details->minrate) {
02109       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02110       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02111       ast_string_field_set(details, resultstr, "maxrate is less than minrate");
02112       set_channel_variables(chan, details);
02113       ast_log(LOG_ERROR, "maxrate %u is less than minrate %u\n", details->maxrate, details->minrate);
02114       ao2_ref(details, -1);
02115       return -1;
02116    }
02117 
02118    if (check_modem_rate(details->modems, details->minrate)) {
02119       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02120       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
02121       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %u\n", modems, details->minrate);
02122       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02123       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
02124       set_channel_variables(chan, details);
02125       ao2_ref(details, -1);
02126       return -1;
02127    }
02128 
02129    if (check_modem_rate(details->modems, details->maxrate)) {
02130       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02131       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
02132       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %u\n", modems, details->maxrate);
02133       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02134       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
02135       set_channel_variables(chan, details);
02136       ao2_ref(details, -1);
02137       return -1;
02138    }
02139 
02140    if (ast_strlen_zero(data)) {
02141       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02142       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02143       ast_string_field_set(details, resultstr, "invalid arguments");
02144       set_channel_variables(chan, details);
02145       ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax);
02146       ao2_ref(details, -1);
02147       return -1;
02148    }
02149    parse = ast_strdupa(data);
02150    AST_STANDARD_APP_ARGS(args, parse);
02151 
02152 
02153    if (!ast_strlen_zero(args.options) &&
02154        ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
02155       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02156       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02157       ast_string_field_set(details, resultstr, "invalid arguments");
02158       set_channel_variables(chan, details);
02159       ao2_ref(details, -1);
02160       return -1;
02161    }
02162    if (ast_strlen_zero(args.filenames)) {
02163       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02164       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02165       ast_string_field_set(details, resultstr, "invalid arguments");
02166       set_channel_variables(chan, details);
02167       ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax);
02168       ao2_ref(details, -1);
02169       return -1;
02170    }
02171    
02172    /* check for unsupported FAX application options */
02173    if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) {
02174       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02175       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02176       ast_string_field_set(details, resultstr, "invalid arguments");
02177       set_channel_variables(chan, details);
02178       ast_log(LOG_WARNING, "%s does not support polling\n", app_sendfax);
02179       ao2_ref(details, -1);
02180       return -1;
02181    }
02182 
02183    file_count = 0;
02184    filenames = args.filenames;
02185    while ((c = strsep(&filenames, "&"))) {
02186       if (access(c, (F_OK | R_OK)) < 0) {
02187          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02188          ast_string_field_set(details, error, "FILE_ERROR");
02189          ast_string_field_set(details, resultstr, "error reading file");
02190          set_channel_variables(chan, details);
02191          ast_log(LOG_ERROR, "access failure.  Verify '%s' exists and check permissions.\n", args.filenames);
02192          ao2_ref(details, -1);
02193          return -1;
02194       }
02195 
02196       if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(c) + 1))) {
02197          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02198          ast_string_field_set(details, error, "MEMORY_ERROR");
02199          ast_string_field_set(details, resultstr, "error allocating memory");
02200          set_channel_variables(chan, details);
02201          ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
02202          ao2_ref(details, -1);
02203          return -1;
02204       }
02205 
02206       strcpy(doc->filename, c);
02207       AST_LIST_INSERT_TAIL(&details->documents, doc, next);
02208       file_count++;
02209    }
02210 
02211    if (file_count > 1) {
02212       details->caps |= AST_FAX_TECH_MULTI_DOC;
02213    }
02214 
02215    ast_verb(3, "Channel '%s' sending FAX:\n", chan->name);
02216    AST_LIST_TRAVERSE(&details->documents, doc, next) {
02217       ast_verb(3, "   %s\n", doc->filename);
02218    }
02219 
02220    details->caps = AST_FAX_TECH_SEND;
02221 
02222    /* check for debug */
02223    if (ast_test_flag(&opts, OPT_DEBUG) || global_fax_debug) {
02224       details->option.debug = AST_FAX_OPTFLAG_TRUE;
02225    }
02226 
02227    /* check for request for status events */
02228    if (ast_test_flag(&opts, OPT_STATUS)) {
02229       details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
02230    }
02231 
02232    if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
02233        ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
02234       details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
02235    }
02236 
02237    if (ast_test_flag(&opts, OPT_REQUEST_T38)) {
02238       details->option.request_t38 = AST_FAX_OPTFLAG_TRUE;
02239    }
02240 
02241    if (!(s = fax_session_reserve(details, &token))) {
02242       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02243       ast_string_field_set(details, resultstr, "error reserving fax session");
02244       set_channel_variables(chan, details);
02245       ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
02246       ao2_ref(details, -1);
02247       return -1;
02248    }
02249 
02250    /* make sure the channel is up */
02251    if (chan->_state != AST_STATE_UP) {
02252       if (ast_answer(chan)) {
02253          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02254          ast_string_field_set(details, resultstr, "error answering channel");
02255          set_channel_variables(chan, details);
02256          ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
02257          fax_session_release(s, token);
02258          ao2_ref(s, -1);
02259          ao2_ref(details, -1);
02260          return -1;
02261       }
02262    }
02263 
02264    if (set_fax_t38_caps(chan, details)) {
02265       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02266       ast_string_field_set(details, error, "T38_NEG_ERROR");
02267       ast_string_field_set(details, resultstr, "error negotiating T.38");
02268       set_channel_variables(chan, details);
02269       fax_session_release(s, token);
02270       ao2_ref(s, -1);
02271       ao2_ref(details, -1);
02272       return -1;
02273    }
02274 
02275    if (details->caps & AST_FAX_TECH_T38) {
02276       if (sendfax_t38_init(chan, details)) {
02277          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02278          ast_string_field_set(details, error, "T38_NEG_ERROR");
02279          ast_string_field_set(details, resultstr, "error negotiating T.38");
02280          set_channel_variables(chan, details);
02281          fax_session_release(s, token);
02282          ao2_ref(s, -1);
02283          ao2_ref(details, -1);
02284          ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
02285          return -1;
02286       }
02287    } else {
02288       details->option.send_cng = 1;
02289    }
02290 
02291    if ((channel_alive = generic_fax_exec(chan, details, s, token)) < 0) {
02292       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02293    }
02294 
02295    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
02296       if (disable_t38(chan)) {
02297          ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
02298       }
02299    }
02300 
02301    if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
02302       ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
02303       ao2_ref(s, -1);
02304       ao2_ref(details, -1);
02305       return (!channel_alive) ? -1 : 0;
02306    }
02307 
02308    /* send out the AMI completion event */
02309    ast_channel_lock(chan);
02310    get_manager_event_info(chan, &info);
02311    manager_event(EVENT_FLAG_CALL,
02312             "SendFAX", 
02313             "Channel: %s\r\n"
02314             "Context: %s\r\n"
02315             "Exten: %s\r\n"
02316             "CallerID: %s\r\n"
02317             "RemoteStationID: %s\r\n"
02318             "LocalStationID: %s\r\n"
02319             "PagesTransferred: %s\r\n"
02320             "Resolution: %s\r\n"
02321             "TransferRate: %s\r\n"
02322             "%s\r\n",
02323             chan->name,
02324             info.context,
02325             info.exten,
02326             info.cid,
02327             S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
02328             S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
02329             S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
02330             S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
02331             S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
02332             filenames);
02333    ast_channel_unlock(chan);
02334 
02335    ast_free(filenames);
02336 
02337    ao2_ref(s, -1);
02338    ao2_ref(details, -1);
02339 
02340    /* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
02341    return (!channel_alive) ? -1 : 0;
02342 }

static int sendfax_t38_init ( struct ast_channel chan,
struct ast_fax_session_details details 
) [static]

Definition at line 1823 of file res_fax.c.

References ast_fax_session_details::allow_audio, ast_channel_get_t38_state(), AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FAX_OPTFLAG_FALSE, AST_FAX_OPTFLAG_TRUE, AST_FAX_TECH_AUDIO, AST_FAX_TECH_T38, AST_FRAME_CONTROL, ast_frfree, ast_indicate_data(), ast_log(), ast_playtones_start(), ast_playtones_stop(), ast_read(), ast_remaining_ms(), AST_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, ast_tvnow(), ast_waitfor(), ast_fax_session_details::caps, ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_fax_session_details::option, our_t38_parameters, ast_fax_session_details::our_t38_parameters, ast_frame::ptr, report_fax_status(), ast_control_t38_parameters::request_response, ast_fax_session_details::request_t38, ast_frame::subclass, t38_parameters_ast_to_fax(), t38_parameters_fax_to_ast(), T38_STATE_NEGOTIATED, T38_STATE_NEGOTIATING, and ast_fax_session_details::their_t38_parameters.

Referenced by sendfax_exec().

01824 {
01825    int timeout_ms;
01826    struct ast_frame *frame = NULL;
01827    struct ast_control_t38_parameters t38_parameters;
01828    struct timeval start;
01829    int ms;
01830 
01831    t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
01832 
01833    /* send CNG tone while listening for the receiver to initiate a switch
01834     * to T.38 mode; if they do, stop sending the CNG tone and proceed with
01835     * the switch.
01836     *
01837     * 10500 is enough time for 3 CNG tones
01838     */
01839    timeout_ms = 10500;
01840 
01841    /* don't send any audio if we've already received a T.38 reinvite */
01842    if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
01843       if (ast_playtones_start(chan, 1024, "!1100/500,!0/3000,!1100/500,!0/3000,!1100/500,!0/3000", 1)) {
01844          ast_log(LOG_ERROR, "error generating CNG tone on %s\n", chan->name);
01845          return -1;
01846       }
01847    }
01848 
01849    start = ast_tvnow();
01850    while ((ms = ast_remaining_ms(start, timeout_ms))) {
01851       int break_loop = 0;
01852       ms = ast_waitfor(chan, ms);
01853 
01854       if (ms < 0) {
01855          ast_log(LOG_ERROR, "error while generating CNG tone on %s\n", chan->name);
01856          ast_playtones_stop(chan);
01857          return -1;
01858       }
01859 
01860       if (ms == 0) { /* all done, nothing happened */
01861          break;
01862       }
01863 
01864       if (!(frame = ast_read(chan))) {
01865          ast_log(LOG_ERROR, "error reading frame while generating CNG tone on %s\n", chan->name);
01866          ast_playtones_stop(chan);
01867          return -1;
01868       }
01869 
01870       if ((frame->frametype == AST_FRAME_CONTROL) &&
01871             (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01872             (frame->datalen == sizeof(t38_parameters))) {
01873          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01874 
01875          switch (parameters->request_response) {
01876          case AST_T38_REQUEST_NEGOTIATE:
01877             /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01878              * do T.38 as well
01879              */
01880             t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01881             t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01882             ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01883             ast_playtones_stop(chan);
01884             break;
01885          case AST_T38_NEGOTIATED:
01886             ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
01887             t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01888             details->caps &= ~AST_FAX_TECH_AUDIO;
01889             report_fax_status(chan, details, "T.38 Negotiated");
01890             break_loop = 1;
01891             break;
01892          default:
01893             break;
01894          }
01895       }
01896       ast_frfree(frame);
01897       if (break_loop) {
01898          break;
01899       }
01900    }
01901 
01902    ast_playtones_stop(chan);
01903 
01904    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01905       return 0;
01906    }
01907 
01908    /* T.38 negotiation did not happen, initiate a switch if requested */
01909    if (details->option.request_t38 == AST_FAX_OPTFLAG_TRUE) {
01910       ast_debug(1, "Negotiating T.38 for send on %s\n", chan->name);
01911 
01912       /* wait up to five seconds for negotiation to complete */
01913       timeout_ms = 5000;
01914 
01915       /* set parameters based on the session's parameters */
01916       t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01917       t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
01918       if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
01919          return -1;
01920       }
01921 
01922       start = ast_tvnow();
01923       while ((ms = ast_remaining_ms(start, timeout_ms))) {
01924          int break_loop = 0;
01925 
01926          ms = ast_waitfor(chan, ms);
01927          if (ms < 0) {
01928             ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01929             return -1;
01930          }
01931          if (ms == 0) { /* all done, nothing happened */
01932             ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
01933             details->caps &= ~AST_FAX_TECH_T38;
01934             break;
01935          }
01936 
01937          if (!(frame = ast_read(chan))) {
01938             ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01939             return -1;
01940          }
01941 
01942          if ((frame->frametype == AST_FRAME_CONTROL) &&
01943                (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01944                (frame->datalen == sizeof(t38_parameters))) {
01945             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01946 
01947             switch (parameters->request_response) {
01948             case AST_T38_REQUEST_NEGOTIATE:
01949                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01950                t38_parameters.request_response = AST_T38_NEGOTIATED;
01951                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01952                break;
01953             case AST_T38_NEGOTIATED:
01954                ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01955                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01956                details->caps &= ~AST_FAX_TECH_AUDIO;
01957                report_fax_status(chan, details, "T.38 Negotiated");
01958                break_loop = 1;
01959                break;
01960             case AST_T38_REFUSED:
01961                ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
01962                details->caps &= ~AST_FAX_TECH_T38;
01963                break_loop = 1;
01964                break;
01965             default:
01966                ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
01967                details->caps &= ~AST_FAX_TECH_T38;
01968                break_loop = 1;
01969                break;
01970             }
01971          }
01972          ast_frfree(frame);
01973          if (break_loop) {
01974             break;
01975          }
01976       }
01977 
01978       /* if T.38 was negotiated, we are done initializing */
01979       if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01980          return 0;
01981       }
01982 
01983       /* send one more CNG tone to get audio going again for some
01984        * carriers if we are going to fall back to audio mode */
01985       if (details->option.allow_audio == AST_FAX_OPTFLAG_TRUE) {
01986          if (ast_playtones_start(chan, 1024, "!1100/500,!0/3000", 1)) {
01987             ast_log(LOG_ERROR, "error generating second CNG tone on %s\n", chan->name);
01988             return -1;
01989          }
01990 
01991          timeout_ms = 3500;
01992          start = ast_tvnow();
01993          while ((ms = ast_remaining_ms(start, timeout_ms))) {
01994             int break_loop = 0;
01995 
01996             ms = ast_waitfor(chan, ms);
01997             if (ms < 0) {
01998                ast_log(LOG_ERROR, "error while generating second CNG tone on %s\n", chan->name);
01999                ast_playtones_stop(chan);
02000                return -1;
02001             }
02002             if (ms == 0) { /* all done, nothing happened */
02003                break;
02004             }
02005 
02006             if (!(frame = ast_read(chan))) {
02007                ast_log(LOG_ERROR, "error reading frame while generating second CNG tone on %s\n", chan->name);
02008                ast_playtones_stop(chan);
02009                return -1;
02010             }
02011 
02012             if ((frame->frametype == AST_FRAME_CONTROL) &&
02013                   (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
02014                   (frame->datalen == sizeof(t38_parameters))) {
02015                struct ast_control_t38_parameters *parameters = frame->data.ptr;
02016 
02017                switch (parameters->request_response) {
02018                case AST_T38_REQUEST_NEGOTIATE:
02019                   /* the other end has requested a switch to T.38, so reply that we are willing, if we can
02020                    * do T.38 as well
02021                    */
02022                   t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
02023                   t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
02024                   ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
02025                   ast_playtones_stop(chan);
02026                   break;
02027                case AST_T38_NEGOTIATED:
02028                   ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
02029                   t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
02030                   details->caps &= ~AST_FAX_TECH_AUDIO;
02031                   report_fax_status(chan, details, "T.38 Negotiated");
02032                   break_loop = 1;
02033                   break;
02034                default:
02035                   break;
02036                }
02037             }
02038             ast_frfree(frame);
02039             if (break_loop) {
02040                break;
02041             }
02042          }
02043 
02044          ast_playtones_stop(chan);
02045 
02046          /* if T.38 was negotiated, we are done initializing */
02047          if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
02048             return 0;
02049          }
02050       }
02051    }
02052 
02053    /* if we made it here, then T.38 failed, check the 'f' flag */
02054    if (details->option.allow_audio == AST_FAX_OPTFLAG_FALSE) {
02055       ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
02056       return -1;
02057    }
02058 
02059    /* ok, audio fallback is allowed */
02060    details->caps |= AST_FAX_TECH_AUDIO;
02061 
02062    return 0;
02063 }

static int session_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

compare callback for ao2

Definition at line 2353 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

02354 {
02355    struct ast_fax_session *lhs = obj, *rhs = arg;
02356 
02357    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02358 }

static struct ast_fax_session_details* session_details_new ( void   )  [static, read]

create a FAX session details structure

Definition at line 383 of file res_fax.c.

References ao2_alloc, ao2_ref, AST_FAX_OPTFLAG_FALSE, AST_LIST_HEAD_INIT_NOLOCK, ast_string_field_init, destroy_session_details(), ast_fax_session_details::documents, fax_options::ecm, ast_fax_session_details::ecm, get_general_options(), fax_options::maxrate, ast_fax_session_details::maxrate, fax_options::minrate, ast_fax_session_details::minrate, fax_options::modems, ast_fax_session_details::modems, ast_fax_session_details::option, ast_fax_session_details::request_t38, ast_fax_session_details::send_ced, ast_fax_session_details::send_cng, fax_options::statusevents, and ast_fax_session_details::statusevents.

Referenced by find_or_create_details().

00384 {
00385    struct ast_fax_session_details *d;
00386    struct fax_options options;
00387 
00388    if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) {
00389       return NULL;
00390    }
00391    
00392    if (ast_string_field_init(d, 512)) {
00393       ao2_ref(d, -1);
00394       return NULL;
00395    }
00396 
00397    get_general_options(&options);
00398 
00399    AST_LIST_HEAD_INIT_NOLOCK(&d->documents);
00400 
00401    /* These options need to be set to the configured default and may be overridden by
00402     * SendFAX, ReceiveFAX, or FAXOPT */
00403    d->option.request_t38 = AST_FAX_OPTFLAG_FALSE;
00404    d->option.send_cng = AST_FAX_OPTFLAG_FALSE;
00405    d->option.send_ced = AST_FAX_OPTFLAG_FALSE;
00406    d->option.ecm = options.ecm;
00407    d->option.statusevents = options.statusevents;
00408    d->modems = options.modems;
00409    d->minrate = options.minrate;
00410    d->maxrate = options.maxrate;
00411 
00412    return d;
00413 }

static int session_hash_cb ( const void *  obj,
const int  flags 
) [static]

hash callback for ao2

Definition at line 2345 of file res_fax.c.

References ast_fax_session::id.

Referenced by load_module().

02346 {
02347    const struct ast_fax_session *s = obj;
02348 
02349    return s->id;
02350 }

static void set_channel_variables ( struct ast_channel chan,
struct ast_fax_session_details details 
) [static]

Set fax related channel variables.

Definition at line 1000 of file res_fax.c.

References ast_fax_session_details::pages_transferred, pbx_builtin_setvar_helper(), and S_OR.

Referenced by generic_fax_exec(), receivefax_exec(), and sendfax_exec().

01001 {
01002    char buf[10];
01003    pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL));
01004    pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL));
01005    pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL));
01006    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", S_OR(details->remotestationid, NULL));
01007    pbx_builtin_setvar_helper(chan, "LOCALSTATIONID", S_OR(details->localstationid, NULL));
01008    pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL));
01009    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL));
01010 
01011    snprintf(buf, sizeof(buf), "%u", details->pages_transferred);
01012    pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
01013 }

static int set_config ( int  reload  )  [static]

configure res_fax

Definition at line 2668 of file res_fax.c.

References ast_config_destroy(), ast_config_load2(), ast_debug, ast_fax_modem_to_str(), AST_FAX_MODEM_V27, AST_FAX_MODEM_V34, ast_log(), ast_true(), ast_variable_browse(), check_modem_rate(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, default_options, fax_options::ecm, fax_rate_str_to_int(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, fax_options::maxrate, fax_options::minrate, fax_options::modems, ast_variable::name, ast_variable::next, set_general_options(), fax_options::statusevents, update_modem_bits(), and ast_variable::value.

Referenced by load_module(), and reload_module().

02669 {
02670    struct ast_config *cfg;
02671    struct ast_variable *v;
02672    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02673    char modems[128] = "";
02674    struct fax_options options;
02675    int res = 0;
02676 
02677    options = default_options;
02678 
02679    /* When we're not reloading, we have to be certain to set the general options
02680     * to the defaults in case config loading goes wrong at some point. On a reload,
02681     * the general options need to stay the same as what they were prior to the
02682     * reload rather than being reset to the defaults.
02683     */
02684    if (!reload) {
02685       set_general_options(&options);
02686    }
02687 
02688    /* read configuration */
02689    if (!(cfg = ast_config_load2(config, "res_fax", config_flags))) {
02690       ast_log(LOG_NOTICE, "Configuration file '%s' not found, %s options.\n",
02691             config, reload ? "not changing" : "using default");
02692       return 0;
02693    }
02694 
02695    if (cfg == CONFIG_STATUS_FILEINVALID) {
02696       ast_log(LOG_NOTICE, "Configuration file '%s' is invalid, %s options.\n",
02697             config, reload ? "not changing" : "using default");
02698       return 0;
02699    }
02700 
02701    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
02702       return 0;
02703    }
02704 
02705    if (reload) {
02706       options = default_options;
02707    }
02708 
02709    /* create configuration */
02710    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
02711       int rate;
02712 
02713       if (!strcasecmp(v->name, "minrate")) {
02714          ast_debug(3, "reading minrate '%s' from configuration file\n", v->value);
02715          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02716             res = -1;
02717             goto end;
02718          }
02719          options.minrate = rate;
02720       } else if (!strcasecmp(v->name, "maxrate")) {
02721          ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value);
02722          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02723             res = -1;
02724             goto end;
02725          }
02726          options.maxrate = rate;
02727       } else if (!strcasecmp(v->name, "statusevents")) {
02728          ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value);
02729          options.statusevents = ast_true(v->value);
02730       } else if (!strcasecmp(v->name, "ecm")) {
02731          ast_debug(3, "reading ecm '%s' from configuration file\n", v->value);
02732          options.ecm = ast_true(v->value);
02733       } else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
02734          options.modems = 0;
02735          update_modem_bits(&options.modems, v->value);
02736       }
02737    }
02738 
02739    if (options.maxrate < options.minrate) {
02740       ast_log(LOG_ERROR, "maxrate %u is less than minrate %u\n", options.maxrate, options.minrate);
02741       res = -1;
02742       goto end;
02743    }
02744 
02745    if (options.minrate == 2400 && (options.modems & AST_FAX_MODEM_V27) && !(options.modems & (AST_FAX_MODEM_V34))) {
02746       ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02747       ast_log(LOG_WARNING, "'modems' setting '%s' is no longer accepted with 'minrate' setting %u\n", modems, options.minrate);
02748       ast_log(LOG_WARNING, "'minrate' has been reset to 4800, please update res_fax.conf.\n");
02749       options.minrate = 4800;
02750    }
02751 
02752    if (check_modem_rate(options.modems, options.minrate)) {
02753       ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02754       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %u\n", modems, options.minrate);
02755       res = -1;
02756       goto end;
02757    }
02758 
02759    if (check_modem_rate(options.modems, options.maxrate)) {
02760       ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02761       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %u\n", modems, options.maxrate);
02762       res = -1;
02763       goto end;
02764    }
02765 
02766    set_general_options(&options);
02767 
02768 end:
02769    ast_config_destroy(cfg);
02770    return res;
02771 }

static int set_fax_t38_caps ( struct ast_channel chan,
struct ast_fax_session_details details 
) [static]

Definition at line 1059 of file res_fax.c.

References ast_channel_get_t38_state(), AST_CONTROL_T38_PARAMETERS, AST_FAX_TECH_AUDIO, AST_FAX_TECH_T38, ast_indicate_data(), ast_log(), AST_T38_REQUEST_PARMS, ast_fax_session_details::caps, LOG_ERROR, ast_control_t38_parameters::request_response, T38_STATE_NEGOTIATING, T38_STATE_UNAVAILABLE, and T38_STATE_UNKNOWN.

Referenced by receivefax_exec(), and sendfax_exec().

01060 {
01061    switch (ast_channel_get_t38_state(chan)) {
01062    case T38_STATE_UNKNOWN:
01063       details->caps |= AST_FAX_TECH_T38;
01064       break;
01065    case T38_STATE_UNAVAILABLE:
01066       details->caps |= AST_FAX_TECH_AUDIO;
01067       break;
01068    case T38_STATE_NEGOTIATING: {
01069       /* the other end already sent us a T.38 reinvite, so we need to prod the channel
01070        * driver into resending their parameters to us if it supports doing so... if
01071        * not, we can't proceed, because we can't create a proper reply without them.
01072        * if it does work, the channel driver will send an AST_CONTROL_T38_PARAMETERS
01073        * with a request of AST_T38_REQUEST_NEGOTIATE, which will be read by the function
01074        * that gets called after this one completes
01075        */
01076       struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, };
01077       if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters)) != AST_T38_REQUEST_PARMS) {
01078          ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01079          return -1;
01080       }
01081       details->caps |= AST_FAX_TECH_T38;
01082       break;
01083    }
01084    default:
01085       ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01086       return -1;
01087    }
01088 
01089    return 0;
01090 }

static void set_general_options ( const struct fax_options options  )  [static]

Definition at line 2653 of file res_fax.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, general_options, and options_lock.

Referenced by set_config().

02654 {
02655    ast_rwlock_wrlock(&options_lock);
02656    general_options = *options;
02657    ast_rwlock_unlock(&options_lock);
02658 }

static void t38_parameters_ast_to_fax ( struct ast_fax_t38_parameters dst,
const struct ast_control_t38_parameters src 
) [static]
static void t38_parameters_fax_to_ast ( struct ast_control_t38_parameters dst,
const struct ast_fax_t38_parameters src 
) [static]
static int unload_module ( void   )  [static]

unload res_fax

Definition at line 2894 of file res_fax.c.

References acf_faxopt, ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_log(), ast_logger_unregister_level(), ast_unregister_application(), fax_cli, faxregistry, LOG_WARNING, and ast_custom_function::name.

02895 {
02896    ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
02897    
02898    if (ast_custom_function_unregister(&acf_faxopt) < 0) {
02899       ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
02900    }
02901 
02902    if (ast_unregister_application(app_sendfax) < 0) {
02903       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_sendfax);
02904    }
02905 
02906    if (ast_unregister_application(app_receivefax) < 0) {
02907       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
02908    }
02909 
02910    if (fax_logger_level != -1) {
02911       ast_logger_unregister_level("FAX");
02912    }
02913 
02914    ao2_ref(faxregistry.container, -1);
02915 
02916    return 0;
02917 }

static int update_modem_bits ( enum ast_fax_modems bits,
const char *  value 
) [static]

Definition at line 460 of file res_fax.c.

References ARRAY_LEN, AST_FAX_MODEM_V17, AST_FAX_MODEM_V27, AST_FAX_MODEM_V29, AST_FAX_MODEM_V34, ast_log(), and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

00461 {     
00462    char *m[5], *tok, *v = (char *)value;
00463    int i = 0, j;
00464 
00465    if (!strchr(v, ',')) {
00466       m[i++] = v;
00467       m[i] = NULL;
00468    } else {
00469       tok = strtok(v, ", ");
00470       while (tok && i < ARRAY_LEN(m) - 1) {
00471          m[i++] = tok;
00472          tok = strtok(NULL, ", ");
00473       }
00474       m[i] = NULL;
00475    }
00476 
00477    *bits = 0;
00478    for (j = 0; j < i; j++) {
00479       if (!strcasecmp(m[j], "v17")) {
00480          *bits |= AST_FAX_MODEM_V17;
00481       } else if (!strcasecmp(m[j], "v27")) {
00482          *bits |= AST_FAX_MODEM_V27;
00483       } else if (!strcasecmp(m[j], "v29")) {
00484          *bits |= AST_FAX_MODEM_V29;
00485       } else if (!strcasecmp(m[j], "v34")) {
00486          *bits |= AST_FAX_MODEM_V34;
00487       } else {
00488          ast_log(LOG_WARNING, "ignoring invalid modem setting: '%s', valid options {v17 | v27 | v29 | v34}\n", m[j]);
00489       }
00490    }
00491    return 0;
00492 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Generic FAX Applications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_APP_DEPEND, } [static]

Definition at line 2968 of file res_fax.c.

Initial value:
 {
   .name = "FAXOPT",
   .read = acf_faxopt_read,
   .write = acf_faxopt_write,
}

FAXOPT dialplan function.

Definition at line 2887 of file res_fax.c.

Referenced by load_module(), and unload_module().

The number of active FAX sessions

Definition at line 223 of file res_fax.c.

const char app_receivefax[] = "ReceiveFAX" [static]

Definition at line 198 of file res_fax.c.

const char app_sendfax[] = "SendFAX" [static]

Definition at line 199 of file res_fax.c.

Definition at line 2968 of file res_fax.c.

const char* config = "res_fax.conf" [static]

Definition at line 275 of file res_fax.c.

Referenced by load_module(), and set_config().

active sessions are astobj2 objects

Definition at line 227 of file res_fax.c.

struct fax_options default_options [static]

Definition at line 262 of file res_fax.c.

Referenced by set_config().

struct ast_cli_entry fax_cli[] [static]

Definition at line 2643 of file res_fax.c.

Referenced by load_module(), and unload_module().

Number of successful FAX transmissions

Definition at line 233 of file res_fax.c.

Initial value:
 {
   .type = "res_fax",
   .destroy = destroy_callback,
}

Definition at line 343 of file res_fax.c.

Referenced by find_details(), and find_or_create_details().

struct ast_app_option fax_exec_options[128] = { [ 'a' ] = { .flag = OPT_CALLEDMODE }, [ 'c' ] = { .flag = OPT_CALLERMODE }, [ 'd' ] = { .flag = OPT_DEBUG }, [ 'f' ] = { .flag = OPT_ALLOWAUDIO }, [ 's' ] = { .flag = OPT_STATUS }, [ 'z' ] = { .flag = OPT_REQUEST_T38 }, } [static]

Definition at line 295 of file res_fax.c.

Referenced by receivefax_exec(), and sendfax_exec().

Number of failed FAX transmissions

Definition at line 235 of file res_fax.c.

int fax_logger_level = -1 [static]

Definition at line 213 of file res_fax.c.

Total number of Rx FAX attempts

Definition at line 231 of file res_fax.c.

Total number of Tx FAX attempts

Definition at line 229 of file res_fax.c.

struct { ... } faxregistry [static]
struct fax_options general_options [static]

Definition at line 260 of file res_fax.c.

Referenced by get_general_options(), and set_general_options().

int global_fax_debug = 0 [static]

Definition at line 277 of file res_fax.c.

Referenced by cli_fax_set_debug(), receivefax_exec(), and sendfax_exec().

the next unique session name

Definition at line 237 of file res_fax.c.

ast_rwlock_t options_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } [static]

Definition at line 270 of file res_fax.c.

Referenced by get_general_options(), and set_general_options().

Definition at line 1154 of file res_fax.c.

Referenced by receivefax_t38_init(), and sendfax_t38_init().

The number of reserved FAX sessions

Definition at line 225 of file res_fax.c.


Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1