Wed Apr 6 11:30:09 2011

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  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 an ast_fax_state to a string
int ast_fax_tech_register (struct ast_fax_tech *tech)
 register a fax technology
void ast_fax_tech_unregister (struct ast_fax_tech *tech)
 unregister a fax technology
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_detailsfind_details (struct ast_channel *chan)
 returns a reference counted pointer to a fax datastore, if it exists
static struct ast_fax_session_detailsfind_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_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 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_detailssession_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 (const char *config_file)
 configure res_fax
static int set_fax_t38_caps (struct ast_channel *chan, struct ast_fax_session_details *details)
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, }
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 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
   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.
struct {
   uint32_t   ecm:1
   unsigned int   maxrate
   unsigned int   minrate
   enum ast_fax_modems   modems
   uint32_t   statusevents:1
general_options
static int global_fax_debug = 0
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 215 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 998 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); \
      res = ms = -1; \
   } while (0)

Definition at line 992 of file res_fax.c.

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

Definition at line 981 of file res_fax.c.

Referenced by generic_fax_exec().

#define RES_FAX_MAXRATE   14400

Definition at line 247 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_MINRATE   2400

Definition at line 246 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_MODEM   (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)

Definition at line 249 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_STATUSEVENTS   0

Definition at line 248 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_TIMEOUT   10000

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

00263      {
00264    OPT_CALLEDMODE  = (1 << 0),
00265    OPT_CALLERMODE  = (1 << 1),
00266    OPT_DEBUG       = (1 << 2),
00267    OPT_STATUS      = (1 << 3),
00268    OPT_ALLOWAUDIO  = (1 << 5),
00269    OPT_REQUEST_T38 = (1 << 6),
00270 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2860 of file res_fax.c.

static void __unreg_module ( void   )  [static]

Definition at line 2860 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 2673 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, ast_fax_session_details::error, find_details(), generate_filenames_string(), ast_fax_session_details::headerinfo, ast_fax_session_details::id, ast_fax_session_details::localstationid, LOG_ERROR, LOG_WARNING, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, ast_channel::name, ast_fax_session_details::option, ast_fax_session_details::pages_transferred, ast_fax_session_details::remotestationid, ast_fax_session_details::resolution, ast_fax_session_details::result, ast_fax_session_details::resultstr, and ast_fax_session_details::transfer_rate.

02674 {
02675    struct ast_fax_session_details *details = find_details(chan);
02676    int res = 0;
02677    char *filenames;
02678 
02679    if (!details) {
02680       ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02681       return -1;
02682    }
02683    if (!strcasecmp(data, "ecm")) {
02684       ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
02685    } else if (!strcasecmp(data, "error")) {
02686       ast_copy_string(buf, details->error, len);
02687    } else if (!strcasecmp(data, "filename")) {
02688       if (AST_LIST_EMPTY(&details->documents)) {
02689          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02690          res = -1;
02691       } else {
02692          ast_copy_string(buf, AST_LIST_FIRST(&details->documents)->filename, len);
02693       }
02694    } else if (!strcasecmp(data, "filenames")) {
02695       if (AST_LIST_EMPTY(&details->documents)) {
02696          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02697          res = -1;
02698       } else if ((filenames = generate_filenames_string(details, "", ","))) {
02699          ast_copy_string(buf, filenames, len);
02700          ast_free(filenames);
02701       } else {
02702          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s), there was an error generating the filenames list.\n", chan->name, data);
02703          res = -1;
02704       }
02705    } else if (!strcasecmp(data, "headerinfo")) {
02706       ast_copy_string(buf, details->headerinfo, len);
02707    } else if (!strcasecmp(data, "localstationid")) {
02708       ast_copy_string(buf, details->localstationid, len);
02709    } else if (!strcasecmp(data, "maxrate")) {
02710       snprintf(buf, len, "%d", details->maxrate);
02711    } else if (!strcasecmp(data, "minrate")) {
02712       snprintf(buf, len, "%d", details->minrate);
02713    } else if (!strcasecmp(data, "pages")) {
02714       snprintf(buf, len, "%d", details->pages_transferred);
02715    } else if (!strcasecmp(data, "rate")) {
02716       ast_copy_string(buf, details->transfer_rate, len);
02717    } else if (!strcasecmp(data, "remotestationid")) {
02718       ast_copy_string(buf, details->remotestationid, len);
02719    } else if (!strcasecmp(data, "resolution")) {
02720       ast_copy_string(buf, details->resolution, len);
02721    } else if (!strcasecmp(data, "sessionid")) {
02722       snprintf(buf, len, "%d", details->id);
02723    } else if (!strcasecmp(data, "status")) {
02724       ast_copy_string(buf, details->result, len);
02725    } else if (!strcasecmp(data, "statusstr")) {
02726       ast_copy_string(buf, details->resultstr, len);
02727    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02728       ast_fax_modem_to_str(details->modems, buf, len);
02729    } else {
02730       ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", chan->name, data);
02731       res = -1;
02732    }
02733    ao2_ref(details, -1);
02734 
02735    return res;
02736 }

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 2739 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(), ast_fax_session_details::headerinfo, ast_fax_session_details::localstationid, LOG_WARNING, ast_fax_session_details::maxrate, ast_fax_session_details::minrate, ast_fax_session_details::modems, ast_channel::name, ast_fax_session_details::option, and update_modem_bits().

02740 {
02741    int res = 0;
02742    struct ast_fax_session_details *details;
02743 
02744    if (!(details = find_or_create_details(chan))) {
02745       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);
02746       return -1;
02747    }
02748    ast_debug(3, "channel '%s' setting FAXOPT(%s) to '%s'\n", chan->name, data, value);
02749 
02750    if (!strcasecmp(data, "ecm")) {
02751       const char *val = ast_skip_blanks(value);
02752       if (ast_true(val)) {
02753          details->option.ecm = AST_FAX_OPTFLAG_TRUE;
02754       } else if (ast_false(val)) {
02755          details->option.ecm = AST_FAX_OPTFLAG_FALSE;
02756       } else {
02757          ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
02758       }
02759    } else if (!strcasecmp(data, "headerinfo")) {
02760       ast_string_field_set(details, headerinfo, value);
02761    } else if (!strcasecmp(data, "localstationid")) {
02762       ast_string_field_set(details, localstationid, value);
02763    } else if (!strcasecmp(data, "maxrate")) {
02764       details->maxrate = fax_rate_str_to_int(value);
02765       if (!details->maxrate) {
02766          details->maxrate = ast_fax_maxrate();
02767       }
02768    } else if (!strcasecmp(data, "minrate")) {
02769       details->minrate = fax_rate_str_to_int(value);
02770       if (!details->minrate) {
02771          details->minrate = ast_fax_minrate();
02772       }
02773    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02774       update_modem_bits(&details->modems, value);
02775    } else {
02776       ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", chan->name, data, value);
02777       res = -1;
02778    }
02779 
02780    ao2_ref(details, -1);
02781 
02782    return res;
02783 }

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

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

00470 {
00471    char *out = buf;
00472    size_t size = bufsize;
00473    int first = 1;
00474 
00475    if (caps & AST_FAX_TECH_SEND) {
00476       if (!first) {
00477          ast_build_string(&buf, &size, ",");
00478       }
00479       ast_build_string(&buf, &size, "SEND");
00480       first = 0;
00481    }
00482    if (caps & AST_FAX_TECH_RECEIVE) {
00483       if (!first) {
00484          ast_build_string(&buf, &size, ",");
00485       }
00486       ast_build_string(&buf, &size, "RECEIVE");
00487       first = 0;
00488    }
00489    if (caps & AST_FAX_TECH_AUDIO) {
00490       if (!first) {
00491          ast_build_string(&buf, &size, ",");
00492       }
00493       ast_build_string(&buf, &size, "AUDIO");
00494       first = 0;
00495    }
00496    if (caps & AST_FAX_TECH_T38) {
00497       if (!first) {
00498          ast_build_string(&buf, &size, ",");
00499       }
00500       ast_build_string(&buf, &size, "T38");
00501       first = 0;
00502    }
00503    if (caps & AST_FAX_TECH_MULTI_DOC) {
00504       if (!first) {
00505          ast_build_string(&buf, &size, ",");
00506       }
00507       ast_build_string(&buf, &size, "MULTI_DOC");
00508       first = 0;
00509    }
00510 
00511    return out;
00512 }

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

References ast_log(), and ast_log_dynamic_level.

Referenced by spandsp_log().

00652 {
00653    if (fax_logger_level != -1) {
00654       ast_log_dynamic_level(fax_logger_level, "%s", msg);
00655    } else {
00656       ast_log(level, file, line, function, "%s", msg);
00657    }
00658 }

unsigned int ast_fax_maxrate ( void   ) 

get the maxiumum supported fax rate

Definition at line 425 of file res_fax.c.

References general_options.

Referenced by acf_faxopt_write().

00426 {
00427    return general_options.maxrate;
00428 }

unsigned int ast_fax_minrate ( void   ) 

get the minimum supported fax rate

Definition at line 430 of file res_fax.c.

References general_options.

Referenced by acf_faxopt_write().

00431 {
00432    return general_options.minrate;
00433 }

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

Definition at line 514 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(), and sendfax_exec().

00515 {
00516    int count = 0;
00517 
00518    if (bits & AST_FAX_MODEM_V17) {
00519       strcat(tbuf, "V17");
00520       count++;
00521    }
00522    if (bits & AST_FAX_MODEM_V27) {
00523       if (count) {
00524          strcat(tbuf, ",");
00525       }
00526       strcat(tbuf, "V27");
00527       count++;
00528    }
00529    if (bits & AST_FAX_MODEM_V29) {
00530       if (count) {
00531          strcat(tbuf, ",");
00532       }
00533       strcat(tbuf, "V29");
00534       count++;
00535    }
00536    if (bits & AST_FAX_MODEM_V34) {
00537       if (count) {
00538          strcat(tbuf, ",");
00539       }
00540       strcat(tbuf, "V34");
00541       count++;
00542    }
00543 
00544    return 0;
00545 }

const char* ast_fax_state_to_str ( enum ast_fax_state  state  ) 

convert an ast_fax_state to a string

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

00629 {
00630    switch (state) {
00631    case AST_FAX_STATE_UNINITIALIZED:
00632       return "Uninitialized";
00633    case AST_FAX_STATE_INITIALIZED:
00634       return "Initialized";
00635    case AST_FAX_STATE_OPEN:
00636       return "Open";
00637    case AST_FAX_STATE_ACTIVE:
00638       return "Active";
00639    case AST_FAX_STATE_COMPLETE:
00640       return "Complete";
00641    case AST_FAX_STATE_RESERVED:
00642       return "Reserved";
00643    case AST_FAX_STATE_INACTIVE:
00644       return "Inactive";
00645    default:
00646       ast_log(LOG_WARNING, "unhandled FAX state: %d\n", state);
00647       return "Unknown";
00648    }
00649 }

int ast_fax_tech_register ( struct ast_fax_tech tech  ) 

register a fax technology

Definition at line 587 of file res_fax.c.

References ast_calloc, ast_module_ref(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, fax_module::list, and fax_module::tech.

Referenced by load_module().

00588 {
00589    struct fax_module *fax;
00590 
00591    if (!(fax = ast_calloc(1, sizeof(*fax)))) {
00592       return -1;
00593    }
00594    fax->tech = tech;
00595    AST_RWLIST_WRLOCK(&faxmodules);
00596    AST_RWLIST_INSERT_TAIL(&faxmodules, fax, list);
00597    AST_RWLIST_UNLOCK(&faxmodules);
00598    ast_module_ref(ast_module_info->self);
00599 
00600    ast_verb(3, "Registered handler for '%s' (%s)\n", fax->tech->type, fax->tech->description);
00601 
00602    return 0;
00603 }

void ast_fax_tech_unregister ( struct ast_fax_tech tech  ) 

unregister a fax technology

Definition at line 606 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::list, fax_module::tech, and ast_fax_tech::type.

Referenced by unload_module().

00607 {
00608    struct fax_module *fax;
00609 
00610    ast_verb(3, "Unregistering FAX module type '%s'\n", tech->type);
00611 
00612    AST_RWLIST_WRLOCK(&faxmodules);
00613    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&faxmodules, fax, list) {
00614       if (fax->tech != tech) {
00615          continue;
00616       }
00617       AST_RWLIST_REMOVE_CURRENT(list);
00618       ast_module_unref(ast_module_info->self);
00619       ast_free(fax);
00620       ast_verb(4, "Unregistered FAX module type '%s'\n", tech->type);
00621       break;   
00622    }
00623    AST_RWLIST_TRAVERSE_SAFE_END;
00624    AST_RWLIST_UNLOCK(&faxmodules);
00625 }

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

Definition at line 547 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(), and sendfax_exec().

00548 {
00549    switch (rate) {
00550    case 2400:
00551       if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
00552          return 1;
00553       }
00554       break;
00555    case 4800:
00556       if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
00557          return 1;
00558       }
00559       break;
00560    case 7200:
00561    case 9600:
00562       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
00563          return 1;
00564       }
00565       break;
00566    case 12000:
00567    case 14400:
00568       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
00569          return 1;
00570       }
00571       break;
00572    case 28800:
00573    case 33600:
00574       if (!(modems & AST_FAX_MODEM_V34)) {
00575          return 1;
00576       }
00577       break;
00578    default:
00579       /* this should never happen */
00580       return 1;
00581    }
00582 
00583    return 0;
00584 }

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

02363 {
02364    int flag;
02365    const char *what;
02366 
02367    switch (cmd) {
02368    case CLI_INIT:
02369       e->command = "fax set debug {on|off}";
02370       e->usage = 
02371          "Usage: fax set debug { on | off }\n"
02372          "       Enable/Disable FAX debugging on new FAX sessions.  The basic FAX debugging will result in\n"
02373          "       additional events sent to manager sessions with 'call' class permissions.  When\n"
02374          "       verbosity is greater than '5' events will be displayed to the console and audio versus\n"
02375          "       energy analysis will be performed and displayed to the console.\n";
02376       return NULL;
02377    case CLI_GENERATE:
02378       return NULL;
02379    }
02380 
02381    what = a->argv[e->args-1];      /* guaranteed to exist */
02382    if (!strcasecmp(what, "on")) {
02383       flag = 1;
02384    } else if (!strcasecmp(what, "off")) {
02385       flag = 0;
02386    } else {
02387       return CLI_SHOWUSAGE;
02388    }
02389 
02390    global_fax_debug = flag;
02391    ast_cli(a->fd, "\n\nFAX Debug %s\n\n", (flag) ? "Enabled" : "Disabled");
02392 
02393    return CLI_SUCCESS;
02394 }

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 2397 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::list, fax_module::tech, ast_fax_tech::type, and ast_cli_entry::usage.

02398 {
02399    struct fax_module *fax;
02400    unsigned int num_modules = 0;
02401    
02402    switch (cmd) {
02403    case CLI_INIT:
02404       e->command = "fax show capabilities";
02405       e->usage = 
02406          "Usage: fax show capabilities\n"
02407          "       Shows the capabilities of the registered FAX technology modules\n";
02408       return NULL;
02409    case CLI_GENERATE:
02410       return NULL;
02411    }
02412 
02413    ast_cli(a->fd, "\n\nRegistered FAX Technology Modules:\n\n");
02414    AST_RWLIST_RDLOCK(&faxmodules);
02415    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02416       ast_cli(a->fd, "%-15s : %s\n%-15s : %s\n%-15s : ", "Type", fax->tech->type, "Description", fax->tech->description, "Capabilities");
02417       fax->tech->cli_show_capabilities(a->fd);
02418       num_modules++;
02419    }
02420    AST_RWLIST_UNLOCK(&faxmodules);
02421    ast_cli(a->fd, "%d registered modules\n\n", num_modules);
02422 
02423    return CLI_SUCCESS;
02424 }

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

02463 {
02464    struct ast_fax_session *s, tmp;
02465 
02466    switch (cmd) {
02467    case CLI_INIT:
02468       e->command = "fax show session";
02469       e->usage =
02470          "Usage: fax show session <session number>\n"
02471          "       Shows status of the named FAX session\n";
02472       return NULL;
02473    case CLI_GENERATE:
02474       return fax_session_tab_complete(a);
02475    }
02476 
02477    if (a->argc != 4) {
02478       return CLI_SHOWUSAGE;
02479    }
02480 
02481    if (sscanf(a->argv[3], "%d", &tmp.id) != 1) {
02482       ast_log(LOG_ERROR, "invalid session id: '%s'\n", a->argv[3]);
02483       return RESULT_SUCCESS;
02484    }
02485 
02486    ast_cli(a->fd, "\nFAX Session Details:\n--------------------\n\n");
02487    s = ao2_find(faxregistry.container, &tmp, OBJ_POINTER);
02488    if (s) {
02489       s->tech->cli_show_session(s, a->fd);
02490       ao2_ref(s, -1);
02491    }
02492    ast_cli(a->fd, "\n\n");
02493 
02494    return CLI_SUCCESS;
02495 }

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 2531 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(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, faxregistry, ast_cli_args::fd, generate_filenames_string(), LOG_ERROR, and ast_cli_entry::usage.

02532 {
02533    struct ast_fax_session *s;
02534    struct ao2_iterator i;
02535    int session_count;
02536    char *filenames;
02537 
02538    switch (cmd) {
02539    case CLI_INIT:
02540       e->command = "fax show sessions";
02541       e->usage =
02542          "Usage: fax show sessions\n"
02543          "       Shows the current FAX sessions\n";
02544       return NULL;
02545    case CLI_GENERATE:
02546       return NULL;
02547    }
02548 
02549    ast_cli(a->fd, "\nCurrent FAX Sessions:\n\n");
02550    ast_cli(a->fd, "%-20.20s %-10.10s %-10.10s %-5.5s %-10.10s %-15.15s %-30.30s\n",
02551       "Channel", "Tech", "FAXID", "Type", "Operation", "State", "File(s)");
02552    i = ao2_iterator_init(faxregistry.container, 0);
02553    while ((s = ao2_iterator_next(&i))) {
02554       ao2_lock(s);
02555 
02556       if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
02557          ast_log(LOG_ERROR, "error printing filenames for 'fax show sessions' command");
02558          ao2_unlock(s);
02559          ao2_ref(s, -1);
02560          if (ao2_iterator_destroy != NULL) {
02561             ao2_iterator_destroy(&i);
02562          }
02563          return CLI_FAILURE;
02564       }
02565 
02566       ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
02567          s->channame, s->tech->type, s->id,
02568          (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
02569          (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
02570          ast_fax_state_to_str(s->state), filenames);
02571 
02572       ast_free(filenames);
02573       ao2_unlock(s);
02574       ao2_ref(s, -1);
02575    }
02576    if (ao2_iterator_destroy != NULL) {
02577       ao2_iterator_destroy(&i);
02578    }
02579    session_count = ao2_container_count(faxregistry.container);
02580    ast_cli(a->fd, "\n%d FAX sessions\n\n", session_count);
02581 
02582    return CLI_SUCCESS;
02583 }

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 2427 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, ast_cli_args::fd, general_options, fax_module::list, modems, fax_module::tech, ast_fax_tech::type, and ast_cli_entry::usage.

02428 {
02429    struct fax_module *fax;
02430    char modems[128] = "";
02431 
02432    switch (cmd) {
02433    case CLI_INIT:
02434       e->command = "fax show settings";
02435       e->usage =
02436          "Usage: fax show settings\n"
02437          "       Show the global settings and defaults of both the FAX core and technology modules\n";
02438       return NULL;
02439    case CLI_GENERATE:
02440       return NULL;
02441    }
02442 
02443    ast_cli(a->fd, "FAX For Asterisk Settings:\n");
02444    ast_cli(a->fd, "\tECM: %s\n", general_options.ecm ? "Enabled" : "Disabled");
02445    ast_cli(a->fd, "\tStatus Events: %s\n",  general_options.statusevents ? "On" : "Off");
02446    ast_cli(a->fd, "\tMinimum Bit Rate: %d\n", general_options.minrate);
02447    ast_cli(a->fd, "\tMaximum Bit Rate: %d\n", general_options.maxrate);
02448    ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02449    ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
02450    ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
02451    AST_RWLIST_RDLOCK(&faxmodules);
02452    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02453       ast_cli(a->fd, "%s (%s) Settings:\n", fax->tech->type, fax->tech->description);
02454       fax->tech->cli_show_settings(a->fd);
02455    }
02456    AST_RWLIST_UNLOCK(&faxmodules);
02457 
02458    return CLI_SUCCESS;
02459 }

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 2498 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::list, fax_module::tech, and ast_cli_entry::usage.

02499 {
02500    struct fax_module *fax;
02501    
02502    switch (cmd) {
02503    case CLI_INIT:
02504       e->command = "fax show stats";
02505       e->usage =
02506          "Usage: fax show stats\n"
02507          "       Shows a statistical summary of FAX transmissions\n";
02508       return NULL;
02509    case CLI_GENERATE:
02510       return NULL;
02511    }
02512 
02513    ast_cli(a->fd, "\nFAX Statistics:\n---------------\n\n");
02514    ast_cli(a->fd, "%-20.20s : %d\n", "Current Sessions", faxregistry.active_sessions);
02515    ast_cli(a->fd, "%-20.20s : %d\n", "Reserved Sessions", faxregistry.reserved_sessions);
02516    ast_cli(a->fd, "%-20.20s : %d\n", "Transmit Attempts", faxregistry.fax_tx_attempts);
02517    ast_cli(a->fd, "%-20.20s : %d\n", "Receive Attempts", faxregistry.fax_rx_attempts);
02518    ast_cli(a->fd, "%-20.20s : %d\n", "Completed FAXes", faxregistry.fax_complete);
02519    ast_cli(a->fd, "%-20.20s : %d\n", "Failed FAXes", faxregistry.fax_failures);
02520    AST_RWLIST_RDLOCK(&faxmodules);
02521    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02522       fax->tech->cli_show_stats(a->fd);
02523    }
02524    AST_RWLIST_UNLOCK(&faxmodules);
02525    ast_cli(a->fd, "\n\n");
02526 
02527    return CLI_SUCCESS;
02528 }

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

Definition at line 2330 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::list, fax_module::tech, ast_cli_entry::usage, and ast_fax_tech::version.

02331 {
02332    struct fax_module *fax;
02333 
02334    switch(cmd) {
02335    case CLI_INIT:
02336       e->command = "fax show version";
02337       e->usage =
02338          "Usage: fax show version\n"
02339          "       Show versions of FAX For Asterisk components.\n";
02340       return NULL;
02341    case CLI_GENERATE:
02342       return NULL;
02343    }
02344 
02345    if (a->argc != 3) {
02346       return CLI_SHOWUSAGE;
02347    }
02348 
02349    ast_cli(a->fd, "FAX For Asterisk Components:\n");
02350    ast_cli(a->fd, "\tApplications: %s\n", ast_get_version());
02351    AST_RWLIST_RDLOCK(&faxmodules);
02352    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02353       ast_cli(a->fd, "\t%s: %s\n", fax->tech->description, fax->tech->version);
02354    }
02355    AST_RWLIST_UNLOCK(&faxmodules);
02356    ast_cli(a->fd, "\n");
02357 
02358    return CLI_SUCCESS;
02359 }

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

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

00288 {  
00289    struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
00290    int dspsilence;
00291    unsigned int last_consec_frames, last_consec_ms;
00292    unsigned char wassil;
00293    struct timeval diff;
00294 
00295    diff = ast_tvsub(ast_tvnow(), s->debug_info->base_tv);
00296 
00297    ast_dsp_reset(s->debug_info->dsp);
00298    ast_dsp_silence(s->debug_info->dsp, frame, &dspsilence);
00299 
00300    wassil = history->silence;
00301    history->silence = (dspsilence != 0) ? 1 : 0;
00302    if (history->silence != wassil) {
00303       last_consec_frames = history->consec_frames;
00304       last_consec_ms = history->consec_ms;
00305       history->consec_frames = 0;
00306       history->consec_ms = 0;
00307 
00308       if ((last_consec_frames != 0)) {
00309          ast_verb(6, "Channel '%s' fax session '%d', [ %.3ld.%.6ld ], %s sent %d frames (%d ms) of %s.\n",
00310              s->channame, s->id, (long) diff.tv_sec, (long int) diff.tv_usec,
00311              (c2s) ? "channel" : "stack", last_consec_frames, last_consec_ms,
00312              (wassil) ? "silence" : "energy");
00313       }
00314    }
00315 
00316    history->consec_frames++;
00317    history->consec_ms += (frame->samples / 8);
00318 }

static void destroy_callback ( void *  data  )  [static]

Definition at line 320 of file res_fax.c.

References ao2_ref.

00321 {
00322    if (data) {
00323       ao2_ref(data, -1);
00324    }
00325 }

static void destroy_session ( void *  session  )  [static]

destroy a FAX session structure

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

00699 {
00700    struct ast_fax_session *s = session;
00701 
00702    if (s->tech) {
00703       fax_session_release(s, NULL);
00704       if (s->tech_pvt) {
00705          s->tech->destroy_session(s);
00706       }
00707       ast_module_unref(s->tech->module);
00708    }
00709 
00710    if (s->details) {
00711       ao2_ref(s->details, -1);
00712    }
00713    
00714    if (s->debug_info) {
00715       ast_dsp_free(s->debug_info->dsp);
00716       ast_free(s->debug_info);
00717    }
00718 
00719    if (s->smoother) {
00720       ast_smoother_free(s->smoother);
00721    }
00722 
00723    if (s->state != AST_FAX_STATE_INACTIVE) {
00724       ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
00725    }
00726 
00727    ast_free(s->channame);
00728    ast_free(s->chan_uniqueid);
00729 }

static void destroy_session_details ( void *  details  )  [static]

destroy a FAX session details structure

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

00356 {
00357    struct ast_fax_session_details *d = details;
00358    struct ast_fax_document *doc;
00359    
00360    while ((doc = AST_LIST_REMOVE_HEAD(&d->documents, next))) {
00361       ast_free(doc);
00362    }
00363    ast_string_field_free_memory(d); 
00364 }

static int disable_t38 ( struct ast_channel chan  )  [static]

Definition at line 1059 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_T38_REFUSED, AST_T38_REQUEST_TERMINATE, AST_T38_TERMINATED, ast_waitfor(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_frame::ptr, ast_control_t38_parameters::request_response, and ast_frame::subclass.

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

01060 {
01061    int ms;
01062    struct ast_frame *frame = NULL;
01063    struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
01064 
01065    ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
01066    if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
01067       ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01068       return -1;
01069    }
01070 
01071    /* wait up to five seconds for negotiation to complete */
01072    ms = 5000;
01073 
01074    while (ms > 0) {
01075       ms = ast_waitfor(chan, ms);
01076       if (ms < 0) {
01077          ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01078          return -1;
01079       }
01080 
01081       if (ms == 0) { /* all done, nothing happened */
01082          ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
01083          break;
01084       }
01085 
01086       if (!(frame = ast_read(chan))) {
01087          return -1;
01088       }
01089       if ((frame->frametype == AST_FRAME_CONTROL) &&
01090           (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01091           (frame->datalen == sizeof(t38_parameters))) {
01092          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01093 
01094          switch (parameters->request_response) {
01095          case AST_T38_TERMINATED:
01096             ast_debug(1, "Shut down T.38 on %s\n", chan->name);
01097             break;
01098          case AST_T38_REFUSED:
01099             ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", chan->name);
01100             ast_frfree(frame);
01101             return -1;
01102          default:
01103             ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", chan->name);
01104             ast_frfree(frame);
01105             return -1;
01106          }
01107          ast_frfree(frame);
01108          break;
01109       }
01110       ast_frfree(frame);
01111    }
01112 
01113    return 0;
01114 }

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

convert a rate string to a rate

Definition at line 661 of file res_fax.c.

References ast_log(), LOG_ERROR, and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

00662 {
00663    int rate;
00664 
00665    if (sscanf(ratestr, "%d", &rate) != 1) {
00666       ast_log(LOG_ERROR, "failed to sscanf '%s' to rate\n", ratestr);
00667       return 0;
00668    }
00669    switch (rate) {
00670    case 2400:
00671    case 4800:
00672    case 7200:
00673    case 9600:
00674    case 12000:
00675    case 14400:
00676    case 28800:
00677    case 33600:
00678       return rate;
00679    default:
00680       ast_log(LOG_WARNING, "ignoring invalid rate '%s'.  Valid options are {2400 | 4800 | 7200 | 9600 | 12000 | 14400 | 28800 | 33600}\n", ratestr);
00681       return 0;
00682    }
00683 }

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]

create a FAX session

Definition at line 781 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_details::debug, ast_fax_tech::description, destroy_session(), fax_session_release(), faxregistry, ast_fax_session_details::id, fax_module::list, LOG_ERROR, ast_fax_tech::module, ast_channel::name, ast_fax_session_details::option, ast_fax_session::state, fax_module::tech, and ast_channel::uniqueid.

Referenced by generic_fax_exec().

00782 {
00783    struct ast_fax_session *s = NULL;
00784    struct fax_module *faxmod;
00785    char caps[128] = "";
00786 
00787    if (reserved) {
00788       s = reserved;
00789       ao2_ref(reserved, +1);
00790 
00791       if (s->state == AST_FAX_STATE_RESERVED) {
00792          ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00793          s->state = AST_FAX_STATE_UNINITIALIZED;
00794       }
00795    }
00796 
00797    if (!s && !(s = ao2_alloc(sizeof(*s), destroy_session))) {
00798       return NULL;
00799    }
00800 
00801    ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
00802    s->state = AST_FAX_STATE_UNINITIALIZED;
00803 
00804    if (details->option.debug && (details->caps & AST_FAX_TECH_AUDIO)) {
00805       if (!(s->debug_info = ast_calloc(1, sizeof(*(s->debug_info))))) {
00806          fax_session_release(s, token);
00807          ao2_ref(s, -1);
00808          return NULL;
00809       }
00810       if (!(s->debug_info->dsp = ast_dsp_new())) {
00811          ast_free(s->debug_info);
00812          s->debug_info = NULL;
00813          fax_session_release(s, token);
00814          ao2_ref(s, -1);
00815          return NULL;
00816       }
00817       ast_dsp_set_threshold(s->debug_info->dsp, 128);
00818    }  
00819 
00820    if (!(s->channame = ast_strdup(chan->name))) {
00821       fax_session_release(s, token);
00822       ao2_ref(s, -1);
00823       return NULL;
00824    }
00825 
00826    if (!(s->chan_uniqueid = ast_strdup(chan->uniqueid))) {
00827       fax_session_release(s, token);
00828       ao2_ref(s, -1);
00829       return NULL;
00830    }
00831 
00832    s->chan = chan;
00833    s->details = details;
00834    ao2_ref(s->details, 1);
00835 
00836    details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
00837 
00838    if (!token) {
00839       /* locate a FAX technology module that can handle said requirements */
00840       AST_RWLIST_RDLOCK(&faxmodules);
00841       AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00842          if ((faxmod->tech->caps & details->caps) != details->caps) {
00843             continue;
00844          }
00845          ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
00846          ast_module_ref(faxmod->tech->module);
00847          s->tech = faxmod->tech;
00848          break;
00849       }
00850       AST_RWLIST_UNLOCK(&faxmodules);
00851 
00852       if (!faxmod) {
00853          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)));
00854          ao2_ref(s, -1);
00855          return NULL;
00856       }
00857    }
00858 
00859    if (!(s->tech_pvt = s->tech->new_session(s, token))) {
00860       ast_log(LOG_ERROR, "FAX session failed to initialize.\n");
00861       ao2_ref(s, -1);
00862       return NULL;
00863    }
00864    /* link the session to the session container */
00865    if (!(ao2_link(faxregistry.container, s))) {
00866       ast_log(LOG_ERROR, "failed to add FAX session '%d' to container.\n", s->id);
00867       ao2_ref(s, -1);
00868       return NULL;
00869    }
00870    ast_debug(4, "channel '%s' using FAX session '%d'\n", s->channame, s->id);
00871 
00872    return s;
00873 }

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

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

00686 {
00687    if (token) {
00688       s->tech->release_token(token);
00689    }
00690 
00691    if (s->state == AST_FAX_STATE_RESERVED) {
00692       ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00693       s->state = AST_FAX_STATE_INACTIVE;
00694    }
00695 }

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

Definition at line 731 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, fax_module::list, LOG_ERROR, ast_fax_tech::module, ast_fax_session::state, and fax_module::tech.

Referenced by receivefax_exec(), and sendfax_exec().

00732 {
00733    struct ast_fax_session *s;
00734    struct fax_module *faxmod;
00735    char caps[128] = "";
00736 
00737    if (!(s = ao2_alloc(sizeof(*s), destroy_session))) {
00738       return NULL;
00739    }
00740 
00741    s->state = AST_FAX_STATE_INACTIVE;
00742 
00743    /* locate a FAX technology module that can handle said requirements
00744     * Note: the requirements have not yet been finalized as T.38
00745     * negotiation has not yet occured. */
00746    AST_RWLIST_RDLOCK(&faxmodules);
00747    AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00748       if ((faxmod->tech->caps & details->caps) != details->caps) {
00749          continue;
00750       }
00751       ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
00752       ast_module_ref(faxmod->tech->module);
00753       s->tech = faxmod->tech;
00754       break;
00755    }
00756    AST_RWLIST_UNLOCK(&faxmodules);
00757 
00758    if (!faxmod) {
00759       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)));
00760       ao2_ref(s, -1);
00761       return NULL;
00762    }
00763 
00764    if (!s->tech->reserve_session) {
00765       ast_debug(1, "Selected FAX technology module (%s) does not support reserving sessions.\n", s->tech->description);
00766       return s;
00767    }
00768 
00769    if (!(*token = s->tech->reserve_session(s))) {
00770       ao2_ref(s, -1);
00771       return NULL;
00772    }
00773 
00774    s->state = AST_FAX_STATE_RESERVED;
00775    ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, 1);
00776 
00777    return s;
00778 }

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

fax session tab completion

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

02301 {
02302    int tklen;
02303    int wordnum = 0;
02304    char *name = NULL;
02305    struct ao2_iterator i;
02306    struct ast_fax_session *s;
02307    char tbuf[5];
02308 
02309    if (a->pos != 3) {
02310       return NULL;
02311    }
02312 
02313    tklen = strlen(a->word);
02314    i = ao2_iterator_init(faxregistry.container, 0);
02315    while ((s = ao2_iterator_next(&i))) {
02316       snprintf(tbuf, sizeof(tbuf), "%d", s->id);
02317       if (!strncasecmp(a->word, tbuf, tklen) && ++wordnum > a->n) {
02318          name = ast_strdup(tbuf);
02319          ao2_ref(s, -1);
02320          break;
02321       }
02322       ao2_ref(s, -1);
02323    }
02324    if (ao2_iterator_destroy != NULL) {
02325       ao2_iterator_destroy(&i);
02326    }
02327    return name;
02328 }

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

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

Definition at line 333 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, LOG_WARNING, and ast_channel::name.

Referenced by acf_faxopt_read(), and find_or_create_details().

00334 {
00335    struct ast_fax_session_details *details;
00336    struct ast_datastore *datastore;
00337 
00338    ast_channel_lock(chan); 
00339    if (!(datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL))) {
00340       ast_channel_unlock(chan);  
00341       return NULL;
00342    }
00343    if (!(details = datastore->data)) {
00344       ast_log(LOG_WARNING, "Huh?  channel '%s' has a FAX datastore without data!\n", chan->name);
00345       ast_channel_unlock(chan);
00346       return NULL;
00347    }
00348    ao2_ref(details, 1); 
00349    ast_channel_unlock(chan);  
00350 
00351    return details;
00352 }

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

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 398 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, ast_channel::name, and session_details_new().

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

00399 {
00400    struct ast_fax_session_details *details;
00401    struct ast_datastore *datastore;
00402 
00403    if ((details = find_details(chan))) {
00404       return details;
00405    }
00406    /* channel does not have one so we must create one */
00407    if (!(details = session_details_new())) {
00408       ast_log(LOG_WARNING, "channel '%s' can't get a FAX details structure for the datastore!\n", chan->name);
00409       return NULL;
00410    }
00411    if (!(datastore = ast_datastore_alloc(&fax_datastore, NULL))) {
00412       ao2_ref(details, -1);
00413       ast_log(LOG_WARNING, "channel '%s' can't get a datastore!\n", chan->name);
00414       return NULL;
00415    }
00416    /* add the datastore to the channel and increment the refcount */
00417    datastore->data = details;
00418    ao2_ref(details, 1);
00419    ast_channel_lock(chan);
00420    ast_channel_datastore_add(chan, datastore);
00421    ast_channel_unlock(chan);
00422    return details;
00423 }

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

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

00895 {
00896    char *filenames, *c;
00897    size_t size = 0;
00898    int first = 1;
00899    struct ast_fax_document *doc;
00900 
00901    /* don't process empty lists */
00902    if (AST_LIST_EMPTY(&details->documents)) {
00903       return NULL;
00904    }
00905 
00906    /* Calculate the total length of all of the file names */
00907    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00908       size += strlen(separator) + strlen(prefix) + strlen(doc->filename);
00909    }
00910    size += 1; /* add space for the terminating null */
00911 
00912    if (!(filenames = ast_malloc(size))) {
00913       return NULL;
00914    }
00915    c = filenames;
00916 
00917    ast_build_string(&c, &size, "%s%s", prefix, AST_LIST_FIRST(&details->documents)->filename);
00918    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00919       if (first) {
00920          first = 0;
00921          continue;
00922       }
00923 
00924       ast_build_string(&c, &size, "%s%s%s", separator, prefix, doc->filename);
00925    }
00926 
00927    return filenames;
00928 }

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 1124 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_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, 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_details::headerinfo, ast_fax_session::id, ast_frame_subclass::integer, ast_fax_session_details::localstationid, LOG_ERROR, LOG_WARNING, ast_channel::name, 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, ast_fax_session_details::result, 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().

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

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

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

00876 {
00877    pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
00878    pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
00879    pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
00880 }

static int load_module ( void   )  [static]

load res_fax

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

02820 {
02821    int res;
02822 
02823    /* initialize the registry */
02824    faxregistry.active_sessions = 0;
02825    faxregistry.reserved_sessions = 0;
02826    if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
02827       return AST_MODULE_LOAD_DECLINE;
02828    }
02829    
02830    if (set_config(config) < 0) {
02831       ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
02832       ao2_ref(faxregistry.container, -1);
02833       return AST_MODULE_LOAD_DECLINE;
02834    }
02835 
02836    /* register CLI operations and applications */
02837    if (ast_register_application_xml(app_sendfax, sendfax_exec) < 0) {
02838       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_sendfax);
02839       ao2_ref(faxregistry.container, -1);
02840       return AST_MODULE_LOAD_DECLINE;
02841    }
02842    if (ast_register_application_xml(app_receivefax, receivefax_exec) < 0) {
02843       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_receivefax);
02844       ast_unregister_application(app_sendfax);
02845       ao2_ref(faxregistry.container, -1);
02846       return AST_MODULE_LOAD_DECLINE;
02847    }
02848    ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
02849    res = ast_custom_function_register(&acf_faxopt);   
02850    fax_logger_level = ast_logger_register_level("FAX");
02851 
02852    return res;
02853 }

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

initiate a receive FAX session

Definition at line 1535 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, modems, ast_channel::name, 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(), 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().

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

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

Definition at line 1382 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_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, 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_channel::name, 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().

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

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 931 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(), ast_fax_session_details::localstationid, manager_event, ast_channel::name, ast_fax_session_details::option, and ast_fax_session_details::statusevents.

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

00932 {
00933    char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
00934    if (!filenames) {
00935       return 1;
00936    }
00937 
00938    ast_channel_lock(chan);
00939    if (details->option.statusevents) {
00940       struct manager_event_info info;
00941 
00942       get_manager_event_info(chan, &info);
00943       manager_event(EVENT_FLAG_CALL,
00944                (details->caps & AST_FAX_TECH_RECEIVE) ? "ReceiveFAXStatus" : "SendFAXStatus",
00945                "Status: %s\r\n"
00946                "Channel: %s\r\n"
00947                "Context: %s\r\n"
00948                "Exten: %s\r\n"
00949                "CallerID: %s\r\n"
00950                "LocalStationID: %s\r\n"
00951                "%s\r\n",
00952                status,
00953                chan->name,
00954                info.context,
00955                info.exten,
00956                info.cid,
00957                details->localstationid,
00958                filenames);
00959    }
00960    ast_channel_unlock(chan);
00961    ast_free(filenames);
00962 
00963    return 0;
00964 }

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

initiate a send FAX session

Definition at line 2006 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, modems, ast_channel::name, 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, ast_fax_session_details::send_cng, sendfax_t38_init(), set_channel_variables(), set_fax_t38_caps(), ast_fax_session_details::statusevents, strsep(), T38_STATE_NEGOTIATED, and T38_STATE_UNAVAILABLE.

Referenced by load_module().

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

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

Definition at line 1780 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_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, 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_channel::name, 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().

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

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

compare callback for ao2

Definition at line 2292 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

02293 {
02294    struct ast_fax_session *lhs = obj, *rhs = arg;
02295 
02296    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02297 }

static struct ast_fax_session_details* session_details_new ( void   )  [static]

create a FAX session details structure

Definition at line 367 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(), and general_options.

Referenced by find_or_create_details().

00368 {
00369    struct ast_fax_session_details *d;
00370 
00371    if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) {
00372       return NULL;
00373    }
00374    
00375    if (ast_string_field_init(d, 512)) {
00376       ao2_ref(d, -1);
00377       return NULL;
00378    }
00379 
00380    AST_LIST_HEAD_INIT_NOLOCK(&d->documents);
00381 
00382    /* These options need to be set to the configured default and may be overridden by
00383     * SendFAX, ReceiveFAX, or FAXOPT */
00384    d->option.request_t38 = AST_FAX_OPTFLAG_FALSE;
00385    d->option.send_cng = AST_FAX_OPTFLAG_FALSE;
00386    d->option.send_ced = AST_FAX_OPTFLAG_FALSE;
00387    d->option.ecm = general_options.ecm;
00388    d->option.statusevents = general_options.statusevents;
00389    d->modems = general_options.modems;
00390    d->minrate = general_options.minrate;
00391    d->maxrate = general_options.maxrate;
00392 
00393    return d;
00394 }

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

hash callback for ao2

Definition at line 2284 of file res_fax.c.

References ast_fax_session::id.

Referenced by load_module().

02285 {
02286    const struct ast_fax_session *s = obj;
02287 
02288    return s->id;
02289 }

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

Set fax related channel variables.

Definition at line 967 of file res_fax.c.

References ast_fax_session_details::error, ast_fax_session_details::pages_transferred, pbx_builtin_setvar_helper(), ast_fax_session_details::remotestationid, ast_fax_session_details::resolution, ast_fax_session_details::result, ast_fax_session_details::resultstr, S_OR, and ast_fax_session_details::transfer_rate.

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

00968 {
00969    char buf[10];
00970    pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL));
00971    pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL));
00972    pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL));
00973    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", S_OR(details->remotestationid, NULL));
00974    pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL));
00975    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL));
00976 
00977    snprintf(buf, sizeof(buf), "%d", details->pages_transferred);
00978    pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
00979 }

static int set_config ( const char *  config_file  )  [static]

configure res_fax

Definition at line 2596 of file res_fax.c.

References ast_clear_flag, ast_config_destroy(), ast_config_load2(), ast_debug, AST_FAX_OPTFLAG_TRUE, ast_log(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, fax_rate_str_to_int(), general_options, LOG_NOTICE, modems, ast_variable::name, ast_variable::next, RES_FAX_MAXRATE, RES_FAX_MINRATE, RES_FAX_MODEM, RES_FAX_STATUSEVENTS, and ast_variable::value.

02597 {
02598    struct ast_config *cfg;
02599    struct ast_variable *v;
02600    struct ast_flags config_flags = { 0 };
02601    char modems[128] = "";
02602 
02603    /* set defaults */   
02604    general_options.minrate = RES_FAX_MINRATE;
02605    general_options.maxrate = RES_FAX_MAXRATE;   
02606    general_options.statusevents = RES_FAX_STATUSEVENTS;
02607    general_options.modems = RES_FAX_MODEM;
02608    general_options.ecm = AST_FAX_OPTFLAG_TRUE;
02609 
02610    /* read configuration */
02611    if (!(cfg = ast_config_load2(config_file, "res_fax", config_flags))) {
02612       ast_log(LOG_NOTICE, "Configuration file '%s' not found, using default options.\n", config_file);
02613       return 0;
02614    }
02615    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
02616       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
02617       cfg = ast_config_load2(config_file, "res_fax", config_flags);
02618    }
02619 
02620    /* create configuration */
02621    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
02622       int rate;
02623 
02624       if (!strcasecmp(v->name, "minrate")) {
02625          ast_debug(3, "reading minrate '%s' from configuration file\n", v->value);
02626          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02627             ast_config_destroy(cfg);
02628             return -1;
02629          }
02630          general_options.minrate = rate;
02631       } else if (!strcasecmp(v->name, "maxrate")) {
02632          ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value);
02633          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02634             ast_config_destroy(cfg);
02635             return -1;
02636          }
02637          general_options.maxrate = rate;
02638       } else if (!strcasecmp(v->name, "statusevents")) {
02639          ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value);
02640          general_options.statusevents = ast_true(v->value);
02641       } else if (!strcasecmp(v->name, "ecm")) {
02642          ast_debug(3, "reading ecm '%s' from configuration file\n", v->value);
02643          general_options.ecm = ast_true(v->value);
02644       } else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
02645          general_options.modems = 0;
02646          update_modem_bits(&general_options.modems, v->value);
02647       }
02648    }
02649 
02650    ast_config_destroy(cfg);
02651 
02652    if (general_options.maxrate < general_options.minrate) {
02653       ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", general_options.maxrate, general_options.minrate);
02654       return -1;
02655    }
02656 
02657    if (check_modem_rate(general_options.modems, general_options.minrate)) {
02658       ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02659       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, general_options.minrate);
02660       return -1;
02661    }
02662 
02663    if (check_modem_rate(general_options.modems, general_options.maxrate)) {
02664       ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02665       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, general_options.maxrate);
02666       return -1;
02667    }
02668 
02669    return 0;
02670 }

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

Definition at line 1026 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_channel::name, ast_control_t38_parameters::request_response, T38_STATE_NEGOTIATING, T38_STATE_UNAVAILABLE, and T38_STATE_UNKNOWN.

Referenced by receivefax_exec(), and sendfax_exec().

01027 {
01028    switch (ast_channel_get_t38_state(chan)) {
01029    case T38_STATE_UNKNOWN:
01030       details->caps |= AST_FAX_TECH_T38;
01031       break;
01032    case T38_STATE_UNAVAILABLE:
01033       details->caps |= AST_FAX_TECH_AUDIO;
01034       break;
01035    case T38_STATE_NEGOTIATING: {
01036       /* the other end already sent us a T.38 reinvite, so we need to prod the channel
01037        * driver into resending their parameters to us if it supports doing so... if
01038        * not, we can't proceed, because we can't create a proper reply without them.
01039        * if it does work, the channel driver will send an AST_CONTROL_T38_PARAMETERS
01040        * with a request of AST_T38_REQUEST_NEGOTIATE, which will be read by the function
01041        * that gets called after this one completes
01042        */
01043       struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, };
01044       if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters)) != AST_T38_REQUEST_PARMS) {
01045          ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01046          return -1;
01047       }
01048       details->caps |= AST_FAX_TECH_T38;
01049       break;
01050    }
01051    default:
01052       ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01053       return -1;
01054    }
01055 
01056    return 0;
01057 }

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

Definition at line 1004 of file res_fax.c.

References ast_control_t38_parameters::fill_bit_removal, ast_fax_t38_parameters::fill_bit_removal, ast_control_t38_parameters::max_ifp, ast_fax_t38_parameters::max_ifp, ast_control_t38_parameters::rate, ast_fax_t38_parameters::rate, ast_control_t38_parameters::rate_management, ast_fax_t38_parameters::rate_management, ast_control_t38_parameters::transcoding_jbig, ast_fax_t38_parameters::transcoding_jbig, ast_control_t38_parameters::transcoding_mmr, ast_fax_t38_parameters::transcoding_mmr, ast_control_t38_parameters::version, and ast_fax_t38_parameters::version.

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

01005 {
01006    dst->version = src->version;
01007    dst->max_ifp = src->max_ifp;
01008    dst->rate = src->rate;
01009    dst->rate_management = src->rate_management;
01010    dst->fill_bit_removal = src->fill_bit_removal;
01011    dst->transcoding_mmr = src->transcoding_mmr;
01012    dst->transcoding_jbig = src->transcoding_jbig;
01013 }

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

Definition at line 1015 of file res_fax.c.

References ast_fax_t38_parameters::fill_bit_removal, ast_control_t38_parameters::fill_bit_removal, ast_fax_t38_parameters::max_ifp, ast_control_t38_parameters::max_ifp, ast_fax_t38_parameters::rate, ast_control_t38_parameters::rate, ast_fax_t38_parameters::rate_management, ast_control_t38_parameters::rate_management, ast_fax_t38_parameters::transcoding_jbig, ast_control_t38_parameters::transcoding_jbig, ast_fax_t38_parameters::transcoding_mmr, ast_control_t38_parameters::transcoding_mmr, ast_fax_t38_parameters::version, and ast_control_t38_parameters::version.

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

01016 {
01017    dst->version = src->version;
01018    dst->max_ifp = src->max_ifp;
01019    dst->rate = src->rate;
01020    dst->rate_management = src->rate_management;
01021    dst->fill_bit_removal = src->fill_bit_removal;
01022    dst->transcoding_mmr = src->transcoding_mmr;
01023    dst->transcoding_jbig = src->transcoding_jbig;
01024 }

static int unload_module ( void   )  [static]

unload res_fax

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

02794 {
02795    ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
02796    
02797    if (ast_custom_function_unregister(&acf_faxopt) < 0) {
02798       ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
02799    }
02800 
02801    if (ast_unregister_application(app_sendfax) < 0) {
02802       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_sendfax);
02803    }
02804 
02805    if (ast_unregister_application(app_receivefax) < 0) {
02806       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
02807    }
02808 
02809    if (fax_logger_level != -1) {
02810       ast_logger_unregister_level("FAX");
02811    }
02812 
02813    ao2_ref(faxregistry.container, -1);
02814 
02815    return 0;
02816 }

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

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

00436 {     
00437    char *m[5], *tok, *v = (char *)value;
00438    int i = 0, j;
00439 
00440    if (!(tok = strchr(v, ','))) {
00441       m[i++] = v;
00442       m[i] = NULL;
00443    } else {
00444       tok = strtok(v, ", ");
00445       while (tok && (i < 5)) {
00446          m[i++] = tok;
00447          tok = strtok(NULL, ", ");
00448       }
00449       m[i] = NULL;
00450    }
00451 
00452    *bits = 0;
00453    for (j = 0; j < i; j++) {
00454       if (!strcasecmp(m[j], "v17")) {
00455          *bits |= AST_FAX_MODEM_V17;
00456       } else if (!strcasecmp(m[j], "v27")) {
00457          *bits |= AST_FAX_MODEM_V27;
00458       } else if (!strcasecmp(m[j], "v29")) {
00459          *bits |= AST_FAX_MODEM_V29;
00460       } else if (!strcasecmp(m[j], "v34")) {
00461          *bits |= AST_FAX_MODEM_V34;
00462       } else {
00463          ast_log(LOG_WARNING, "ignoring invalid modem setting: '%s', valid options {v17 | v27 | v29 | v34}\n", m[j]);
00464       }
00465    }
00466    return 0;
00467 }


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

Definition at line 2860 of file res_fax.c.

struct ast_custom_function acf_faxopt

Initial value:

 {
   .name = "FAXOPT",
   .read = acf_faxopt_read,
   .write = acf_faxopt_write,
}
FAXOPT dialplan function.

Definition at line 2786 of file res_fax.c.

Referenced by load_module(), and unload_module().

int active_sessions

The number of active FAX sessions

Definition at line 222 of file res_fax.c.

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

Definition at line 197 of file res_fax.c.

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

Definition at line 198 of file res_fax.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2860 of file res_fax.c.

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

Definition at line 259 of file res_fax.c.

struct ao2_container* container

active sessions are astobj2 objects

Definition at line 226 of file res_fax.c.

uint32_t ecm

Definition at line 254 of file res_fax.c.

struct ast_cli_entry fax_cli[] [static]

Definition at line 2585 of file res_fax.c.

Referenced by load_module(), and unload_module().

int fax_complete

Number of successful FAX transmissions

Definition at line 232 of file res_fax.c.

struct ast_datastore_info fax_datastore [static]

Initial value:

 {
   .type = "res_fax",
   .destroy = destroy_callback,
}

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

Referenced by receivefax_exec(), and sendfax_exec().

int fax_failures

Number of failed FAX transmissions

Definition at line 234 of file res_fax.c.

int fax_logger_level = -1 [static]

Definition at line 212 of file res_fax.c.

int fax_rx_attempts

Total number of Rx FAX attempts

Definition at line 230 of file res_fax.c.

int fax_tx_attempts

Total number of Tx FAX attempts

Definition at line 228 of file res_fax.c.

struct { ... } faxregistry [static]

The faxregistry is used to manage information and statistics for all FAX sessions.

Referenced by cli_fax_show_session(), cli_fax_show_sessions(), cli_fax_show_stats(), destroy_session(), fax_session_new(), fax_session_release(), fax_session_reserve(), fax_session_tab_complete(), generic_fax_exec(), load_module(), receivefax_exec(), sendfax_exec(), and unload_module().

struct { ... } general_options [static]

Referenced by ast_fax_maxrate(), ast_fax_minrate(), cli_fax_show_settings(), session_details_new(), and set_config().

int global_fax_debug = 0 [static]

Definition at line 261 of file res_fax.c.

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

unsigned int maxrate

Definition at line 256 of file res_fax.c.

unsigned int minrate

Definition at line 255 of file res_fax.c.

enum ast_fax_modems modems

Definition at line 252 of file res_fax.c.

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

int nextsessionname

the next unique session name

Definition at line 236 of file res_fax.c.

struct ast_control_t38_parameters our_t38_parameters [static]

Definition at line 1116 of file res_fax.c.

Referenced by receivefax_t38_init(), and sendfax_t38_init().

int reserved_sessions

The number of reserved FAX sessions

Definition at line 224 of file res_fax.c.

uint32_t statusevents

Definition at line 253 of file res_fax.c.


Generated on Wed Apr 6 11:30:09 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7