Sat Mar 10 01:55:40 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 216 of file res_fax.c.

Referenced by load_module().

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

Value:

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

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

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

Definition at line 983 of file res_fax.c.

Referenced by generic_fax_exec().

#define RES_FAX_MAXRATE   14400

Definition at line 248 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_MINRATE   2400

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

Referenced by set_config().

#define RES_FAX_STATUSEVENTS   0

Definition at line 249 of file res_fax.c.

Referenced by set_config().

#define RES_FAX_TIMEOUT   10000

Definition at line 218 of file res_fax.c.

Referenced by generic_fax_exec().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_CALLEDMODE 
OPT_CALLERMODE 
OPT_DEBUG 
OPT_STATUS 
OPT_ALLOWAUDIO 
OPT_REQUEST_T38 

Definition at line 264 of file res_fax.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2862 of file res_fax.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

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

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

References ast_log(), and ast_log_dynamic_level.

Referenced by spandsp_log().

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

unsigned int ast_fax_maxrate ( void   ) 

get the maxiumum supported fax rate

Definition at line 426 of file res_fax.c.

References general_options.

Referenced by acf_faxopt_write().

00427 {
00428    return general_options.maxrate;
00429 }

unsigned int ast_fax_minrate ( void   ) 

get the minimum supported fax rate

Definition at line 431 of file res_fax.c.

References general_options.

Referenced by acf_faxopt_write().

00432 {
00433    return general_options.minrate;
00434 }

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

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

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

const char* ast_fax_state_to_str ( enum ast_fax_state  state  ) 

convert an ast_fax_state to a string

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

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

int ast_fax_tech_register ( struct ast_fax_tech tech  ) 

register a fax technology

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

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

void ast_fax_tech_unregister ( struct ast_fax_tech tech  ) 

unregister a fax technology

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

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

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

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

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

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, session_count, 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          ao2_iterator_destroy(&i);
02561          return CLI_FAILURE;
02562       }
02563 
02564       ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
02565          s->channame, s->tech->type, s->id,
02566          (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
02567          (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
02568          ast_fax_state_to_str(s->state), filenames);
02569 
02570       ast_free(filenames);
02571       ao2_unlock(s);
02572       ao2_ref(s, -1);
02573    }
02574    ao2_iterator_destroy(&i);
02575    session_count = ao2_container_count(faxregistry.container);
02576    ast_cli(a->fd, "\n%d FAX sessions\n\n", session_count);
02577 
02578    return CLI_SUCCESS;
02579 }

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

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

static void destroy_callback ( void *  data  )  [static]

Definition at line 321 of file res_fax.c.

References ao2_ref.

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

static void destroy_session ( void *  session  )  [static]

destroy a FAX session structure

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

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

static void destroy_session_details ( void *  details  )  [static]

destroy a FAX session details structure

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

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

static int disable_t38 ( struct ast_channel chan  )  [static]

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

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

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

convert a rate string to a rate

Definition at line 662 of file res_fax.c.

References ast_log(), LOG_ERROR, and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

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

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

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

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

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

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

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

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

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

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

fax session tab completion

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

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

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

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

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

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

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

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

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

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

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

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

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

static int load_module ( void   )  [static]

load res_fax

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

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

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

initiate a receive FAX session

Definition at line 1537 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(), S_OR, ast_fax_session_details::send_ced, set_channel_variables(), set_fax_t38_caps(), ast_fax_session_details::statusevents, T38_STATE_NEGOTIATED, and T38_STATE_UNAVAILABLE.

Referenced by load_module().

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

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

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

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

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

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

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

initiate a send FAX session

Definition at line 2008 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, S_OR, 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().

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

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

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

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

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

compare callback for ao2

Definition at line 2294 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

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

static struct ast_fax_session_details* session_details_new ( void   )  [static]

create a FAX session details structure

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

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

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

hash callback for ao2

Definition at line 2286 of file res_fax.c.

References ast_fax_session::id.

Referenced by load_module().

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

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

Set fax related channel variables.

Definition at line 968 of file res_fax.c.

References ast_fax_session_details::error, ast_fax_session_details::localstationid, 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().

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

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

configure res_fax

Definition at line 2592 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_FILEINVALID, 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.

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

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

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

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

unload res_fax

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

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

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

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

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


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

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

Referenced by load_module(), and unload_module().

int active_sessions

The number of active FAX sessions

Definition at line 223 of file res_fax.c.

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

Definition at line 198 of file res_fax.c.

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

Definition at line 199 of file res_fax.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2862 of file res_fax.c.

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

Definition at line 260 of file res_fax.c.

struct ao2_container* container

active sessions are astobj2 objects

Definition at line 227 of file res_fax.c.

uint32_t ecm

Definition at line 255 of file res_fax.c.

struct ast_cli_entry fax_cli[] [static]

Definition at line 2581 of file res_fax.c.

Referenced by load_module(), and unload_module().

int fax_complete

Number of successful FAX transmissions

Definition at line 233 of file res_fax.c.

struct ast_datastore_info fax_datastore [static]

Initial value:

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

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

Referenced by receivefax_exec(), and sendfax_exec().

int fax_failures

Number of failed FAX transmissions

Definition at line 235 of file res_fax.c.

int fax_logger_level = -1 [static]

Definition at line 213 of file res_fax.c.

int fax_rx_attempts

Total number of Rx FAX attempts

Definition at line 231 of file res_fax.c.

int fax_tx_attempts

Total number of Tx FAX attempts

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

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

unsigned int maxrate

Definition at line 257 of file res_fax.c.

unsigned int minrate

Definition at line 256 of file res_fax.c.

enum ast_fax_modems modems

Definition at line 253 of file res_fax.c.

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

int nextsessionname

the next unique session name

Definition at line 237 of file res_fax.c.

struct ast_control_t38_parameters our_t38_parameters [static]

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

uint32_t statusevents

Definition at line 254 of file res_fax.c.


Generated on Sat Mar 10 01:55:41 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7