Mon Oct 8 12:39:27 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  fax_options
struct  faxmodules
struct  manager_event_info

Defines

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

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int acf_faxopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 FAXOPT read function returns the contents of a FAX option.
static int acf_faxopt_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 FAXOPT write function modifies the contents of a FAX option.
static char * ast_fax_caps_to_str (enum ast_fax_capabilities caps, char *buf, size_t bufsize)
void ast_fax_log (int level, const char *file, const int line, const char *function, const char *msg)
 Log message at FAX or recommended level.
unsigned int ast_fax_maxrate (void)
 get the maxiumum supported fax rate
unsigned int ast_fax_minrate (void)
 get the minimum supported fax rate
static int ast_fax_modem_to_str (enum ast_fax_modems bits, char *tbuf, size_t bufsize)
const char * ast_fax_state_to_str (enum ast_fax_state state)
 convert 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_general_options (struct fax_options *options)
static void get_manager_event_info (struct ast_channel *chan, struct manager_event_info *info)
static int load_module (void)
 load res_fax
static int receivefax_exec (struct ast_channel *chan, const char *data)
 initiate a receive FAX session
static int receivefax_t38_init (struct ast_channel *chan, struct ast_fax_session_details *details)
static int reload_module (void)
static int report_fax_status (struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
 send a FAX status manager event
static int sendfax_exec (struct ast_channel *chan, const char *data)
 initiate a send FAX session
static int sendfax_t38_init (struct ast_channel *chan, struct ast_fax_session_details *details)
static int session_cmp_cb (void *obj, void *arg, int flags)
 compare callback for ao2
static struct ast_fax_session_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 (int reload)
 configure res_fax
static int set_fax_t38_caps (struct ast_channel *chan, struct ast_fax_session_details *details)
static void set_general_options (const struct fax_options *options)
static void t38_parameters_ast_to_fax (struct ast_fax_t38_parameters *dst, const struct ast_control_t38_parameters *src)
static void t38_parameters_fax_to_ast (struct ast_control_t38_parameters *dst, const struct ast_fax_t38_parameters *src)
static int unload_module (void)
 unload res_fax
static int update_modem_bits (enum ast_fax_modems *bits, const char *value)

Variables

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


Detailed Description

Generic FAX Resource for FAX technology resource modules.

Author:
Dwayne M. Hubbard <dhubbard@digium.com>

Kevin P. Fleming <kpfleming@digium.com>

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

Definition in file res_fax.c.


Define Documentation

#define FAX_MAXBUCKETS   10

maximum buckets for res_fax ao2 containers

Definition at line 216 of file res_fax.c.

Referenced by load_module().

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

Value:

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

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

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

Definition at line 1007 of file res_fax.c.

Referenced by generic_fax_exec().

#define RES_FAX_MAXRATE   14400

Definition at line 248 of file res_fax.c.

#define RES_FAX_MINRATE   2400

Definition at line 247 of file res_fax.c.

#define RES_FAX_MODEM   (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)

Definition at line 250 of file res_fax.c.

#define RES_FAX_STATUSEVENTS   0

Definition at line 249 of file res_fax.c.

#define RES_FAX_TIMEOUT   10000

Definition at line 218 of file res_fax.c.

Referenced by generic_fax_exec().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_CALLEDMODE 
OPT_CALLERMODE 
OPT_DEBUG 
OPT_STATUS 
OPT_ALLOWAUDIO 
OPT_REQUEST_T38 

Definition at line 279 of file res_fax.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2926 of file res_fax.c.

static void __unreg_module ( void   )  [static]

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

02733 {
02734    struct ast_fax_session_details *details = find_details(chan);
02735    int res = 0;
02736    char *filenames;
02737 
02738    if (!details) {
02739       ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02740       return -1;
02741    }
02742    if (!strcasecmp(data, "ecm")) {
02743       ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
02744    } else if (!strcasecmp(data, "error")) {
02745       ast_copy_string(buf, details->error, len);
02746    } else if (!strcasecmp(data, "filename")) {
02747       if (AST_LIST_EMPTY(&details->documents)) {
02748          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02749          res = -1;
02750       } else {
02751          ast_copy_string(buf, AST_LIST_FIRST(&details->documents)->filename, len);
02752       }
02753    } else if (!strcasecmp(data, "filenames")) {
02754       if (AST_LIST_EMPTY(&details->documents)) {
02755          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02756          res = -1;
02757       } else if ((filenames = generate_filenames_string(details, "", ","))) {
02758          ast_copy_string(buf, filenames, len);
02759          ast_free(filenames);
02760       } else {
02761          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s), there was an error generating the filenames list.\n", chan->name, data);
02762          res = -1;
02763       }
02764    } else if (!strcasecmp(data, "headerinfo")) {
02765       ast_copy_string(buf, details->headerinfo, len);
02766    } else if (!strcasecmp(data, "localstationid")) {
02767       ast_copy_string(buf, details->localstationid, len);
02768    } else if (!strcasecmp(data, "maxrate")) {
02769       snprintf(buf, len, "%d", details->maxrate);
02770    } else if (!strcasecmp(data, "minrate")) {
02771       snprintf(buf, len, "%d", details->minrate);
02772    } else if (!strcasecmp(data, "pages")) {
02773       snprintf(buf, len, "%d", details->pages_transferred);
02774    } else if (!strcasecmp(data, "rate")) {
02775       ast_copy_string(buf, details->transfer_rate, len);
02776    } else if (!strcasecmp(data, "remotestationid")) {
02777       ast_copy_string(buf, details->remotestationid, len);
02778    } else if (!strcasecmp(data, "resolution")) {
02779       ast_copy_string(buf, details->resolution, len);
02780    } else if (!strcasecmp(data, "sessionid")) {
02781       snprintf(buf, len, "%d", details->id);
02782    } else if (!strcasecmp(data, "status")) {
02783       ast_copy_string(buf, details->result, len);
02784    } else if (!strcasecmp(data, "statusstr")) {
02785       ast_copy_string(buf, details->resultstr, len);
02786    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02787       ast_fax_modem_to_str(details->modems, buf, len);
02788    } else {
02789       ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", chan->name, data);
02790       res = -1;
02791    }
02792    ao2_ref(details, -1);
02793 
02794    return res;
02795 }

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

02799 {
02800    int res = 0;
02801    struct ast_fax_session_details *details;
02802 
02803    if (!(details = find_or_create_details(chan))) {
02804       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);
02805       return -1;
02806    }
02807    ast_debug(3, "channel '%s' setting FAXOPT(%s) to '%s'\n", chan->name, data, value);
02808 
02809    if (!strcasecmp(data, "ecm")) {
02810       const char *val = ast_skip_blanks(value);
02811       if (ast_true(val)) {
02812          details->option.ecm = AST_FAX_OPTFLAG_TRUE;
02813       } else if (ast_false(val)) {
02814          details->option.ecm = AST_FAX_OPTFLAG_FALSE;
02815       } else {
02816          ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
02817       }
02818    } else if (!strcasecmp(data, "headerinfo")) {
02819       ast_string_field_set(details, headerinfo, value);
02820    } else if (!strcasecmp(data, "localstationid")) {
02821       ast_string_field_set(details, localstationid, value);
02822    } else if (!strcasecmp(data, "maxrate")) {
02823       details->maxrate = fax_rate_str_to_int(value);
02824       if (!details->maxrate) {
02825          details->maxrate = ast_fax_maxrate();
02826       }
02827    } else if (!strcasecmp(data, "minrate")) {
02828       details->minrate = fax_rate_str_to_int(value);
02829       if (!details->minrate) {
02830          details->minrate = ast_fax_minrate();
02831       }
02832    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02833       update_modem_bits(&details->modems, value);
02834    } else {
02835       ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", chan->name, data, value);
02836       res = -1;
02837    }
02838 
02839    ao2_ref(details, -1);
02840 
02841    return res;
02842 }

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

Definition at line 494 of file res_fax.c.

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

Referenced by fax_session_new(), and fax_session_reserve().

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

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

Log message at FAX or recommended level.

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

ast_fax_log(LOG_DEBUG, msg);

Definition at line 676 of file res_fax.c.

References ast_log(), and ast_log_dynamic_level.

Referenced by spandsp_log().

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

unsigned int ast_fax_maxrate ( void   ) 

get the maxiumum supported fax rate

Definition at line 444 of file res_fax.c.

References get_general_options(), and fax_options::maxrate.

Referenced by acf_faxopt_write().

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

unsigned int ast_fax_minrate ( void   ) 

get the minimum supported fax rate

Definition at line 452 of file res_fax.c.

References get_general_options(), and fax_options::minrate.

Referenced by acf_faxopt_write().

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

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

Definition at line 539 of file res_fax.c.

References AST_FAX_MODEM_V17, AST_FAX_MODEM_V27, AST_FAX_MODEM_V29, and AST_FAX_MODEM_V34.

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

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

const char* ast_fax_state_to_str ( enum ast_fax_state  state  ) 

convert an ast_fax_state to a string

Definition at line 653 of file res_fax.c.

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

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

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

int ast_fax_tech_register ( struct ast_fax_tech tech  ) 

register a fax technology

Definition at line 612 of file res_fax.c.

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

Referenced by load_module().

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

void ast_fax_tech_unregister ( struct ast_fax_tech tech  ) 

unregister a fax technology

Definition at line 631 of file res_fax.c.

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

Referenced by unload_module().

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

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

Definition at line 572 of file res_fax.c.

References AST_FAX_MODEM_V17, AST_FAX_MODEM_V27, AST_FAX_MODEM_V29, and AST_FAX_MODEM_V34.

Referenced by receivefax_exec(), and sendfax_exec().

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

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

enable FAX debugging

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

02387 {
02388    int flag;
02389    const char *what;
02390 
02391    switch (cmd) {
02392    case CLI_INIT:
02393       e->command = "fax set debug {on|off}";
02394       e->usage = 
02395          "Usage: fax set debug { on | off }\n"
02396          "       Enable/Disable FAX debugging on new FAX sessions.  The basic FAX debugging will result in\n"
02397          "       additional events sent to manager sessions with 'call' class permissions.  When\n"
02398          "       verbosity is greater than '5' events will be displayed to the console and audio versus\n"
02399          "       energy analysis will be performed and displayed to the console.\n";
02400       return NULL;
02401    case CLI_GENERATE:
02402       return NULL;
02403    }
02404 
02405    what = a->argv[e->args-1];      /* guaranteed to exist */
02406    if (!strcasecmp(what, "on")) {
02407       flag = 1;
02408    } else if (!strcasecmp(what, "off")) {
02409       flag = 0;
02410    } else {
02411       return CLI_SHOWUSAGE;
02412    }
02413 
02414    global_fax_debug = flag;
02415    ast_cli(a->fd, "\n\nFAX Debug %s\n\n", (flag) ? "Enabled" : "Disabled");
02416 
02417    return CLI_SUCCESS;
02418 }

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

02422 {
02423    struct fax_module *fax;
02424    unsigned int num_modules = 0;
02425    
02426    switch (cmd) {
02427    case CLI_INIT:
02428       e->command = "fax show capabilities";
02429       e->usage = 
02430          "Usage: fax show capabilities\n"
02431          "       Shows the capabilities of the registered FAX technology modules\n";
02432       return NULL;
02433    case CLI_GENERATE:
02434       return NULL;
02435    }
02436 
02437    ast_cli(a->fd, "\n\nRegistered FAX Technology Modules:\n\n");
02438    AST_RWLIST_RDLOCK(&faxmodules);
02439    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02440       ast_cli(a->fd, "%-15s : %s\n%-15s : %s\n%-15s : ", "Type", fax->tech->type, "Description", fax->tech->description, "Capabilities");
02441       fax->tech->cli_show_capabilities(a->fd);
02442       num_modules++;
02443    }
02444    AST_RWLIST_UNLOCK(&faxmodules);
02445    ast_cli(a->fd, "%d registered modules\n\n", num_modules);
02446 
02447    return CLI_SUCCESS;
02448 }

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

02490 {
02491    struct ast_fax_session *s, tmp;
02492 
02493    switch (cmd) {
02494    case CLI_INIT:
02495       e->command = "fax show session";
02496       e->usage =
02497          "Usage: fax show session <session number>\n"
02498          "       Shows status of the named FAX session\n";
02499       return NULL;
02500    case CLI_GENERATE:
02501       return fax_session_tab_complete(a);
02502    }
02503 
02504    if (a->argc != 4) {
02505       return CLI_SHOWUSAGE;
02506    }
02507 
02508    if (sscanf(a->argv[3], "%d", &tmp.id) != 1) {
02509       ast_log(LOG_ERROR, "invalid session id: '%s'\n", a->argv[3]);
02510       return RESULT_SUCCESS;
02511    }
02512 
02513    ast_cli(a->fd, "\nFAX Session Details:\n--------------------\n\n");
02514    s = ao2_find(faxregistry.container, &tmp, OBJ_POINTER);
02515    if (s) {
02516       s->tech->cli_show_session(s, a->fd);
02517       ao2_ref(s, -1);
02518    }
02519    ast_cli(a->fd, "\n\n");
02520 
02521    return CLI_SUCCESS;
02522 }

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

02559 {
02560    struct ast_fax_session *s;
02561    struct ao2_iterator i;
02562    int session_count;
02563    char *filenames;
02564 
02565    switch (cmd) {
02566    case CLI_INIT:
02567       e->command = "fax show sessions";
02568       e->usage =
02569          "Usage: fax show sessions\n"
02570          "       Shows the current FAX sessions\n";
02571       return NULL;
02572    case CLI_GENERATE:
02573       return NULL;
02574    }
02575 
02576    ast_cli(a->fd, "\nCurrent FAX Sessions:\n\n");
02577    ast_cli(a->fd, "%-20.20s %-10.10s %-10.10s %-5.5s %-10.10s %-15.15s %-30.30s\n",
02578       "Channel", "Tech", "FAXID", "Type", "Operation", "State", "File(s)");
02579    i = ao2_iterator_init(faxregistry.container, 0);
02580    while ((s = ao2_iterator_next(&i))) {
02581       ao2_lock(s);
02582 
02583       if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
02584          ast_log(LOG_ERROR, "Error printing filenames for 'fax show sessions' command\n");
02585          ao2_unlock(s);
02586          ao2_ref(s, -1);
02587          ao2_iterator_destroy(&i);
02588          return CLI_FAILURE;
02589       }
02590 
02591       ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
02592          s->channame, s->tech->type, s->id,
02593          (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
02594          (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
02595          ast_fax_state_to_str(s->state), filenames);
02596 
02597       ast_free(filenames);
02598       ao2_unlock(s);
02599       ao2_ref(s, -1);
02600    }
02601    ao2_iterator_destroy(&i);
02602    session_count = ao2_container_count(faxregistry.container);
02603    ast_cli(a->fd, "\n%d FAX sessions\n\n", session_count);
02604 
02605    return CLI_SUCCESS;
02606 }

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

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

02452 {
02453    struct fax_module *fax;
02454    char modems[128] = "";
02455    struct fax_options options;
02456 
02457    switch (cmd) {
02458    case CLI_INIT:
02459       e->command = "fax show settings";
02460       e->usage =
02461          "Usage: fax show settings\n"
02462          "       Show the global settings and defaults of both the FAX core and technology modules\n";
02463       return NULL;
02464    case CLI_GENERATE:
02465       return NULL;
02466    }
02467 
02468    get_general_options(&options);
02469 
02470    ast_cli(a->fd, "FAX For Asterisk Settings:\n");
02471    ast_cli(a->fd, "\tECM: %s\n", options.ecm ? "Enabled" : "Disabled");
02472    ast_cli(a->fd, "\tStatus Events: %s\n",  options.statusevents ? "On" : "Off");
02473    ast_cli(a->fd, "\tMinimum Bit Rate: %d\n", options.minrate);
02474    ast_cli(a->fd, "\tMaximum Bit Rate: %d\n", options.maxrate);
02475    ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02476    ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
02477    ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
02478    AST_RWLIST_RDLOCK(&faxmodules);
02479    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02480       ast_cli(a->fd, "%s (%s) Settings:\n", fax->tech->type, fax->tech->description);
02481       fax->tech->cli_show_settings(a->fd);
02482    }
02483    AST_RWLIST_UNLOCK(&faxmodules);
02484 
02485    return CLI_SUCCESS;
02486 }

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

02526 {
02527    struct fax_module *fax;
02528    
02529    switch (cmd) {
02530    case CLI_INIT:
02531       e->command = "fax show stats";
02532       e->usage =
02533          "Usage: fax show stats\n"
02534          "       Shows a statistical summary of FAX transmissions\n";
02535       return NULL;
02536    case CLI_GENERATE:
02537       return NULL;
02538    }
02539 
02540    ast_cli(a->fd, "\nFAX Statistics:\n---------------\n\n");
02541    ast_cli(a->fd, "%-20.20s : %d\n", "Current Sessions", faxregistry.active_sessions);
02542    ast_cli(a->fd, "%-20.20s : %d\n", "Reserved Sessions", faxregistry.reserved_sessions);
02543    ast_cli(a->fd, "%-20.20s : %d\n", "Transmit Attempts", faxregistry.fax_tx_attempts);
02544    ast_cli(a->fd, "%-20.20s : %d\n", "Receive Attempts", faxregistry.fax_rx_attempts);
02545    ast_cli(a->fd, "%-20.20s : %d\n", "Completed FAXes", faxregistry.fax_complete);
02546    ast_cli(a->fd, "%-20.20s : %d\n", "Failed FAXes", faxregistry.fax_failures);
02547    AST_RWLIST_RDLOCK(&faxmodules);
02548    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02549       fax->tech->cli_show_stats(a->fd);
02550    }
02551    AST_RWLIST_UNLOCK(&faxmodules);
02552    ast_cli(a->fd, "\n\n");
02553 
02554    return CLI_SUCCESS;
02555 }

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

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

02355 {
02356    struct fax_module *fax;
02357 
02358    switch(cmd) {
02359    case CLI_INIT:
02360       e->command = "fax show version";
02361       e->usage =
02362          "Usage: fax show version\n"
02363          "       Show versions of FAX For Asterisk components.\n";
02364       return NULL;
02365    case CLI_GENERATE:
02366       return NULL;
02367    }
02368 
02369    if (a->argc != 3) {
02370       return CLI_SHOWUSAGE;
02371    }
02372 
02373    ast_cli(a->fd, "FAX For Asterisk Components:\n");
02374    ast_cli(a->fd, "\tApplications: %s\n", ast_get_version());
02375    AST_RWLIST_RDLOCK(&faxmodules);
02376    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02377       ast_cli(a->fd, "\t%s: %s\n", fax->tech->description, fax->tech->version);
02378    }
02379    AST_RWLIST_UNLOCK(&faxmodules);
02380    ast_cli(a->fd, "\n");
02381 
02382    return CLI_SUCCESS;
02383 }

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

Definition at line 303 of file res_fax.c.

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

Referenced by generic_fax_exec().

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

static void destroy_callback ( void *  data  )  [static]

Definition at line 336 of file res_fax.c.

References ao2_ref.

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

static void destroy_session ( void *  session  )  [static]

destroy a FAX session structure

Definition at line 723 of file res_fax.c.

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

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

static void destroy_session_details ( void *  details  )  [static]

destroy a FAX session details structure

Definition at line 371 of file res_fax.c.

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

Referenced by session_details_new().

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

static int disable_t38 ( struct ast_channel chan  )  [static]

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

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

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

convert a rate string to a rate

Definition at line 686 of file res_fax.c.

References ast_log(), LOG_ERROR, and LOG_WARNING.

Referenced by acf_faxopt_write(), and set_config().

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

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

create a FAX session

Definition at line 806 of file res_fax.c.

References ao2_alloc, ao2_link, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_debug, ast_dsp_new(), ast_dsp_set_threshold(), ast_fax_caps_to_str(), AST_FAX_STATE_RESERVED, AST_FAX_STATE_UNINITIALIZED, AST_FAX_TECH_AUDIO, ast_free, ast_log(), ast_module_ref(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_fax_tech::caps, ast_fax_session_details::caps, ast_fax_session_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().

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

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

Definition at line 710 of file res_fax.c.

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

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

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

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

Definition at line 756 of file res_fax.c.

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

Referenced by receivefax_exec(), and sendfax_exec().

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

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

fax session tab completion

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

02327 {
02328    int tklen;
02329    int wordnum = 0;
02330    char *name = NULL;
02331    struct ao2_iterator i;
02332    struct ast_fax_session *s;
02333    char tbuf[5];
02334 
02335    if (a->pos != 3) {
02336       return NULL;
02337    }
02338 
02339    tklen = strlen(a->word);
02340    i = ao2_iterator_init(faxregistry.container, 0);
02341    while ((s = ao2_iterator_next(&i))) {
02342       snprintf(tbuf, sizeof(tbuf), "%d", s->id);
02343       if (!strncasecmp(a->word, tbuf, tklen) && ++wordnum > a->n) {
02344          name = ast_strdup(tbuf);
02345          ao2_ref(s, -1);
02346          break;
02347       }
02348       ao2_ref(s, -1);
02349    }
02350    ao2_iterator_destroy(&i);
02351    return name;
02352 }

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

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

Referenced by acf_faxopt_read(), and find_or_create_details().

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

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

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

Definition at line 417 of file res_fax.c.

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

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

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

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

Definition at line 919 of file res_fax.c.

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

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

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

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

this is the generic FAX session handling function

Definition at line 1150 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, chancount, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, debug_check_frame_for_silence(), ast_fax_session::debug_info, errno, f, fax_session_new(), faxregistry, ast_fax_session::fd, ast_fax_session::frames_received, ast_fax_session::frames_sent, ast_frame::frametype, ast_fax_tech::generate_silence, GENERIC_FAX_EXEC_ERROR, GENERIC_FAX_EXEC_SET_VARS, ast_fax_session_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().

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

static void get_general_options ( struct fax_options options  )  [static]

Definition at line 2625 of file res_fax.c.

References ast_rwlock_rdlock, ast_rwlock_unlock, general_options, and options_lock.

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

02626 {
02627    ast_rwlock_rdlock(&options_lock);
02628    *options = general_options;
02629    ast_rwlock_unlock(&options_lock);
02630 }

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

Definition at line 900 of file res_fax.c.

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

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

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

static int load_module ( void   )  [static]

load res_fax

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

02879 {
02880    int res;
02881 
02882    /* initialize the registry */
02883    faxregistry.active_sessions = 0;
02884    faxregistry.reserved_sessions = 0;
02885    if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
02886       return AST_MODULE_LOAD_DECLINE;
02887    }
02888    
02889    if (set_config(0) < 0) {
02890       ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
02891       ao2_ref(faxregistry.container, -1);
02892       return AST_MODULE_LOAD_DECLINE;
02893    }
02894 
02895    /* register CLI operations and applications */
02896    if (ast_register_application_xml(app_sendfax, sendfax_exec) < 0) {
02897       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_sendfax);
02898       ao2_ref(faxregistry.container, -1);
02899       return AST_MODULE_LOAD_DECLINE;
02900    }
02901    if (ast_register_application_xml(app_receivefax, receivefax_exec) < 0) {
02902       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_receivefax);
02903       ast_unregister_application(app_sendfax);
02904       ao2_ref(faxregistry.container, -1);
02905       return AST_MODULE_LOAD_DECLINE;
02906    }
02907    ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
02908    res = ast_custom_function_register(&acf_faxopt);   
02909    fax_logger_level = ast_logger_register_level("FAX");
02910 
02911    return res;
02912 }

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

initiate a receive FAX session

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

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

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

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

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

static int reload_module ( void   )  [static]

Definition at line 2914 of file res_fax.c.

References set_config().

02915 {
02916    set_config(1);
02917    return 0;
02918 }

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

send a FAX status manager event

Definition at line 956 of file res_fax.c.

References ast_channel_lock, ast_channel_unlock, AST_FAX_TECH_RECEIVE, ast_free, ast_fax_session_details::caps, manager_event_info::cid, manager_event_info::context, EVENT_FLAG_CALL, manager_event_info::exten, generate_filenames_string(), get_manager_event_info(), 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().

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

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

initiate a send FAX session

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

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

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

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

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

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

compare callback for ao2

Definition at line 2318 of file res_fax.c.

References CMP_MATCH, CMP_STOP, and ast_fax_session::id.

Referenced by load_module().

02319 {
02320    struct ast_fax_session *lhs = obj, *rhs = arg;
02321 
02322    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02323 }

static struct ast_fax_session_details* session_details_new ( void   )  [static]

create a FAX session details structure

Definition at line 383 of file res_fax.c.

References ao2_alloc, ao2_ref, AST_FAX_OPTFLAG_FALSE, AST_LIST_HEAD_INIT_NOLOCK, ast_string_field_init, destroy_session_details(), fax_options::ecm, get_general_options(), fax_options::maxrate, fax_options::minrate, fax_options::modems, and fax_options::statusevents.

Referenced by find_or_create_details().

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

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

hash callback for ao2

Definition at line 2310 of file res_fax.c.

References ast_fax_session::id.

Referenced by load_module().

02311 {
02312    const struct ast_fax_session *s = obj;
02313 
02314    return s->id;
02315 }

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

Set fax related channel variables.

Definition at line 992 of file res_fax.c.

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

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

static int set_config ( int  reload  )  [static]

configure res_fax

Definition at line 2633 of file res_fax.c.

References ast_config_load2(), ast_debug, ast_log(), ast_variable_browse(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, default_options, fax_rate_str_to_int(), LOG_NOTICE, fax_options::minrate, ast_variable::name, ast_variable::next, set_general_options(), and ast_variable::value.

02634 {
02635    struct ast_config *cfg;
02636    struct ast_variable *v;
02637    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02638    char modems[128] = "";
02639    struct fax_options options;
02640    int res = 0;
02641 
02642    options = default_options;
02643 
02644    /* When we're not reloading, we have to be certain to set the general options
02645     * to the defaults in case config loading goes wrong at some point. On a reload,
02646     * the general options need to stay the same as what they were prior to the
02647     * reload rather than being reset to the defaults.
02648     */
02649    if (!reload) {
02650       set_general_options(&options);
02651    }
02652 
02653    /* read configuration */
02654    if (!(cfg = ast_config_load2(config, "res_fax", config_flags))) {
02655       ast_log(LOG_NOTICE, "Configuration file '%s' not found, %s options.\n",
02656             config, reload ? "not changing" : "using default");
02657       return 0;
02658    }
02659 
02660    if (cfg == CONFIG_STATUS_FILEINVALID) {
02661       ast_log(LOG_NOTICE, "Configuration file '%s' is invalid, %s options.\n",
02662             config, reload ? "not changing" : "using default");
02663       return 0;
02664    }
02665 
02666    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
02667       return 0;
02668    }
02669 
02670    if (reload) {
02671       options = default_options;
02672    }
02673 
02674    /* create configuration */
02675    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
02676       int rate;
02677 
02678       if (!strcasecmp(v->name, "minrate")) {
02679          ast_debug(3, "reading minrate '%s' from configuration file\n", v->value);
02680          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02681             res = -1;
02682             goto end;
02683          }
02684          options.minrate = rate;
02685       } else if (!strcasecmp(v->name, "maxrate")) {
02686          ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value);
02687          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02688             res = -1;
02689             goto end;
02690          }
02691          options.maxrate = rate;
02692       } else if (!strcasecmp(v->name, "statusevents")) {
02693          ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value);
02694          options.statusevents = ast_true(v->value);
02695       } else if (!strcasecmp(v->name, "ecm")) {
02696          ast_debug(3, "reading ecm '%s' from configuration file\n", v->value);
02697          options.ecm = ast_true(v->value);
02698       } else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
02699          options.modems = 0;
02700          update_modem_bits(&options.modems, v->value);
02701       }
02702    }
02703 
02704    if (options.maxrate < options.minrate) {
02705       ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", options.maxrate, options.minrate);
02706       res = -1;
02707       goto end;
02708    }
02709 
02710    if (check_modem_rate(options.modems, options.minrate)) {
02711       ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02712       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, options.minrate);
02713       res = -1;
02714       goto end;
02715    }
02716 
02717    if (check_modem_rate(options.modems, options.maxrate)) {
02718       ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
02719       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, options.maxrate);
02720       res = -1;
02721       goto end;
02722    }
02723 
02724    set_general_options(&options);
02725 
02726 end:
02727    ast_config_destroy(cfg);
02728    return res;
02729 }

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

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

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

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

Definition at line 2618 of file res_fax.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, general_options, and options_lock.

Referenced by set_config().

02619 {
02620    ast_rwlock_wrlock(&options_lock);
02621    general_options = *options;
02622    ast_rwlock_unlock(&options_lock);
02623 }

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

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

01031 {
01032    dst->version = src->version;
01033    dst->max_ifp = src->max_ifp;
01034    dst->rate = src->rate;
01035    dst->rate_management = src->rate_management;
01036    dst->fill_bit_removal = src->fill_bit_removal;
01037    dst->transcoding_mmr = src->transcoding_mmr;
01038    dst->transcoding_jbig = src->transcoding_jbig;
01039 }

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

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

01042 {
01043    dst->version = src->version;
01044    dst->max_ifp = src->max_ifp;
01045    dst->rate = src->rate;
01046    dst->rate_management = src->rate_management;
01047    dst->fill_bit_removal = src->fill_bit_removal;
01048    dst->transcoding_mmr = src->transcoding_mmr;
01049    dst->transcoding_jbig = src->transcoding_jbig;
01050 }

static int unload_module ( void   )  [static]

unload res_fax

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

02853 {
02854    ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
02855    
02856    if (ast_custom_function_unregister(&acf_faxopt) < 0) {
02857       ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
02858    }
02859 
02860    if (ast_unregister_application(app_sendfax) < 0) {
02861       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_sendfax);
02862    }
02863 
02864    if (ast_unregister_application(app_receivefax) < 0) {
02865       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
02866    }
02867 
02868    if (fax_logger_level != -1) {
02869       ast_logger_unregister_level("FAX");
02870    }
02871 
02872    ao2_ref(faxregistry.container, -1);
02873 
02874    return 0;
02875 }

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

Definition at line 460 of file res_fax.c.

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

Referenced by acf_faxopt_write().

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


Variable Documentation

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

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

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

Definition at line 275 of file res_fax.c.

struct ao2_container* container

active sessions are astobj2 objects

Definition at line 227 of file res_fax.c.

struct fax_options default_options [static]

Definition at line 262 of file res_fax.c.

Referenced by set_config().

struct ast_cli_entry fax_cli[] [static]

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

Referenced by find_details(), and find_or_create_details().

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

Definition at line 295 of file res_fax.c.

Referenced by receivefax_exec(), and sendfax_exec().

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 fax_options general_options [static]

Definition at line 260 of file res_fax.c.

Referenced by get_general_options(), and set_general_options().

int global_fax_debug = 0 [static]

Definition at line 277 of file res_fax.c.

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

int nextsessionname

the next unique session name

Definition at line 237 of file res_fax.c.

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

Definition at line 270 of file res_fax.c.

Referenced by get_general_options(), and set_general_options().

struct ast_control_t38_parameters our_t38_parameters [static]

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


Generated on Mon Oct 8 12:39:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7