Tue Aug 20 16:35:13 2013

Asterisk developer's documentation


res_fax.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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

Variables

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

Detailed Description

Generic FAX Resource for FAX technology resource modules.

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

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

Definition in file res_fax.c.


Define Documentation

#define FAX_MAXBUCKETS   10

maximum buckets for res_fax ao2 containers

Definition at line 216 of file res_fax.c.

Referenced by load_module().

#define GENERIC_FAX_EXEC_ERROR ( fax,
chan,
errorstr,
reason   ) 
Value:
do {  \
      ast_log(LOG_ERROR, "channel '%s' FAX session '%d' 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 1023 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 1018 of file res_fax.c.

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

Definition at line 1007 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   2400

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

static void __unreg_module ( void   )  [static]

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

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

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

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

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

References ast_log(), and ast_log_dynamic_level.

Referenced by spandsp_log().

00677 {
00678    if (fax_logger_level != -1) {
00679       ast_log_dynamic_level(fax_logger_level, "%s", msg);
00680    } else {
00681       ast_log(level, file, line, function, "%s", msg);
00682    }
00683 }

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

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

int ast_fax_tech_register ( struct ast_fax_tech tech  ) 

register a FAX technology module

register a fax technology

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

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

void ast_fax_tech_unregister ( struct ast_fax_tech tech  ) 

unregister a FAX technology module

unregister a fax technology

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

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

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_V27 | 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    case 9600:
00587       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
00588          return 1;
00589       }
00590       break;
00591    case 12000:
00592    case 14400:
00593       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
00594          return 1;
00595       }
00596       break;
00597    case 28800:
00598    case 33600:
00599       if (!(modems & AST_FAX_MODEM_V34)) {
00600          return 1;
00601       }
00602       break;
00603    default:
00604       /* this should never happen */
00605       return 1;
00606    }
00607 
00608    return 0;
00609 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 '%d', [ %.3ld.%.6ld ], %s sent %d frames (%d 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 723 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().

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

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

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

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

convert a rate string to a rate

Definition at line 686 of file res_fax.c.

References ast_log(), LOG_ERROR, and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

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

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

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

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

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

00711 {
00712    if (token) {
00713       s->tech->release_token(token);
00714    }
00715 
00716    if (s->state == AST_FAX_STATE_RESERVED) {
00717       ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00718       s->state = AST_FAX_STATE_INACTIVE;
00719    }
00720 }

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

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

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

fax session tab completion

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

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

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

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

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

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

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

00901 {
00902    pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
00903    pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
00904    pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
00905 }

static int load_module ( void   )  [static]

load res_fax

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

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

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

initiate a receive FAX session

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

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

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

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

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

static int reload_module ( void   )  [static]

Definition at line 2941 of file res_fax.c.

References set_config().

02942 {
02943    set_config(1);
02944    return 0;
02945 }

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

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

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

initiate a send FAX session

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

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

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

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

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

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

compare callback for ao2

Definition at line 2345 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

02346 {
02347    struct ast_fax_session *lhs = obj, *rhs = arg;
02348 
02349    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02350 }

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

References ast_fax_session::id.

Referenced by load_module().

02338 {
02339    const struct ast_fax_session *s = obj;
02340 
02341    return s->id;
02342 }

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

Set fax related channel variables.

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

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

static int set_config ( int  reload  )  [static]

configure res_fax

Definition at line 2660 of file res_fax.c.

References ast_config_destroy(), ast_config_load2(), ast_debug, ast_fax_modem_to_str(), 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, 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().

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

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

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

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

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

Definition at line 2645 of file res_fax.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, general_options, and options_lock.

Referenced by set_config().

02646 {
02647    ast_rwlock_wrlock(&options_lock);
02648    general_options = *options;
02649    ast_rwlock_unlock(&options_lock);
02650 }

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

02880 {
02881    ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
02882    
02883    if (ast_custom_function_unregister(&acf_faxopt) < 0) {
02884       ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
02885    }
02886 
02887    if (ast_unregister_application(app_sendfax) < 0) {
02888       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_sendfax);
02889    }
02890 
02891    if (ast_unregister_application(app_receivefax) < 0) {
02892       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
02893    }
02894 
02895    if (fax_logger_level != -1) {
02896       ast_logger_unregister_level("FAX");
02897    }
02898 
02899    ao2_ref(faxregistry.container, -1);
02900 
02901    return 0;
02902 }

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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_APP_DEPEND, } [static]

Definition at line 2953 of file res_fax.c.

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

FAXOPT dialplan function.

Definition at line 2872 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 2953 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 2635 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 1146 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 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1