Wed Oct 29 05:04:58 2014

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"
Include dependency graph for res_fax.c:

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 = "95089850e3c922fa176f9bd274fd8109" , .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 1027 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 1022 of file res_fax.c.

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

Definition at line 1011 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 2964 of file res_fax.c.

static void __unreg_module ( void   )  [static]

Definition at line 2964 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 2770 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.

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

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 2836 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().

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

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 2417 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.

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

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 2452 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.

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

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 2520 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.

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

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 2589 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.

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

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 2482 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.

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

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 2556 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.

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

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

Definition at line 2385 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.

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

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 1088 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().

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

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_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          s->tech = faxmod->tech;
00877          break;
00878       }
00879       AST_RWLIST_UNLOCK(&faxmodules);
00880 
00881       if (!faxmod) {
00882          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)));
00883          ao2_ref(s, -1);
00884          return NULL;
00885       }
00886    }
00887 
00888    if (!(s->tech_pvt = s->tech->new_session(s, token))) {
00889       ast_log(LOG_ERROR, "FAX session failed to initialize.\n");
00890       ao2_ref(s, -1);
00891       return NULL;
00892    }
00893    /* link the session to the session container */
00894    if (!(ao2_link(faxregistry.container, s))) {
00895       ast_log(LOG_ERROR, "failed to add FAX session '%u' to container.\n", s->id);
00896       ao2_ref(s, -1);
00897       return NULL;
00898    }
00899    ast_debug(4, "channel '%s' using FAX session '%u'\n", s->channame, s->id);
00900 
00901    return s;
00902 }

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 2357 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().

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

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 923 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().

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

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 1158 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().

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

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 904 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().

00905 {
00906    pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
00907    pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
00908    pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
00909 }

static int load_module ( void   )  [static]

load res_fax

Definition at line 2916 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().

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

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

initiate a receive FAX session

Definition at line 1575 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().

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

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

Definition at line 1413 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().

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

static int reload_module ( void   )  [static]

Definition at line 2952 of file res_fax.c.

References set_config().

02953 {
02954    set_config(1);
02955    return 0;
02956 }

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 960 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().

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

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

initiate a send FAX session

Definition at line 2063 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().

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

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

Definition at line 1819 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().

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

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

compare callback for ao2

Definition at line 2349 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

02350 {
02351    struct ast_fax_session *lhs = obj, *rhs = arg;
02352 
02353    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02354 }

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 2341 of file res_fax.c.

References ast_fax_session::id.

Referenced by load_module().

02342 {
02343    const struct ast_fax_session *s = obj;
02344 
02345    return s->id;
02346 }

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

Set fax related channel variables.

Definition at line 996 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().

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

static int set_config ( int  reload  )  [static]

configure res_fax

Definition at line 2664 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().

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

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

Definition at line 1055 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().

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

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

Definition at line 2649 of file res_fax.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, general_options, and options_lock.

Referenced by set_config().

02650 {
02651    ast_rwlock_wrlock(&options_lock);
02652    general_options = *options;
02653    ast_rwlock_unlock(&options_lock);
02654 }

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 2890 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.

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

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

Definition at line 460 of file res_fax.c.

References 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 < 5)) {
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 = "95089850e3c922fa176f9bd274fd8109" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_APP_DEPEND, } [static]

Definition at line 2964 of file res_fax.c.

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

FAXOPT dialplan function.

Definition at line 2883 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 2964 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 2639 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 1150 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 29 Oct 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1