Mon Mar 19 11:30:29 2012

Asterisk developer's documentation


res_fax.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2008-2009, Digium, Inc.
00005  *
00006  * Dwayne M. Hubbard <dhubbard@digium.com>
00007  * Kevin P. Fleming <kpfleming@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*** MODULEINFO
00021    <support_level>core</support_level>
00022    <conflict>app_fax</conflict>
00023 ***/
00024 
00025 /*! \file
00026  *
00027  * \brief Generic FAX Resource for FAX technology resource modules
00028  *
00029  * \author Dwayne M. Hubbard <dhubbard@digium.com>
00030  * \author Kevin P. Fleming <kpfleming@digium.com>
00031  *
00032  * A generic FAX resource module that provides SendFAX and ReceiveFAX applications.
00033  * This module requires FAX technology modules, like res_fax_spandsp, to register with it
00034  * so it can use the technology modules to perform the actual FAX transmissions.
00035  * \ingroup applications
00036  */
00037 
00038 #include "asterisk.h"
00039 
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 348212 $")
00041 
00042 #include "asterisk/io.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/options.h"
00049 #include "asterisk/strings.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/config.h"
00053 #include "asterisk/astobj2.h"
00054 #include "asterisk/res_fax.h"
00055 #include "asterisk/file.h"
00056 #include "asterisk/channel.h"
00057 #include "asterisk/pbx.h"
00058 #include "asterisk/manager.h"
00059 #include "asterisk/dsp.h"
00060 #include "asterisk/indications.h"
00061 #include "asterisk/ast_version.h"
00062 
00063 /*** DOCUMENTATION
00064    <application name="ReceiveFAX" language="en_US" module="res_fax">
00065       <synopsis>
00066          Receive a FAX and save as a TIFF/F file.
00067       </synopsis>
00068       <syntax>
00069          <parameter name="filename" required="true" />
00070          <parameter name="options">
00071             <optionlist>
00072                <option name="d">
00073                   <para>Enable FAX debugging.</para>
00074                </option>
00075                <option name="f">
00076                   <para>Allow audio fallback FAX transfer on T.38 capable channels.</para>
00077                </option>
00078                <option name="s">
00079                   <para>Send progress Manager events (overrides statusevents setting in res_fax.conf).</para>
00080                </option>
00081             </optionlist>
00082          </parameter>
00083       </syntax>
00084       <description>
00085          <para>This application is provided by res_fax, which is a FAX technology agnostic module
00086          that utilizes FAX technology resource modules to complete a FAX transmission.</para>
00087          <para>Session arguments can be set by the FAXOPT function and to check results of the ReceiveFax() application.</para>
00088       </description>
00089       <see-also>
00090          <ref type="function">FAXOPT</ref>
00091       </see-also>
00092    </application>
00093    <application name="SendFAX" language="en_US" module="res_fax">
00094       <synopsis>
00095          Sends a specified TIFF/F file as a FAX.
00096       </synopsis>
00097       <syntax>
00098          <parameter name="filename" required="true" argsep="&amp;">
00099             <argument name="filename2" multiple="true">
00100                <para>TIFF file to send as a FAX.</para>
00101             </argument>
00102          </parameter>
00103          <parameter name="options">
00104             <optionlist>
00105                <option name="d">
00106                   <para>Enable FAX debugging.</para>
00107                </option>
00108                <option name="f">
00109                   <para>Allow audio fallback FAX transfer on T.38 capable channels.</para>
00110                </option>
00111                <option name="s">
00112                   <para>Send progress Manager events (overrides statusevents setting in res_fax.conf).</para>
00113                </option>
00114                <option name="z">
00115                   <para>Initiate a T.38 reinvite on the channel if the remote end does not.</para>
00116                </option>
00117             </optionlist>
00118          </parameter>
00119       </syntax>
00120       <description>
00121          <para>This application is provided by res_fax, which is a FAX technology agnostic module
00122          that utilizes FAX technology resource modules to complete a FAX transmission.</para>
00123          <para>Session arguments can be set by the FAXOPT function and to check results of the SendFax() application.</para>
00124       </description>
00125       <see-also>
00126          <ref type="function">FAXOPT</ref>
00127       </see-also>
00128    </application>
00129    <function name="FAXOPT" language="en_US" module="res_fax">
00130       <synopsis>
00131          Gets/sets various pieces of information about a fax session.
00132       </synopsis>
00133       <syntax>
00134          <parameter name="item" required="true">
00135             <enumlist>
00136                <enum name="ecm">
00137                   <para>R/W Error Correction Mode (ECM) enable with 'yes', disable with 'no'.</para>
00138                </enum>
00139                <enum name="error">
00140                   <para>R/O FAX transmission error code upon failure.</para>
00141                </enum>
00142                <enum name="filename">
00143                   <para>R/O Filename of the first file of the FAX transmission.</para>
00144                </enum>
00145                <enum name="filenames">
00146                   <para>R/O Filenames of all of the files in the FAX transmission (comma separated).</para>
00147                </enum>
00148                <enum name="headerinfo">
00149                   <para>R/W FAX header information.</para>
00150                </enum>
00151                <enum name="localstationid">
00152                   <para>R/W Local Station Identification.</para>
00153                </enum>
00154                <enum name="minrate">
00155                   <para>R/W Minimum transfer rate set before transmission.</para>
00156                </enum>
00157                <enum name="maxrate">
00158                   <para>R/W Maximum transfer rate set before transmission.</para>
00159                </enum>
00160                <enum name="modem">
00161                   <para>R/W Modem type (v17/v27/v29).</para>
00162                </enum>
00163                <enum name="pages">
00164                   <para>R/O Number of pages transferred.</para>
00165                </enum>
00166                <enum name="rate">
00167                   <para>R/O Negotiated transmission rate.</para>
00168                </enum>
00169                <enum name="remotestationid">
00170                   <para>R/O Remote Station Identification after transmission.</para>
00171                </enum>
00172                <enum name="resolution">
00173                   <para>R/O Negotiated image resolution after transmission.</para>
00174                </enum>
00175                <enum name="sessionid">
00176                   <para>R/O Session ID of the FAX transmission.</para>
00177                </enum>
00178                <enum name="status">
00179                   <para>R/O Result Status of the FAX transmission.</para>
00180                </enum>
00181                <enum name="statusstr">
00182                   <para>R/O Verbose Result Status of the FAX transmission.</para>
00183                </enum>
00184             </enumlist>
00185          </parameter>
00186       </syntax>
00187       <description>
00188          <para>FAXOPT can be used to override the settings for a FAX session listed in <filename>res_fax.conf</filename>,
00189             it can also be used to retreive information about a FAX session that has finished eg. pages/status.</para>
00190       </description>
00191       <see-also>
00192          <ref type="application">ReceiveFax</ref>
00193          <ref type="application">SendFax</ref>
00194       </see-also>
00195    </function>
00196 ***/
00197 
00198 static const char app_receivefax[] = "ReceiveFAX";
00199 static const char app_sendfax[] = "SendFAX";
00200 
00201 struct debug_info_history {
00202    unsigned int consec_frames;
00203    unsigned int consec_ms;
00204    unsigned char silence;
00205 };
00206 
00207 struct ast_fax_debug_info {
00208    struct timeval base_tv;
00209    struct debug_info_history c2s, s2c;
00210    struct ast_dsp *dsp;
00211 };
00212 
00213 static int fax_logger_level = -1;
00214 
00215 /*! \brief maximum buckets for res_fax ao2 containers */
00216 #define FAX_MAXBUCKETS 10
00217 
00218 #define RES_FAX_TIMEOUT 10000
00219 
00220 /*! \brief The faxregistry is used to manage information and statistics for all FAX sessions. */
00221 static struct {
00222    /*! The number of active FAX sessions */
00223    int active_sessions;
00224    /*! The number of reserved FAX sessions */
00225    int reserved_sessions;
00226    /*! active sessions are astobj2 objects */
00227    struct ao2_container *container;
00228    /*! Total number of Tx FAX attempts */
00229    int fax_tx_attempts;
00230    /*! Total number of Rx FAX attempts */
00231    int fax_rx_attempts;
00232    /*! Number of successful FAX transmissions */
00233    int fax_complete;
00234    /*! Number of failed FAX transmissions */
00235    int fax_failures;
00236    /*! the next unique session name */
00237    int nextsessionname;
00238 } faxregistry;
00239 
00240 /*! \brief registered FAX technology modules are put into this list */
00241 struct fax_module {
00242    const struct ast_fax_tech *tech;
00243    AST_RWLIST_ENTRY(fax_module) list;
00244 };
00245 static AST_RWLIST_HEAD_STATIC(faxmodules, fax_module);
00246 
00247 #define RES_FAX_MINRATE 2400
00248 #define RES_FAX_MAXRATE 14400
00249 #define RES_FAX_STATUSEVENTS 0
00250 #define RES_FAX_MODEM (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)
00251 
00252 static struct {
00253    enum ast_fax_modems modems;
00254    uint32_t statusevents:1;
00255    uint32_t ecm:1;
00256    unsigned int minrate;   
00257    unsigned int maxrate;
00258 } general_options;
00259 
00260 static const char *config = "res_fax.conf";
00261 
00262 static int global_fax_debug = 0;
00263 
00264 enum {
00265    OPT_CALLEDMODE  = (1 << 0),
00266    OPT_CALLERMODE  = (1 << 1),
00267    OPT_DEBUG       = (1 << 2),
00268    OPT_STATUS      = (1 << 3),
00269    OPT_ALLOWAUDIO  = (1 << 5),
00270    OPT_REQUEST_T38 = (1 << 6),
00271 };
00272 
00273 AST_APP_OPTIONS(fax_exec_options, BEGIN_OPTIONS
00274    AST_APP_OPTION('a', OPT_CALLEDMODE),
00275    AST_APP_OPTION('c', OPT_CALLERMODE),
00276    AST_APP_OPTION('d', OPT_DEBUG),
00277    AST_APP_OPTION('f', OPT_ALLOWAUDIO),
00278    AST_APP_OPTION('s', OPT_STATUS),
00279    AST_APP_OPTION('z', OPT_REQUEST_T38),
00280 END_OPTIONS);
00281 
00282 struct manager_event_info {
00283    char context[AST_MAX_CONTEXT];
00284    char exten[AST_MAX_EXTENSION];
00285    char cid[128];
00286 };
00287 
00288 static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned int c2s, struct ast_frame *frame)
00289 {  
00290    struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
00291    int dspsilence;
00292    unsigned int last_consec_frames, last_consec_ms;
00293    unsigned char wassil;
00294    struct timeval diff;
00295 
00296    diff = ast_tvsub(ast_tvnow(), s->debug_info->base_tv);
00297 
00298    ast_dsp_reset(s->debug_info->dsp);
00299    ast_dsp_silence(s->debug_info->dsp, frame, &dspsilence);
00300 
00301    wassil = history->silence;
00302    history->silence = (dspsilence != 0) ? 1 : 0;
00303    if (history->silence != wassil) {
00304       last_consec_frames = history->consec_frames;
00305       last_consec_ms = history->consec_ms;
00306       history->consec_frames = 0;
00307       history->consec_ms = 0;
00308 
00309       if ((last_consec_frames != 0)) {
00310          ast_verb(6, "Channel '%s' fax session '%d', [ %.3ld.%.6ld ], %s sent %d frames (%d ms) of %s.\n",
00311              s->channame, s->id, (long) diff.tv_sec, (long int) diff.tv_usec,
00312              (c2s) ? "channel" : "stack", last_consec_frames, last_consec_ms,
00313              (wassil) ? "silence" : "energy");
00314       }
00315    }
00316 
00317    history->consec_frames++;
00318    history->consec_ms += (frame->samples / 8);
00319 }
00320 
00321 static void destroy_callback(void *data) 
00322 {
00323    if (data) {
00324       ao2_ref(data, -1);
00325    }
00326 }
00327 
00328 static const struct ast_datastore_info fax_datastore = {
00329    .type = "res_fax",
00330    .destroy = destroy_callback,
00331 };
00332 
00333 /*! \brief returns a reference counted pointer to a fax datastore, if it exists */
00334 static struct ast_fax_session_details *find_details(struct ast_channel *chan)
00335 {
00336    struct ast_fax_session_details *details;
00337    struct ast_datastore *datastore;
00338 
00339    ast_channel_lock(chan); 
00340    if (!(datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL))) {
00341       ast_channel_unlock(chan);  
00342       return NULL;
00343    }
00344    if (!(details = datastore->data)) {
00345       ast_log(LOG_WARNING, "Huh?  channel '%s' has a FAX datastore without data!\n", chan->name);
00346       ast_channel_unlock(chan);
00347       return NULL;
00348    }
00349    ao2_ref(details, 1); 
00350    ast_channel_unlock(chan);  
00351 
00352    return details;
00353 }
00354 
00355 /*! \brief destroy a FAX session details structure */
00356 static void destroy_session_details(void *details)
00357 {
00358    struct ast_fax_session_details *d = details;
00359    struct ast_fax_document *doc;
00360    
00361    while ((doc = AST_LIST_REMOVE_HEAD(&d->documents, next))) {
00362       ast_free(doc);
00363    }
00364    ast_string_field_free_memory(d); 
00365 }
00366 
00367 /*! \brief create a FAX session details structure */
00368 static struct ast_fax_session_details *session_details_new(void)
00369 {
00370    struct ast_fax_session_details *d;
00371 
00372    if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) {
00373       return NULL;
00374    }
00375    
00376    if (ast_string_field_init(d, 512)) {
00377       ao2_ref(d, -1);
00378       return NULL;
00379    }
00380 
00381    AST_LIST_HEAD_INIT_NOLOCK(&d->documents);
00382 
00383    /* These options need to be set to the configured default and may be overridden by
00384     * SendFAX, ReceiveFAX, or FAXOPT */
00385    d->option.request_t38 = AST_FAX_OPTFLAG_FALSE;
00386    d->option.send_cng = AST_FAX_OPTFLAG_FALSE;
00387    d->option.send_ced = AST_FAX_OPTFLAG_FALSE;
00388    d->option.ecm = general_options.ecm;
00389    d->option.statusevents = general_options.statusevents;
00390    d->modems = general_options.modems;
00391    d->minrate = general_options.minrate;
00392    d->maxrate = general_options.maxrate;
00393 
00394    return d;
00395 }
00396 
00397 /*! \brief returns a reference counted details structure from the channel's fax datastore.  If the datastore
00398  * does not exist it will be created */   
00399 static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan)
00400 {
00401    struct ast_fax_session_details *details;
00402    struct ast_datastore *datastore;
00403 
00404    if ((details = find_details(chan))) {
00405       return details;
00406    }
00407    /* channel does not have one so we must create one */
00408    if (!(details = session_details_new())) {
00409       ast_log(LOG_WARNING, "channel '%s' can't get a FAX details structure for the datastore!\n", chan->name);
00410       return NULL;
00411    }
00412    if (!(datastore = ast_datastore_alloc(&fax_datastore, NULL))) {
00413       ao2_ref(details, -1);
00414       ast_log(LOG_WARNING, "channel '%s' can't get a datastore!\n", chan->name);
00415       return NULL;
00416    }
00417    /* add the datastore to the channel and increment the refcount */
00418    datastore->data = details;
00419    ao2_ref(details, 1);
00420    ast_channel_lock(chan);
00421    ast_channel_datastore_add(chan, datastore);
00422    ast_channel_unlock(chan);
00423    return details;
00424 }
00425 
00426 unsigned int ast_fax_maxrate(void)
00427 {
00428    return general_options.maxrate;
00429 }
00430 
00431 unsigned int ast_fax_minrate(void)
00432 {
00433    return general_options.minrate;
00434 }
00435 
00436 static int update_modem_bits(enum ast_fax_modems *bits, const char *value)
00437 {     
00438    char *m[5], *tok, *v = (char *)value;
00439    int i = 0, j;
00440 
00441    if (!(tok = strchr(v, ','))) {
00442       m[i++] = v;
00443       m[i] = NULL;
00444    } else {
00445       tok = strtok(v, ", ");
00446       while (tok && (i < 5)) {
00447          m[i++] = tok;
00448          tok = strtok(NULL, ", ");
00449       }
00450       m[i] = NULL;
00451    }
00452 
00453    *bits = 0;
00454    for (j = 0; j < i; j++) {
00455       if (!strcasecmp(m[j], "v17")) {
00456          *bits |= AST_FAX_MODEM_V17;
00457       } else if (!strcasecmp(m[j], "v27")) {
00458          *bits |= AST_FAX_MODEM_V27;
00459       } else if (!strcasecmp(m[j], "v29")) {
00460          *bits |= AST_FAX_MODEM_V29;
00461       } else if (!strcasecmp(m[j], "v34")) {
00462          *bits |= AST_FAX_MODEM_V34;
00463       } else {
00464          ast_log(LOG_WARNING, "ignoring invalid modem setting: '%s', valid options {v17 | v27 | v29 | v34}\n", m[j]);
00465       }
00466    }
00467    return 0;
00468 }
00469 
00470 static char *ast_fax_caps_to_str(enum ast_fax_capabilities caps, char *buf, size_t bufsize)
00471 {
00472    char *out = buf;
00473    size_t size = bufsize;
00474    int first = 1;
00475 
00476    if (caps & AST_FAX_TECH_SEND) {
00477       if (!first) {
00478          ast_build_string(&buf, &size, ",");
00479       }
00480       ast_build_string(&buf, &size, "SEND");
00481       first = 0;
00482    }
00483    if (caps & AST_FAX_TECH_RECEIVE) {
00484       if (!first) {
00485          ast_build_string(&buf, &size, ",");
00486       }
00487       ast_build_string(&buf, &size, "RECEIVE");
00488       first = 0;
00489    }
00490    if (caps & AST_FAX_TECH_AUDIO) {
00491       if (!first) {
00492          ast_build_string(&buf, &size, ",");
00493       }
00494       ast_build_string(&buf, &size, "AUDIO");
00495       first = 0;
00496    }
00497    if (caps & AST_FAX_TECH_T38) {
00498       if (!first) {
00499          ast_build_string(&buf, &size, ",");
00500       }
00501       ast_build_string(&buf, &size, "T38");
00502       first = 0;
00503    }
00504    if (caps & AST_FAX_TECH_MULTI_DOC) {
00505       if (!first) {
00506          ast_build_string(&buf, &size, ",");
00507       }
00508       ast_build_string(&buf, &size, "MULTI_DOC");
00509       first = 0;
00510    }
00511 
00512    return out;
00513 }
00514 
00515 static int ast_fax_modem_to_str(enum ast_fax_modems bits, char *tbuf, size_t bufsize)
00516 {
00517    int count = 0;
00518 
00519    if (bits & AST_FAX_MODEM_V17) {
00520       strcat(tbuf, "V17");
00521       count++;
00522    }
00523    if (bits & AST_FAX_MODEM_V27) {
00524       if (count) {
00525          strcat(tbuf, ",");
00526       }
00527       strcat(tbuf, "V27");
00528       count++;
00529    }
00530    if (bits & AST_FAX_MODEM_V29) {
00531       if (count) {
00532          strcat(tbuf, ",");
00533       }
00534       strcat(tbuf, "V29");
00535       count++;
00536    }
00537    if (bits & AST_FAX_MODEM_V34) {
00538       if (count) {
00539          strcat(tbuf, ",");
00540       }
00541       strcat(tbuf, "V34");
00542       count++;
00543    }
00544 
00545    return 0;
00546 }
00547 
00548 static int check_modem_rate(enum ast_fax_modems modems, unsigned int rate)
00549 {
00550    switch (rate) {
00551    case 2400:
00552       if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
00553          return 1;
00554       }
00555       break;
00556    case 4800:
00557       if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
00558          return 1;
00559       }
00560       break;
00561    case 7200:
00562    case 9600:
00563       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
00564          return 1;
00565       }
00566       break;
00567    case 12000:
00568    case 14400:
00569       if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
00570          return 1;
00571       }
00572       break;
00573    case 28800:
00574    case 33600:
00575       if (!(modems & AST_FAX_MODEM_V34)) {
00576          return 1;
00577       }
00578       break;
00579    default:
00580       /* this should never happen */
00581       return 1;
00582    }
00583 
00584    return 0;
00585 }
00586 
00587 /*! \brief register a FAX technology module */
00588 int ast_fax_tech_register(struct ast_fax_tech *tech)
00589 {
00590    struct fax_module *fax;
00591 
00592    if (!(fax = ast_calloc(1, sizeof(*fax)))) {
00593       return -1;
00594    }
00595    fax->tech = tech;
00596    AST_RWLIST_WRLOCK(&faxmodules);
00597    AST_RWLIST_INSERT_TAIL(&faxmodules, fax, list);
00598    AST_RWLIST_UNLOCK(&faxmodules);
00599    ast_module_ref(ast_module_info->self);
00600 
00601    ast_verb(3, "Registered handler for '%s' (%s)\n", fax->tech->type, fax->tech->description);
00602 
00603    return 0;
00604 }
00605 
00606 /*! \brief unregister a FAX technology module */
00607 void ast_fax_tech_unregister(struct ast_fax_tech *tech)
00608 {
00609    struct fax_module *fax;
00610 
00611    ast_verb(3, "Unregistering FAX module type '%s'\n", tech->type);
00612 
00613    AST_RWLIST_WRLOCK(&faxmodules);
00614    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&faxmodules, fax, list) {
00615       if (fax->tech != tech) {
00616          continue;
00617       }
00618       AST_RWLIST_REMOVE_CURRENT(list);
00619       ast_module_unref(ast_module_info->self);
00620       ast_free(fax);
00621       ast_verb(4, "Unregistered FAX module type '%s'\n", tech->type);
00622       break;   
00623    }
00624    AST_RWLIST_TRAVERSE_SAFE_END;
00625    AST_RWLIST_UNLOCK(&faxmodules);
00626 }
00627 
00628 /*! \brief convert a ast_fax_state to a string */
00629 const char *ast_fax_state_to_str(enum ast_fax_state state)
00630 {
00631    switch (state) {
00632    case AST_FAX_STATE_UNINITIALIZED:
00633       return "Uninitialized";
00634    case AST_FAX_STATE_INITIALIZED:
00635       return "Initialized";
00636    case AST_FAX_STATE_OPEN:
00637       return "Open";
00638    case AST_FAX_STATE_ACTIVE:
00639       return "Active";
00640    case AST_FAX_STATE_COMPLETE:
00641       return "Complete";
00642    case AST_FAX_STATE_RESERVED:
00643       return "Reserved";
00644    case AST_FAX_STATE_INACTIVE:
00645       return "Inactive";
00646    default:
00647       ast_log(LOG_WARNING, "unhandled FAX state: %d\n", state);
00648       return "Unknown";
00649    }
00650 }
00651 
00652 void ast_fax_log(int level, const char *file, const int line, const char *function, const char *msg)
00653 {
00654    if (fax_logger_level != -1) {
00655       ast_log_dynamic_level(fax_logger_level, "%s", msg);
00656    } else {
00657       ast_log(level, file, line, function, "%s", msg);
00658    }
00659 }
00660 
00661 /*! \brief convert a rate string to a rate */
00662 static unsigned int fax_rate_str_to_int(const char *ratestr)
00663 {
00664    int rate;
00665 
00666    if (sscanf(ratestr, "%d", &rate) != 1) {
00667       ast_log(LOG_ERROR, "failed to sscanf '%s' to rate\n", ratestr);
00668       return 0;
00669    }
00670    switch (rate) {
00671    case 2400:
00672    case 4800:
00673    case 7200:
00674    case 9600:
00675    case 12000:
00676    case 14400:
00677    case 28800:
00678    case 33600:
00679       return rate;
00680    default:
00681       ast_log(LOG_WARNING, "ignoring invalid rate '%s'.  Valid options are {2400 | 4800 | 7200 | 9600 | 12000 | 14400 | 28800 | 33600}\n", ratestr);
00682       return 0;
00683    }
00684 }
00685 
00686 static void fax_session_release(struct ast_fax_session *s, struct ast_fax_tech_token *token)
00687 {
00688    if (token) {
00689       s->tech->release_token(token);
00690    }
00691 
00692    if (s->state == AST_FAX_STATE_RESERVED) {
00693       ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00694       s->state = AST_FAX_STATE_INACTIVE;
00695    }
00696 }
00697 
00698 /*! \brief destroy a FAX session structure */
00699 static void destroy_session(void *session)
00700 {
00701    struct ast_fax_session *s = session;
00702 
00703    if (s->tech) {
00704       fax_session_release(s, NULL);
00705       if (s->tech_pvt) {
00706          s->tech->destroy_session(s);
00707       }
00708       ast_module_unref(s->tech->module);
00709    }
00710 
00711    if (s->details) {
00712       ao2_ref(s->details, -1);
00713    }
00714    
00715    if (s->debug_info) {
00716       ast_dsp_free(s->debug_info->dsp);
00717       ast_free(s->debug_info);
00718    }
00719 
00720    if (s->smoother) {
00721       ast_smoother_free(s->smoother);
00722    }
00723 
00724    if (s->state != AST_FAX_STATE_INACTIVE) {
00725       ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
00726    }
00727 
00728    ast_free(s->channame);
00729    ast_free(s->chan_uniqueid);
00730 }
00731 
00732 static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_details *details, struct ast_fax_tech_token **token)
00733 {
00734    struct ast_fax_session *s;
00735    struct fax_module *faxmod;
00736    char caps[128] = "";
00737 
00738    if (!(s = ao2_alloc(sizeof(*s), destroy_session))) {
00739       return NULL;
00740    }
00741 
00742    s->state = AST_FAX_STATE_INACTIVE;
00743 
00744    /* locate a FAX technology module that can handle said requirements
00745     * Note: the requirements have not yet been finalized as T.38
00746     * negotiation has not yet occured. */
00747    AST_RWLIST_RDLOCK(&faxmodules);
00748    AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00749       if ((faxmod->tech->caps & details->caps) != details->caps) {
00750          continue;
00751       }
00752       ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
00753       ast_module_ref(faxmod->tech->module);
00754       s->tech = faxmod->tech;
00755       break;
00756    }
00757    AST_RWLIST_UNLOCK(&faxmodules);
00758 
00759    if (!faxmod) {
00760       ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (%s)\n", ast_fax_caps_to_str(details->caps, caps, sizeof(caps)));
00761       ao2_ref(s, -1);
00762       return NULL;
00763    }
00764 
00765    if (!s->tech->reserve_session) {
00766       ast_debug(1, "Selected FAX technology module (%s) does not support reserving sessions.\n", s->tech->description);
00767       return s;
00768    }
00769 
00770    if (!(*token = s->tech->reserve_session(s))) {
00771       ao2_ref(s, -1);
00772       return NULL;
00773    }
00774 
00775    s->state = AST_FAX_STATE_RESERVED;
00776    ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, 1);
00777 
00778    return s;
00779 }
00780 
00781 /*! \brief create a FAX session */
00782 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)
00783 {
00784    struct ast_fax_session *s = NULL;
00785    struct fax_module *faxmod;
00786    char caps[128] = "";
00787 
00788    if (reserved) {
00789       s = reserved;
00790       ao2_ref(reserved, +1);
00791 
00792       if (s->state == AST_FAX_STATE_RESERVED) {
00793          ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
00794          s->state = AST_FAX_STATE_UNINITIALIZED;
00795       }
00796    }
00797 
00798    if (!s && !(s = ao2_alloc(sizeof(*s), destroy_session))) {
00799       return NULL;
00800    }
00801 
00802    ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
00803    s->state = AST_FAX_STATE_UNINITIALIZED;
00804 
00805    if (details->option.debug && (details->caps & AST_FAX_TECH_AUDIO)) {
00806       if (!(s->debug_info = ast_calloc(1, sizeof(*(s->debug_info))))) {
00807          fax_session_release(s, token);
00808          ao2_ref(s, -1);
00809          return NULL;
00810       }
00811       if (!(s->debug_info->dsp = ast_dsp_new())) {
00812          ast_free(s->debug_info);
00813          s->debug_info = NULL;
00814          fax_session_release(s, token);
00815          ao2_ref(s, -1);
00816          return NULL;
00817       }
00818       ast_dsp_set_threshold(s->debug_info->dsp, 128);
00819    }  
00820 
00821    if (!(s->channame = ast_strdup(chan->name))) {
00822       fax_session_release(s, token);
00823       ao2_ref(s, -1);
00824       return NULL;
00825    }
00826 
00827    if (!(s->chan_uniqueid = ast_strdup(chan->uniqueid))) {
00828       fax_session_release(s, token);
00829       ao2_ref(s, -1);
00830       return NULL;
00831    }
00832 
00833    s->chan = chan;
00834    s->details = details;
00835    ao2_ref(s->details, 1);
00836 
00837    details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
00838 
00839    if (!token) {
00840       /* locate a FAX technology module that can handle said requirements */
00841       AST_RWLIST_RDLOCK(&faxmodules);
00842       AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
00843          if ((faxmod->tech->caps & details->caps) != details->caps) {
00844             continue;
00845          }
00846          ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
00847          ast_module_ref(faxmod->tech->module);
00848          s->tech = faxmod->tech;
00849          break;
00850       }
00851       AST_RWLIST_UNLOCK(&faxmodules);
00852 
00853       if (!faxmod) {
00854          ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (%s)\n", ast_fax_caps_to_str(details->caps, caps, sizeof(caps)));
00855          ao2_ref(s, -1);
00856          return NULL;
00857       }
00858    }
00859 
00860    if (!(s->tech_pvt = s->tech->new_session(s, token))) {
00861       ast_log(LOG_ERROR, "FAX session failed to initialize.\n");
00862       ao2_ref(s, -1);
00863       return NULL;
00864    }
00865    /* link the session to the session container */
00866    if (!(ao2_link(faxregistry.container, s))) {
00867       ast_log(LOG_ERROR, "failed to add FAX session '%d' to container.\n", s->id);
00868       ao2_ref(s, -1);
00869       return NULL;
00870    }
00871    ast_debug(4, "channel '%s' using FAX session '%d'\n", s->channame, s->id);
00872 
00873    return s;
00874 }
00875 
00876 static void get_manager_event_info(struct ast_channel *chan, struct manager_event_info *info)
00877 {
00878    pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
00879    pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
00880    pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
00881 }
00882 
00883 
00884 /* \brief Generate a string of filenames using the given prefix and separator.
00885  * \param details the fax session details
00886  * \param prefix the prefix to each filename
00887  * \param separator the separator between filenames
00888  *
00889  * This function generates a string of filenames from the given details
00890  * structure and using the given prefix and separator.
00891  *
00892  * \retval NULL there was an error generating the string
00893  * \return the string generated string
00894  */
00895 static char *generate_filenames_string(struct ast_fax_session_details *details, char *prefix, char *separator)
00896 {
00897    char *filenames, *c;
00898    size_t size = 0;
00899    int first = 1;
00900    struct ast_fax_document *doc;
00901 
00902    /* don't process empty lists */
00903    if (AST_LIST_EMPTY(&details->documents)) {
00904       return NULL;
00905    }
00906 
00907    /* Calculate the total length of all of the file names */
00908    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00909       size += strlen(separator) + strlen(prefix) + strlen(doc->filename);
00910    }
00911    size += 1; /* add space for the terminating null */
00912 
00913    if (!(filenames = ast_malloc(size))) {
00914       return NULL;
00915    }
00916    c = filenames;
00917 
00918    ast_build_string(&c, &size, "%s%s", prefix, AST_LIST_FIRST(&details->documents)->filename);
00919    AST_LIST_TRAVERSE(&details->documents, doc, next) {
00920       if (first) {
00921          first = 0;
00922          continue;
00923       }
00924 
00925       ast_build_string(&c, &size, "%s%s%s", separator, prefix, doc->filename);
00926    }
00927 
00928    return filenames;
00929 }
00930 
00931 /*! \brief send a FAX status manager event */
00932 static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
00933 {
00934    char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
00935    if (!filenames) {
00936       return 1;
00937    }
00938 
00939    ast_channel_lock(chan);
00940    if (details->option.statusevents) {
00941       struct manager_event_info info;
00942 
00943       get_manager_event_info(chan, &info);
00944       manager_event(EVENT_FLAG_CALL,
00945                (details->caps & AST_FAX_TECH_RECEIVE) ? "ReceiveFAXStatus" : "SendFAXStatus",
00946                "Status: %s\r\n"
00947                "Channel: %s\r\n"
00948                "Context: %s\r\n"
00949                "Exten: %s\r\n"
00950                "CallerID: %s\r\n"
00951                "LocalStationID: %s\r\n"
00952                "%s\r\n",
00953                status,
00954                chan->name,
00955                info.context,
00956                info.exten,
00957                info.cid,
00958                details->localstationid,
00959                filenames);
00960    }
00961    ast_channel_unlock(chan);
00962    ast_free(filenames);
00963 
00964    return 0;
00965 }
00966 
00967 /*! \brief Set fax related channel variables. */
00968 static void set_channel_variables(struct ast_channel *chan, struct ast_fax_session_details *details)
00969 {
00970    char buf[10];
00971    pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL));
00972    pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL));
00973    pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL));
00974    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", S_OR(details->remotestationid, NULL));
00975    pbx_builtin_setvar_helper(chan, "LOCALSTATIONID", S_OR(details->localstationid, NULL));
00976    pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL));
00977    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL));
00978 
00979    snprintf(buf, sizeof(buf), "%d", details->pages_transferred);
00980    pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
00981 }
00982 
00983 #define GENERIC_FAX_EXEC_SET_VARS(fax, chan, errorstr, reason) \
00984    do {  \
00985       if (ast_strlen_zero(fax->details->result)) \
00986          ast_string_field_set(fax->details, result, "FAILED"); \
00987       if (ast_strlen_zero(fax->details->resultstr)) \
00988          ast_string_field_set(fax->details, resultstr, reason); \
00989       if (ast_strlen_zero(fax->details->error)) \
00990          ast_string_field_set(fax->details, error, errorstr); \
00991       set_channel_variables(chan, fax->details); \
00992    } while (0)
00993 
00994 #define GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason) \
00995    do {  \
00996       GENERIC_FAX_EXEC_SET_VARS(fax, chan, errorstr, reason); \
00997       res = ms = -1; \
00998    } while (0)
00999 
01000 #define GENERIC_FAX_EXEC_ERROR(fax, chan, errorstr, reason) \
01001    do {  \
01002       ast_log(LOG_ERROR, "channel '%s' FAX session '%d' failure, reason: '%s' (%s)\n", chan->name, fax->id, reason, errorstr); \
01003       GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason); \
01004    } while (0)
01005 
01006 static void t38_parameters_ast_to_fax(struct ast_fax_t38_parameters *dst, const struct ast_control_t38_parameters *src)
01007 {
01008    dst->version = src->version;
01009    dst->max_ifp = src->max_ifp;
01010    dst->rate = src->rate;
01011    dst->rate_management = src->rate_management;
01012    dst->fill_bit_removal = src->fill_bit_removal;
01013    dst->transcoding_mmr = src->transcoding_mmr;
01014    dst->transcoding_jbig = src->transcoding_jbig;
01015 }
01016 
01017 static void t38_parameters_fax_to_ast(struct ast_control_t38_parameters *dst, const struct ast_fax_t38_parameters *src)
01018 {
01019    dst->version = src->version;
01020    dst->max_ifp = src->max_ifp;
01021    dst->rate = src->rate;
01022    dst->rate_management = src->rate_management;
01023    dst->fill_bit_removal = src->fill_bit_removal;
01024    dst->transcoding_mmr = src->transcoding_mmr;
01025    dst->transcoding_jbig = src->transcoding_jbig;
01026 }
01027 
01028 static int set_fax_t38_caps(struct ast_channel *chan, struct ast_fax_session_details *details)
01029 {
01030    switch (ast_channel_get_t38_state(chan)) {
01031    case T38_STATE_UNKNOWN:
01032       details->caps |= AST_FAX_TECH_T38;
01033       break;
01034    case T38_STATE_UNAVAILABLE:
01035       details->caps |= AST_FAX_TECH_AUDIO;
01036       break;
01037    case T38_STATE_NEGOTIATING: {
01038       /* the other end already sent us a T.38 reinvite, so we need to prod the channel
01039        * driver into resending their parameters to us if it supports doing so... if
01040        * not, we can't proceed, because we can't create a proper reply without them.
01041        * if it does work, the channel driver will send an AST_CONTROL_T38_PARAMETERS
01042        * with a request of AST_T38_REQUEST_NEGOTIATE, which will be read by the function
01043        * that gets called after this one completes
01044        */
01045       struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, };
01046       if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters)) != AST_T38_REQUEST_PARMS) {
01047          ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01048          return -1;
01049       }
01050       details->caps |= AST_FAX_TECH_T38;
01051       break;
01052    }
01053    default:
01054       ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
01055       return -1;
01056    }
01057 
01058    return 0;
01059 }
01060 
01061 static int disable_t38(struct ast_channel *chan)
01062 {
01063    int ms;
01064    struct ast_frame *frame = NULL;
01065    struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
01066 
01067    ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
01068    if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
01069       ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01070       return -1;
01071    }
01072 
01073    /* wait up to five seconds for negotiation to complete */
01074    ms = 5000;
01075 
01076    while (ms > 0) {
01077       ms = ast_waitfor(chan, ms);
01078       if (ms < 0) {
01079          ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
01080          return -1;
01081       }
01082 
01083       if (ms == 0) { /* all done, nothing happened */
01084          ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
01085          break;
01086       }
01087 
01088       if (!(frame = ast_read(chan))) {
01089          return -1;
01090       }
01091       if ((frame->frametype == AST_FRAME_CONTROL) &&
01092           (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01093           (frame->datalen == sizeof(t38_parameters))) {
01094          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01095 
01096          switch (parameters->request_response) {
01097          case AST_T38_TERMINATED:
01098             ast_debug(1, "Shut down T.38 on %s\n", chan->name);
01099             break;
01100          case AST_T38_REFUSED:
01101             ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", chan->name);
01102             ast_frfree(frame);
01103             return -1;
01104          default:
01105             ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", chan->name);
01106             ast_frfree(frame);
01107             return -1;
01108          }
01109          ast_frfree(frame);
01110          break;
01111       }
01112       ast_frfree(frame);
01113    }
01114 
01115    return 0;
01116 }
01117 
01118 static struct ast_control_t38_parameters our_t38_parameters = {
01119    .version = 0,
01120    .max_ifp = 400,
01121    .rate = AST_T38_RATE_14400,
01122    .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
01123 };
01124 
01125 /*! \brief this is the generic FAX session handling function */
01126 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)
01127 {
01128    int ms;
01129    int timeout = RES_FAX_TIMEOUT;
01130    int res = 0, chancount;
01131    unsigned int expected_frametype = -1;
01132    union ast_frame_subclass expected_framesubclass = { .integer = -1 };
01133    unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
01134    struct ast_control_t38_parameters t38_parameters;
01135    const char *tempvar;
01136    struct ast_fax_session *fax = NULL;
01137    struct ast_frame *frame = NULL;
01138    struct ast_channel *c = chan;
01139    unsigned int orig_write_format = 0, orig_read_format = 0;
01140 
01141    chancount = 1;
01142 
01143    /* create the FAX session */
01144    if (!(fax = fax_session_new(details, chan, reserved, token))) {
01145       ast_log(LOG_ERROR, "Can't create a FAX session, FAX attempt failed.\n");
01146       report_fax_status(chan, details, "No Available Resource");
01147       return -1;
01148    }
01149 
01150    ast_channel_lock(chan);
01151    /* update session details */  
01152    if (ast_strlen_zero(details->headerinfo) && (tempvar = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"))) {
01153       ast_string_field_set(details, headerinfo, tempvar);
01154    }
01155    if (ast_strlen_zero(details->localstationid)) {
01156       tempvar = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
01157       ast_string_field_set(details, localstationid, tempvar ? tempvar : "unknown");
01158    }
01159    ast_channel_unlock(chan);
01160 
01161    report_fax_status(chan, details, "Allocating Resources");
01162 
01163    if (details->caps & AST_FAX_TECH_AUDIO) {
01164       expected_frametype = AST_FRAME_VOICE;;
01165       expected_framesubclass.codec = AST_FORMAT_SLINEAR;
01166       orig_write_format = chan->writeformat;
01167       if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01168          ast_log(LOG_ERROR, "channel '%s' failed to set write format to signed linear'.\n", chan->name);
01169          ao2_lock(faxregistry.container);
01170          ao2_unlink(faxregistry.container, fax);
01171          ao2_unlock(faxregistry.container);
01172          ao2_ref(fax, -1);
01173          ast_channel_unlock(chan);
01174          return -1;
01175       }
01176       orig_read_format = chan->readformat;
01177       if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01178          ast_log(LOG_ERROR, "channel '%s' failed to set read format to signed linear.\n", chan->name);
01179          ao2_lock(faxregistry.container);
01180          ao2_unlink(faxregistry.container, fax);
01181          ao2_unlock(faxregistry.container);
01182          ao2_ref(fax, -1);
01183          ast_channel_unlock(chan);
01184          return -1;
01185       }
01186       if (fax->smoother) {
01187          ast_smoother_free(fax->smoother);
01188          fax->smoother = NULL;
01189       }
01190       if (!(fax->smoother = ast_smoother_new(320))) {
01191          ast_log(LOG_WARNING, "Channel '%s' FAX session '%d' failed to obtain a smoother.\n", chan->name, fax->id);
01192       }
01193    } else {
01194       expected_frametype = AST_FRAME_MODEM;
01195       expected_framesubclass.codec = AST_MODEM_T38;
01196    }
01197 
01198    if (fax->debug_info) {
01199       fax->debug_info->base_tv = ast_tvnow();
01200    }
01201 
01202    /* reset our result fields just in case the fax tech driver wants to
01203     * set custom error messages */
01204    ast_string_field_set(details, result, "");
01205    ast_string_field_set(details, resultstr, "");
01206    ast_string_field_set(details, error, "");
01207    set_channel_variables(chan, details);
01208 
01209    if (fax->tech->start_session(fax) < 0) {
01210       GENERIC_FAX_EXEC_ERROR(fax, chan, "INIT_ERROR", "failed to start FAX session");
01211    }
01212 
01213    report_fax_status(chan, details, "FAX Transmission In Progress");
01214 
01215    ast_debug(5, "channel %s will wait on FAX fd %d\n", chan->name, fax->fd);
01216 
01217    /* handle frames for the session */
01218    ms = 1000;
01219    while ((res > -1) && (ms > -1) && (timeout > 0)) {
01220       struct ast_channel *ready_chan;
01221       int ofd, exception;
01222 
01223       ms = 1000;
01224       errno = 0;
01225       ready_chan = ast_waitfor_nandfds(&c, chancount, &fax->fd, 1, &exception, &ofd, &ms);
01226       if (ready_chan) {
01227          if (!(frame = ast_read(chan))) {
01228             /* the channel is probably gone, so lets stop polling on it and let the
01229              * FAX session complete before we exit the application.  if needed,
01230              * send the FAX stack silence so the modems can finish their session without
01231              * any problems */
01232             ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", chan->name);
01233             GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
01234             c = NULL;
01235             chancount = 0;
01236             timeout -= (1000 - ms);
01237             fax->tech->cancel_session(fax);
01238             if (fax->tech->generate_silence) {
01239                fax->tech->generate_silence(fax);
01240             }
01241             continue;
01242          }
01243 
01244          if ((frame->frametype == AST_FRAME_CONTROL) &&
01245              (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01246              (frame->datalen == sizeof(t38_parameters))) {
01247             unsigned int was_t38 = t38negotiated;
01248             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01249             
01250             switch (parameters->request_response) {
01251             case AST_T38_REQUEST_NEGOTIATE:
01252                /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01253                 * do T.38 as well
01254                 */
01255                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01256                t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01257                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01258                break;
01259             case AST_T38_NEGOTIATED:
01260                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01261                t38negotiated = 1;
01262                break;
01263             default:
01264                break;
01265             }
01266             if (t38negotiated && !was_t38) {
01267                fax->tech->switch_to_t38(fax);
01268                details->caps &= ~AST_FAX_TECH_AUDIO;
01269                expected_frametype = AST_FRAME_MODEM;
01270                expected_framesubclass.codec = AST_MODEM_T38;
01271                if (fax->smoother) {
01272                   ast_smoother_free(fax->smoother);
01273                   fax->smoother = NULL;
01274                }
01275                
01276                report_fax_status(chan, details, "T.38 Negotiated");
01277                
01278                ast_verb(3, "Channel '%s' switched to T.38 FAX session '%d'.\n", chan->name, fax->id);
01279             }
01280          } else if ((frame->frametype == expected_frametype) &&
01281                (!memcmp(&frame->subclass, &expected_framesubclass, sizeof(frame->subclass)))) {
01282             struct ast_frame *f;
01283             
01284             if (fax->smoother) {
01285                /* push the frame into a smoother */
01286                if (ast_smoother_feed(fax->smoother, frame) < 0) {
01287                   GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "Failed to feed the smoother");
01288                }
01289                while ((f = ast_smoother_read(fax->smoother)) && (f->data.ptr)) {
01290                   if (fax->debug_info) {
01291                      debug_check_frame_for_silence(fax, 1, f);
01292                   }
01293                   /* write the frame to the FAX stack */
01294                   fax->tech->write(fax, f);
01295                   fax->frames_received++;
01296                   if (f != frame) {
01297                      ast_frfree(f);
01298                   }
01299                }
01300             } else {
01301                /* write the frame to the FAX stack */
01302                fax->tech->write(fax, frame);
01303                fax->frames_received++;
01304             }
01305             timeout = RES_FAX_TIMEOUT;
01306          }
01307          ast_frfree(frame);
01308       } else if (ofd == fax->fd) {
01309          /* read a frame from the FAX stack and send it out the channel.
01310           * the FAX stack will return a NULL if the FAX session has already completed */
01311          if (!(frame = fax->tech->read(fax))) {
01312             break;
01313          }
01314 
01315          if (fax->debug_info && (frame->frametype == AST_FRAME_VOICE)) {
01316             debug_check_frame_for_silence(fax, 0, frame);
01317          }
01318 
01319          ast_write(chan, frame);
01320          fax->frames_sent++;
01321          ast_frfree(frame);
01322          timeout = RES_FAX_TIMEOUT;
01323       } else {
01324          if (ms && (ofd < 0)) {
01325             if ((errno == 0) || (errno == EINTR)) {
01326                timeout -= (1000 - ms);
01327                if (timeout <= 0)
01328                   GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
01329                continue;
01330             } else {
01331                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
01332                GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data");
01333                res = ms;
01334                break;
01335             }
01336          } else {
01337             /* nothing happened */
01338             if (timeout > 0) {
01339                timeout -= 1000;
01340                if (timeout <= 0)
01341                   GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
01342                continue;
01343             } else {
01344                ast_log(LOG_WARNING, "channel '%s' timed-out during the FAX transmission.\n", chan->name);
01345                GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
01346                break;
01347             }
01348          }
01349       }
01350    }
01351    ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", chan->name, timeout, ms, res);
01352 
01353    set_channel_variables(chan, details);
01354 
01355    if (!strcasecmp(details->result, "FAILED")) {
01356       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01357    } else {
01358       ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1);
01359    }
01360 
01361    if (fax) {
01362       ao2_lock(faxregistry.container);
01363       ao2_unlink(faxregistry.container, fax);
01364       ao2_unlock(faxregistry.container);
01365       ao2_ref(fax, -1);
01366    }
01367 
01368    /* if the channel is still alive, and we changed its read/write formats,
01369     * restore them now
01370     */
01371    if (chancount) {
01372       if (orig_read_format) {
01373          ast_set_read_format(chan, orig_read_format);
01374       }
01375       if (orig_write_format) {
01376          ast_set_write_format(chan, orig_write_format);
01377       }
01378    }
01379 
01380    /* return the chancount so the calling function can determine if the channel hungup during this FAX session or not */
01381    return chancount;
01382 }
01383 
01384 static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
01385 {
01386    int ms;
01387    struct ast_frame *frame = NULL;
01388    struct ast_control_t38_parameters t38_parameters;
01389 
01390    t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
01391 
01392    /* don't send any audio if we've already received a T.38 reinvite */
01393    if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
01394       /* generate 3 seconds of CED */
01395       if (ast_playtones_start(chan, 1024, "!2100/3000", 1)) {
01396          ast_log(LOG_ERROR, "error generating CED tone on %s\n", chan->name);
01397          return -1;
01398       }
01399 
01400       ms = 3000;
01401       while (ms > 0) {
01402          ms = ast_waitfor(chan, ms);
01403          if (ms < 0) {
01404             ast_log(LOG_ERROR, "error while generating CED tone on %s\n", chan->name);
01405             ast_playtones_stop(chan);
01406             return -1;
01407          }
01408 
01409          if (ms == 0) { /* all done, nothing happened */
01410             break;
01411          }
01412 
01413          if (!(frame = ast_read(chan))) {
01414             ast_log(LOG_ERROR, "error reading frame while generating CED tone on %s\n", chan->name);
01415             ast_playtones_stop(chan);
01416             return -1;
01417          }
01418 
01419          if ((frame->frametype == AST_FRAME_CONTROL) &&
01420              (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01421              (frame->datalen == sizeof(t38_parameters))) {
01422             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01423 
01424             switch (parameters->request_response) {
01425             case AST_T38_REQUEST_NEGOTIATE:
01426                /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01427                 * do T.38 as well
01428                 */
01429                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01430                t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01431                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01432                ast_playtones_stop(chan);
01433                break;
01434             case AST_T38_NEGOTIATED:
01435                ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01436                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01437                details->caps &= ~AST_FAX_TECH_AUDIO;
01438                report_fax_status(chan, details, "T.38 Negotiated");
01439                break;
01440             default:
01441                break;
01442             }
01443          }
01444          ast_frfree(frame);
01445       }
01446 
01447       ast_playtones_stop(chan);
01448    }
01449 
01450    /* if T.38 was negotiated, we are done initializing */
01451    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01452       return 0;
01453    }
01454 
01455    /* request T.38 */
01456    ast_debug(1, "Negotiating T.38 for receive on %s\n", chan->name);
01457 
01458    /* wait up to five seconds for negotiation to complete */
01459    ms = 5000;
01460 
01461    /* set parameters based on the session's parameters */
01462    t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01463    t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
01464    if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
01465       return -1;
01466    }
01467 
01468    while (ms > 0) {
01469       ms = ast_waitfor(chan, ms);
01470       if (ms < 0) {
01471          ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01472          return -1;
01473       }
01474 
01475       if (ms == 0) { /* all done, nothing happened */
01476          ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
01477          details->caps &= ~AST_FAX_TECH_T38;
01478          break;
01479       }
01480 
01481       if (!(frame = ast_read(chan))) {
01482          ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01483          return -1;
01484       }
01485 
01486       if ((frame->frametype == AST_FRAME_CONTROL) &&
01487             (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01488             (frame->datalen == sizeof(t38_parameters))) {
01489          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01490 
01491          switch (parameters->request_response) {
01492          case AST_T38_REQUEST_NEGOTIATE:
01493             t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01494             t38_parameters.request_response = AST_T38_NEGOTIATED;
01495             ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01496             break;
01497          case AST_T38_NEGOTIATED:
01498             ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01499             t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01500             details->caps &= ~AST_FAX_TECH_AUDIO;
01501             report_fax_status(chan, details, "T.38 Negotiated");
01502             ms = 0;
01503             break;
01504          case AST_T38_REFUSED:
01505             ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
01506             details->caps &= ~AST_FAX_TECH_T38;
01507             ms = 0;
01508             break;
01509          default:
01510             ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
01511             details->caps &= ~AST_FAX_TECH_T38;
01512             ms = 0;
01513             break;
01514          }
01515       }
01516       ast_frfree(frame);
01517    }
01518 
01519    /* if T.38 was negotiated, we are done initializing */
01520    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01521       return 0;
01522    }
01523 
01524    /* if we made it here, then T.38 failed, check the 'f' flag */
01525    if (details->option.allow_audio != AST_FAX_OPTFLAG_TRUE) {
01526       ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
01527       return -1;
01528    }
01529 
01530    /* ok, audio fallback is allowed */
01531    details->caps |= AST_FAX_TECH_AUDIO;
01532 
01533    return 0;
01534 }
01535 
01536 /*! \brief initiate a receive FAX session */
01537 static int receivefax_exec(struct ast_channel *chan, const char *data)
01538 {
01539    char *parse, modems[128] = "";
01540    int channel_alive;
01541    struct ast_fax_session_details *details;
01542    struct ast_fax_session *s;
01543    struct ast_fax_tech_token *token = NULL;
01544    struct ast_fax_document *doc;
01545    AST_DECLARE_APP_ARGS(args,
01546       AST_APP_ARG(filename);
01547       AST_APP_ARG(options);
01548    );
01549    struct ast_flags opts = { 0, };
01550    struct manager_event_info info;
01551 
01552    /* initialize output channel variables */
01553    pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
01554    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL);
01555    pbx_builtin_setvar_helper(chan, "FAXPAGES", "0");
01556    pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL);
01557    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL);
01558 
01559    /* if we ran receivefax then we attempted to receive a fax, even if we
01560     * never start a fax session */
01561    ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1);
01562 
01563    /* Get a FAX session details structure from the channel's FAX datastore and create one if
01564     * it does not already exist. */
01565    if (!(details = find_or_create_details(chan))) {
01566       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01567       pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR");
01568       pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory");
01569       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
01570       return -1;
01571    }
01572 
01573    ast_string_field_set(details, result, "FAILED");
01574    ast_string_field_set(details, resultstr, "error starting fax session");
01575    ast_string_field_set(details, error, "INIT_ERROR");
01576    set_channel_variables(chan, details);
01577 
01578    if (details->maxrate < details->minrate) {
01579       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01580       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01581       ast_string_field_set(details, resultstr, "maxrate is less than minrate");
01582       set_channel_variables(chan, details);
01583       ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
01584       ao2_ref(details, -1);
01585       return -1;
01586    }
01587 
01588    if (check_modem_rate(details->modems, details->minrate)) {
01589       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01590       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
01591       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
01592       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01593       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
01594       set_channel_variables(chan, details);
01595       ao2_ref(details, -1);
01596       return -1;
01597    }
01598 
01599    if (check_modem_rate(details->modems, details->maxrate)) {
01600       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01601       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
01602       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
01603       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01604       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
01605       set_channel_variables(chan, details);
01606       ao2_ref(details, -1);
01607       return -1;
01608    }
01609 
01610    if (ast_strlen_zero(data)) {
01611       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01612       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01613       ast_string_field_set(details, resultstr, "invalid arguments");
01614       set_channel_variables(chan, details);
01615       ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
01616       ao2_ref(details, -1);
01617       return -1;
01618    }
01619    parse = ast_strdupa(data);
01620    AST_STANDARD_APP_ARGS(args, parse);
01621 
01622    if (!ast_strlen_zero(args.options) &&
01623        ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
01624       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01625       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01626       ast_string_field_set(details, resultstr, "invalid arguments");
01627       set_channel_variables(chan, details);
01628       ao2_ref(details, -1);
01629       return -1;
01630    }
01631    if (ast_strlen_zero(args.filename)) {
01632       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01633       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01634       ast_string_field_set(details, resultstr, "invalid arguments");
01635       set_channel_variables(chan, details);
01636       ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
01637       ao2_ref(details, -1);
01638       return -1;
01639    }
01640 
01641    /* check for unsupported FAX application options */
01642    if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) {
01643       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01644       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
01645       ast_string_field_set(details, resultstr, "invalid arguments");
01646       set_channel_variables(chan, details);
01647       ast_log(LOG_WARNING, "%s does not support polling\n", app_receivefax);
01648       ao2_ref(details, -1);
01649       return -1;
01650    }
01651 
01652    pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems");
01653    pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Error before FAX transmission started.");
01654 
01655    if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(args.filename) + 1))) {
01656       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01657       ast_string_field_set(details, error, "MEMORY_ERROR");
01658       ast_string_field_set(details, resultstr, "error allocating memory");
01659       set_channel_variables(chan, details);
01660       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
01661       ao2_ref(details, -1);
01662       return -1;
01663    }
01664 
01665    strcpy(doc->filename, args.filename);
01666    AST_LIST_INSERT_TAIL(&details->documents, doc, next);
01667 
01668    ast_verb(3, "Channel '%s' receiving FAX '%s'\n", chan->name, args.filename);
01669 
01670    details->caps = AST_FAX_TECH_RECEIVE;
01671 
01672    /* check for debug */
01673    if (ast_test_flag(&opts, OPT_DEBUG) || global_fax_debug) {
01674       details->option.debug = AST_FAX_OPTFLAG_TRUE;
01675    }
01676 
01677    /* check for request for status events */
01678    if (ast_test_flag(&opts, OPT_STATUS)) {
01679       details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
01680    }
01681 
01682    if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
01683        ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
01684       details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
01685    }
01686 
01687    if (!(s = fax_session_reserve(details, &token))) {
01688       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01689       ast_string_field_set(details, resultstr, "error reserving fax session");
01690       set_channel_variables(chan, details);
01691       ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
01692       ao2_ref(details, -1);
01693       return -1;
01694    }
01695 
01696    /* make sure the channel is up */
01697    if (chan->_state != AST_STATE_UP) {
01698       if (ast_answer(chan)) {
01699          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01700          ast_string_field_set(details, resultstr, "error answering channel");
01701          set_channel_variables(chan, details);
01702          ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
01703          fax_session_release(s, token);
01704          ao2_ref(s, -1);
01705          ao2_ref(details, -1);
01706          return -1;
01707       }
01708    }
01709 
01710    if (set_fax_t38_caps(chan, details)) {
01711       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01712       ast_string_field_set(details, error, "T38_NEG_ERROR");
01713       ast_string_field_set(details, resultstr, "error negotiating T.38");
01714       set_channel_variables(chan, details);
01715       fax_session_release(s, token);
01716       ao2_ref(s, -1);
01717       ao2_ref(details, -1);
01718       return -1;
01719    }
01720 
01721    if (details->caps & AST_FAX_TECH_T38) {
01722       if (receivefax_t38_init(chan, details)) {
01723          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01724          ast_string_field_set(details, error, "T38_NEG_ERROR");
01725          ast_string_field_set(details, resultstr, "error negotiating T.38");
01726          set_channel_variables(chan, details);
01727          fax_session_release(s, token);
01728          ao2_ref(s, -1);
01729          ao2_ref(details, -1);
01730          ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
01731          return -1;
01732       }
01733    } else {
01734       details->option.send_ced = 1;
01735    }
01736 
01737    if ((channel_alive = generic_fax_exec(chan, details, s, token)) < 0) {
01738       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
01739    }
01740 
01741    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01742       if (disable_t38(chan)) {
01743          ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
01744       }
01745    }
01746 
01747    /* send out the AMI completion event */
01748    ast_channel_lock(chan);
01749 
01750    get_manager_event_info(chan, &info);
01751    manager_event(EVENT_FLAG_CALL,
01752             "ReceiveFAX", 
01753             "Channel: %s\r\n"
01754             "Context: %s\r\n"
01755             "Exten: %s\r\n"
01756             "CallerID: %s\r\n"
01757             "RemoteStationID: %s\r\n"
01758             "LocalStationID: %s\r\n"
01759             "PagesTransferred: %s\r\n"
01760             "Resolution: %s\r\n"
01761             "TransferRate: %s\r\n"
01762             "FileName: %s\r\n",
01763             chan->name,
01764             info.context,
01765             info.exten,
01766             info.cid,
01767             S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
01768             S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
01769             S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
01770             S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
01771             S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
01772             args.filename);
01773    ast_channel_unlock(chan);
01774 
01775    ao2_ref(s, -1);
01776    ao2_ref(details, -1);
01777 
01778    /* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
01779    return (!channel_alive) ? -1 : 0;
01780 }
01781 
01782 static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
01783 {
01784    int ms;
01785    struct ast_frame *frame = NULL;
01786    struct ast_control_t38_parameters t38_parameters;
01787 
01788    t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
01789 
01790    /* send CNG tone while listening for the receiver to initiate a switch
01791     * to T.38 mode; if they do, stop sending the CNG tone and proceed with
01792     * the switch.
01793     *
01794     * 10500 is enough time for 3 CNG tones
01795     */
01796    ms = 10500;
01797 
01798    /* don't send any audio if we've already received a T.38 reinvite */
01799    if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
01800       if (ast_playtones_start(chan, 1024, "!1100/500,!0/3000,!1100/500,!0/3000,!1100/500,!0/3000", 1)) {
01801          ast_log(LOG_ERROR, "error generating CNG tone on %s\n", chan->name);
01802          return -1;
01803       }
01804    }
01805 
01806    while (ms > 0) {
01807       ms = ast_waitfor(chan, ms);
01808       if (ms < 0) {
01809          ast_log(LOG_ERROR, "error while generating CNG tone on %s\n", chan->name);
01810          ast_playtones_stop(chan);
01811          return -1;
01812       }
01813 
01814       if (ms == 0) { /* all done, nothing happened */
01815          break;
01816       }
01817 
01818       if (!(frame = ast_read(chan))) {
01819          ast_log(LOG_ERROR, "error reading frame while generating CNG tone on %s\n", chan->name);
01820          ast_playtones_stop(chan);
01821          return -1;
01822       }
01823 
01824       if ((frame->frametype == AST_FRAME_CONTROL) &&
01825             (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01826             (frame->datalen == sizeof(t38_parameters))) {
01827          struct ast_control_t38_parameters *parameters = frame->data.ptr;
01828 
01829          switch (parameters->request_response) {
01830          case AST_T38_REQUEST_NEGOTIATE:
01831             /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01832              * do T.38 as well
01833              */
01834             t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01835             t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01836             ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01837             ast_playtones_stop(chan);
01838             break;
01839          case AST_T38_NEGOTIATED:
01840             ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
01841             t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01842             details->caps &= ~AST_FAX_TECH_AUDIO;
01843             report_fax_status(chan, details, "T.38 Negotiated");
01844             ms = 0;
01845             break;
01846          default:
01847             break;
01848          }
01849       }
01850       ast_frfree(frame);
01851    }
01852 
01853    ast_playtones_stop(chan);
01854 
01855    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01856       return 0;
01857    }
01858 
01859    /* T.38 negotiation did not happen, initiate a switch if requested */
01860    if (details->option.request_t38 == AST_FAX_OPTFLAG_TRUE) {
01861       ast_debug(1, "Negotiating T.38 for send on %s\n", chan->name);
01862 
01863       /* wait up to five seconds for negotiation to complete */
01864       ms = 5000;
01865 
01866       /* set parameters based on the session's parameters */
01867       t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01868       t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
01869       if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
01870          return -1;
01871       }
01872 
01873       while (ms > 0) {
01874          ms = ast_waitfor(chan, ms);
01875          if (ms < 0) {
01876             ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01877             return -1;
01878          }
01879 
01880          if (ms == 0) { /* all done, nothing happened */
01881             ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
01882             details->caps &= ~AST_FAX_TECH_T38;
01883             break;
01884          }
01885 
01886          if (!(frame = ast_read(chan))) {
01887             ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
01888             return -1;
01889          }
01890 
01891          if ((frame->frametype == AST_FRAME_CONTROL) &&
01892                (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01893                (frame->datalen == sizeof(t38_parameters))) {
01894             struct ast_control_t38_parameters *parameters = frame->data.ptr;
01895 
01896             switch (parameters->request_response) {
01897             case AST_T38_REQUEST_NEGOTIATE:
01898                t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01899                t38_parameters.request_response = AST_T38_NEGOTIATED;
01900                ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01901                break;
01902             case AST_T38_NEGOTIATED:
01903                ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
01904                t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01905                details->caps &= ~AST_FAX_TECH_AUDIO;
01906                report_fax_status(chan, details, "T.38 Negotiated");
01907                ms = 0;
01908                break;
01909             case AST_T38_REFUSED:
01910                ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
01911                details->caps &= ~AST_FAX_TECH_T38;
01912                ms = 0;
01913                break;
01914             default:
01915                ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
01916                details->caps &= ~AST_FAX_TECH_T38;
01917                ms = 0;
01918                break;
01919             }
01920          }
01921          ast_frfree(frame);
01922       }
01923 
01924       /* if T.38 was negotiated, we are done initializing */
01925       if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01926          return 0;
01927       }
01928 
01929       /* send one more CNG tone to get audio going again for some
01930        * carriers if we are going to fall back to audio mode */
01931       if (details->option.allow_audio == AST_FAX_OPTFLAG_TRUE) {
01932          if (ast_playtones_start(chan, 1024, "!1100/500,!0/3000", 1)) {
01933             ast_log(LOG_ERROR, "error generating second CNG tone on %s\n", chan->name);
01934             return -1;
01935          }
01936 
01937          ms = 3500;
01938          while (ms > 0) {
01939             ms = ast_waitfor(chan, ms);
01940             if (ms < 0) {
01941                ast_log(LOG_ERROR, "error while generating second CNG tone on %s\n", chan->name);
01942                ast_playtones_stop(chan);
01943                return -1;
01944             }
01945 
01946             if (ms == 0) { /* all done, nothing happened */
01947                break;
01948             }
01949 
01950             if (!(frame = ast_read(chan))) {
01951                ast_log(LOG_ERROR, "error reading frame while generating second CNG tone on %s\n", chan->name);
01952                ast_playtones_stop(chan);
01953                return -1;
01954             }
01955 
01956             if ((frame->frametype == AST_FRAME_CONTROL) &&
01957                   (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
01958                   (frame->datalen == sizeof(t38_parameters))) {
01959                struct ast_control_t38_parameters *parameters = frame->data.ptr;
01960 
01961                switch (parameters->request_response) {
01962                case AST_T38_REQUEST_NEGOTIATE:
01963                   /* the other end has requested a switch to T.38, so reply that we are willing, if we can
01964                    * do T.38 as well
01965                    */
01966                   t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
01967                   t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
01968                   ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
01969                   ast_playtones_stop(chan);
01970                   break;
01971                case AST_T38_NEGOTIATED:
01972                   ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
01973                   t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
01974                   details->caps &= ~AST_FAX_TECH_AUDIO;
01975                   report_fax_status(chan, details, "T.38 Negotiated");
01976                   ms = 0;
01977                   break;
01978                default:
01979                   break;
01980                }
01981             }
01982             ast_frfree(frame);
01983          }
01984 
01985          ast_playtones_stop(chan);
01986 
01987          /* if T.38 was negotiated, we are done initializing */
01988          if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
01989             return 0;
01990          }
01991       }
01992    }
01993 
01994    /* if we made it here, then T.38 failed, check the 'f' flag */
01995    if (details->option.allow_audio == AST_FAX_OPTFLAG_FALSE) {
01996       ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
01997       return -1;
01998    }
01999 
02000    /* ok, audio fallback is allowed */
02001    details->caps |= AST_FAX_TECH_AUDIO;
02002 
02003    return 0;
02004 }
02005 
02006 
02007 /*! \brief initiate a send FAX session */
02008 static int sendfax_exec(struct ast_channel *chan, const char *data)
02009 {
02010    char *parse, *filenames, *c, modems[128] = "";
02011    int channel_alive, file_count;
02012    struct ast_fax_session_details *details;
02013    struct ast_fax_session *s;
02014    struct ast_fax_tech_token *token = NULL;
02015    struct ast_fax_document *doc;
02016    AST_DECLARE_APP_ARGS(args,
02017       AST_APP_ARG(filenames);
02018       AST_APP_ARG(options);
02019    );
02020    struct ast_flags opts = { 0, };
02021    struct manager_event_info info;
02022 
02023    /* initialize output channel variables */
02024    pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
02025    pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", NULL);
02026    pbx_builtin_setvar_helper(chan, "FAXPAGES", "0");
02027    pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL);
02028    pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL);
02029 
02030    /* if we ran sendfax then we attempted to send a fax, even if we never
02031     * start a fax session */
02032    ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1);
02033 
02034    /* Get a requirement structure and set it.  This structure is used
02035     * to tell the FAX technology module about the higher level FAX session */
02036    if (!(details = find_or_create_details(chan))) {
02037       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02038       pbx_builtin_setvar_helper(chan, "FAXERROR", "MEMORY_ERROR");
02039       pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "error allocating memory");
02040       ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
02041       return -1;
02042    }
02043 
02044    ast_string_field_set(details, result, "FAILED");
02045    ast_string_field_set(details, resultstr, "error starting fax session");
02046    ast_string_field_set(details, error, "INIT_ERROR");
02047    set_channel_variables(chan, details);
02048 
02049    if (details->maxrate < details->minrate) {
02050       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02051       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02052       ast_string_field_set(details, resultstr, "maxrate is less than minrate");
02053       set_channel_variables(chan, details);
02054       ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
02055       ao2_ref(details, -1);
02056       return -1;
02057    }
02058 
02059    if (check_modem_rate(details->modems, details->minrate)) {
02060       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02061       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
02062       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
02063       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02064       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
02065       set_channel_variables(chan, details);
02066       ao2_ref(details, -1);
02067       return -1;
02068    }
02069 
02070    if (check_modem_rate(details->modems, details->maxrate)) {
02071       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02072       ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
02073       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
02074       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02075       ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
02076       set_channel_variables(chan, details);
02077       ao2_ref(details, -1);
02078       return -1;
02079    }
02080 
02081    if (ast_strlen_zero(data)) {
02082       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02083       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02084       ast_string_field_set(details, resultstr, "invalid arguments");
02085       set_channel_variables(chan, details);
02086       ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax);
02087       ao2_ref(details, -1);
02088       return -1;
02089    }
02090    parse = ast_strdupa(data);
02091    AST_STANDARD_APP_ARGS(args, parse);
02092 
02093 
02094    if (!ast_strlen_zero(args.options) &&
02095        ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
02096       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02097       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02098       ast_string_field_set(details, resultstr, "invalid arguments");
02099       set_channel_variables(chan, details);
02100       ao2_ref(details, -1);
02101       return -1;
02102    }
02103    if (ast_strlen_zero(args.filenames)) {
02104       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02105       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02106       ast_string_field_set(details, resultstr, "invalid arguments");
02107       set_channel_variables(chan, details);
02108       ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax);
02109       ao2_ref(details, -1);
02110       return -1;
02111    }
02112    
02113    /* check for unsupported FAX application options */
02114    if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) {
02115       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02116       ast_string_field_set(details, error, "INVALID_ARGUMENTS");
02117       ast_string_field_set(details, resultstr, "invalid arguments");
02118       set_channel_variables(chan, details);
02119       ast_log(LOG_WARNING, "%s does not support polling\n", app_sendfax);
02120       ao2_ref(details, -1);
02121       return -1;
02122    }
02123 
02124    file_count = 0;
02125    filenames = args.filenames;
02126    while ((c = strsep(&filenames, "&"))) {
02127       if (access(c, (F_OK | R_OK)) < 0) {
02128          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02129          ast_string_field_set(details, error, "FILE_ERROR");
02130          ast_string_field_set(details, resultstr, "error reading file");
02131          set_channel_variables(chan, details);
02132          ast_log(LOG_ERROR, "access failure.  Verify '%s' exists and check permissions.\n", args.filenames);
02133          ao2_ref(details, -1);
02134          return -1;
02135       }
02136 
02137       if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(c) + 1))) {
02138          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02139          ast_string_field_set(details, error, "MEMORY_ERROR");
02140          ast_string_field_set(details, resultstr, "error allocating memory");
02141          set_channel_variables(chan, details);
02142          ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
02143          ao2_ref(details, -1);
02144          return -1;
02145       }
02146 
02147       strcpy(doc->filename, c);
02148       AST_LIST_INSERT_TAIL(&details->documents, doc, next);
02149       file_count++;
02150    }
02151 
02152    if (file_count > 1) {
02153       details->caps |= AST_FAX_TECH_MULTI_DOC;
02154    }
02155 
02156    ast_verb(3, "Channel '%s' sending FAX:\n", chan->name);
02157    AST_LIST_TRAVERSE(&details->documents, doc, next) {
02158       ast_verb(3, "   %s\n", doc->filename);
02159    }
02160 
02161    details->caps = AST_FAX_TECH_SEND;
02162 
02163    /* check for debug */
02164    if (ast_test_flag(&opts, OPT_DEBUG) || global_fax_debug) {
02165       details->option.debug = AST_FAX_OPTFLAG_TRUE;
02166    }
02167 
02168    /* check for request for status events */
02169    if (ast_test_flag(&opts, OPT_STATUS)) {
02170       details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
02171    }
02172 
02173    if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
02174        ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
02175       details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
02176    }
02177 
02178    if (ast_test_flag(&opts, OPT_REQUEST_T38)) {
02179       details->option.request_t38 = AST_FAX_OPTFLAG_TRUE;
02180    }
02181 
02182    if (!(s = fax_session_reserve(details, &token))) {
02183       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02184       ast_string_field_set(details, resultstr, "error reserving fax session");
02185       set_channel_variables(chan, details);
02186       ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
02187       ao2_ref(details, -1);
02188       return -1;
02189    }
02190 
02191    /* make sure the channel is up */
02192    if (chan->_state != AST_STATE_UP) {
02193       if (ast_answer(chan)) {
02194          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02195          ast_string_field_set(details, resultstr, "error answering channel");
02196          set_channel_variables(chan, details);
02197          ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
02198          fax_session_release(s, token);
02199          ao2_ref(s, -1);
02200          ao2_ref(details, -1);
02201          return -1;
02202       }
02203    }
02204 
02205    if (set_fax_t38_caps(chan, details)) {
02206       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02207       ast_string_field_set(details, error, "T38_NEG_ERROR");
02208       ast_string_field_set(details, resultstr, "error negotiating T.38");
02209       set_channel_variables(chan, details);
02210       fax_session_release(s, token);
02211       ao2_ref(s, -1);
02212       ao2_ref(details, -1);
02213       return -1;
02214    }
02215 
02216    if (details->caps & AST_FAX_TECH_T38) {
02217       if (sendfax_t38_init(chan, details)) {
02218          ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02219          ast_string_field_set(details, error, "T38_NEG_ERROR");
02220          ast_string_field_set(details, resultstr, "error negotiating T.38");
02221          set_channel_variables(chan, details);
02222          fax_session_release(s, token);
02223          ao2_ref(s, -1);
02224          ao2_ref(details, -1);
02225          ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
02226          return -1;
02227       }
02228    } else {
02229       details->option.send_cng = 1;
02230    }
02231 
02232    if ((channel_alive = generic_fax_exec(chan, details, s, token)) < 0) {
02233       ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
02234    }
02235 
02236    if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
02237       if (disable_t38(chan)) {
02238          ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
02239       }
02240    }
02241 
02242    if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
02243       ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
02244       ao2_ref(s, -1);
02245       ao2_ref(details, -1);
02246       return (!channel_alive) ? -1 : 0;
02247    }
02248 
02249    /* send out the AMI completion event */
02250    ast_channel_lock(chan);
02251    get_manager_event_info(chan, &info);
02252    manager_event(EVENT_FLAG_CALL,
02253             "SendFAX", 
02254             "Channel: %s\r\n"
02255             "Context: %s\r\n"
02256             "Exten: %s\r\n"
02257             "CallerID: %s\r\n"
02258             "RemoteStationID: %s\r\n"
02259             "LocalStationID: %s\r\n"
02260             "PagesTransferred: %s\r\n"
02261             "Resolution: %s\r\n"
02262             "TransferRate: %s\r\n"
02263             "%s\r\n",
02264             chan->name,
02265             info.context,
02266             info.exten,
02267             info.cid,
02268             S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
02269             S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
02270             S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
02271             S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
02272             S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
02273             filenames);
02274    ast_channel_unlock(chan);
02275 
02276    ast_free(filenames);
02277 
02278    ao2_ref(s, -1);
02279    ao2_ref(details, -1);
02280 
02281    /* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
02282    return (!channel_alive) ? -1 : 0;
02283 }
02284 
02285 /*! \brief hash callback for ao2 */
02286 static int session_hash_cb(const void *obj, const int flags)
02287 {
02288    const struct ast_fax_session *s = obj;
02289 
02290    return s->id;
02291 }
02292 
02293 /*! \brief compare callback for ao2 */
02294 static int session_cmp_cb(void *obj, void *arg, int flags)
02295 {
02296    struct ast_fax_session *lhs = obj, *rhs = arg;
02297 
02298    return (lhs->id == rhs->id) ? CMP_MATCH | CMP_STOP : 0;
02299 }
02300 
02301 /*! \brief fax session tab completion */
02302 static char *fax_session_tab_complete(struct ast_cli_args *a)
02303 {
02304    int tklen;
02305    int wordnum = 0;
02306    char *name = NULL;
02307    struct ao2_iterator i;
02308    struct ast_fax_session *s;
02309    char tbuf[5];
02310 
02311    if (a->pos != 3) {
02312       return NULL;
02313    }
02314 
02315    tklen = strlen(a->word);
02316    i = ao2_iterator_init(faxregistry.container, 0);
02317    while ((s = ao2_iterator_next(&i))) {
02318       snprintf(tbuf, sizeof(tbuf), "%d", s->id);
02319       if (!strncasecmp(a->word, tbuf, tklen) && ++wordnum > a->n) {
02320          name = ast_strdup(tbuf);
02321          ao2_ref(s, -1);
02322          break;
02323       }
02324       ao2_ref(s, -1);
02325    }
02326    ao2_iterator_destroy(&i);
02327    return name;
02328 }
02329 
02330 static char *cli_fax_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02331 {
02332    struct fax_module *fax;
02333 
02334    switch(cmd) {
02335    case CLI_INIT:
02336       e->command = "fax show version";
02337       e->usage =
02338          "Usage: fax show version\n"
02339          "       Show versions of FAX For Asterisk components.\n";
02340       return NULL;
02341    case CLI_GENERATE:
02342       return NULL;
02343    }
02344 
02345    if (a->argc != 3) {
02346       return CLI_SHOWUSAGE;
02347    }
02348 
02349    ast_cli(a->fd, "FAX For Asterisk Components:\n");
02350    ast_cli(a->fd, "\tApplications: %s\n", ast_get_version());
02351    AST_RWLIST_RDLOCK(&faxmodules);
02352    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02353       ast_cli(a->fd, "\t%s: %s\n", fax->tech->description, fax->tech->version);
02354    }
02355    AST_RWLIST_UNLOCK(&faxmodules);
02356    ast_cli(a->fd, "\n");
02357 
02358    return CLI_SUCCESS;
02359 }
02360 
02361 /*! \brief enable FAX debugging */
02362 static char *cli_fax_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02363 {
02364    int flag;
02365    const char *what;
02366 
02367    switch (cmd) {
02368    case CLI_INIT:
02369       e->command = "fax set debug {on|off}";
02370       e->usage = 
02371          "Usage: fax set debug { on | off }\n"
02372          "       Enable/Disable FAX debugging on new FAX sessions.  The basic FAX debugging will result in\n"
02373          "       additional events sent to manager sessions with 'call' class permissions.  When\n"
02374          "       verbosity is greater than '5' events will be displayed to the console and audio versus\n"
02375          "       energy analysis will be performed and displayed to the console.\n";
02376       return NULL;
02377    case CLI_GENERATE:
02378       return NULL;
02379    }
02380 
02381    what = a->argv[e->args-1];      /* guaranteed to exist */
02382    if (!strcasecmp(what, "on")) {
02383       flag = 1;
02384    } else if (!strcasecmp(what, "off")) {
02385       flag = 0;
02386    } else {
02387       return CLI_SHOWUSAGE;
02388    }
02389 
02390    global_fax_debug = flag;
02391    ast_cli(a->fd, "\n\nFAX Debug %s\n\n", (flag) ? "Enabled" : "Disabled");
02392 
02393    return CLI_SUCCESS;
02394 }
02395 
02396 /*! \brief display registered FAX capabilities */
02397 static char *cli_fax_show_capabilities(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02398 {
02399    struct fax_module *fax;
02400    unsigned int num_modules = 0;
02401    
02402    switch (cmd) {
02403    case CLI_INIT:
02404       e->command = "fax show capabilities";
02405       e->usage = 
02406          "Usage: fax show capabilities\n"
02407          "       Shows the capabilities of the registered FAX technology modules\n";
02408       return NULL;
02409    case CLI_GENERATE:
02410       return NULL;
02411    }
02412 
02413    ast_cli(a->fd, "\n\nRegistered FAX Technology Modules:\n\n");
02414    AST_RWLIST_RDLOCK(&faxmodules);
02415    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02416       ast_cli(a->fd, "%-15s : %s\n%-15s : %s\n%-15s : ", "Type", fax->tech->type, "Description", fax->tech->description, "Capabilities");
02417       fax->tech->cli_show_capabilities(a->fd);
02418       num_modules++;
02419    }
02420    AST_RWLIST_UNLOCK(&faxmodules);
02421    ast_cli(a->fd, "%d registered modules\n\n", num_modules);
02422 
02423    return CLI_SUCCESS;
02424 }
02425 
02426 /*! \brief display global defaults and settings */
02427 static char *cli_fax_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02428 {
02429    struct fax_module *fax;
02430    char modems[128] = "";
02431 
02432    switch (cmd) {
02433    case CLI_INIT:
02434       e->command = "fax show settings";
02435       e->usage =
02436          "Usage: fax show settings\n"
02437          "       Show the global settings and defaults of both the FAX core and technology modules\n";
02438       return NULL;
02439    case CLI_GENERATE:
02440       return NULL;
02441    }
02442 
02443    ast_cli(a->fd, "FAX For Asterisk Settings:\n");
02444    ast_cli(a->fd, "\tECM: %s\n", general_options.ecm ? "Enabled" : "Disabled");
02445    ast_cli(a->fd, "\tStatus Events: %s\n",  general_options.statusevents ? "On" : "Off");
02446    ast_cli(a->fd, "\tMinimum Bit Rate: %d\n", general_options.minrate);
02447    ast_cli(a->fd, "\tMaximum Bit Rate: %d\n", general_options.maxrate);
02448    ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02449    ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
02450    ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
02451    AST_RWLIST_RDLOCK(&faxmodules);
02452    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02453       ast_cli(a->fd, "%s (%s) Settings:\n", fax->tech->type, fax->tech->description);
02454       fax->tech->cli_show_settings(a->fd);
02455    }
02456    AST_RWLIST_UNLOCK(&faxmodules);
02457 
02458    return CLI_SUCCESS;
02459 }
02460 
02461 /*! \brief display details of a specified fax session */
02462 static char *cli_fax_show_session(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02463 {
02464    struct ast_fax_session *s, tmp;
02465 
02466    switch (cmd) {
02467    case CLI_INIT:
02468       e->command = "fax show session";
02469       e->usage =
02470          "Usage: fax show session <session number>\n"
02471          "       Shows status of the named FAX session\n";
02472       return NULL;
02473    case CLI_GENERATE:
02474       return fax_session_tab_complete(a);
02475    }
02476 
02477    if (a->argc != 4) {
02478       return CLI_SHOWUSAGE;
02479    }
02480 
02481    if (sscanf(a->argv[3], "%d", &tmp.id) != 1) {
02482       ast_log(LOG_ERROR, "invalid session id: '%s'\n", a->argv[3]);
02483       return RESULT_SUCCESS;
02484    }
02485 
02486    ast_cli(a->fd, "\nFAX Session Details:\n--------------------\n\n");
02487    s = ao2_find(faxregistry.container, &tmp, OBJ_POINTER);
02488    if (s) {
02489       s->tech->cli_show_session(s, a->fd);
02490       ao2_ref(s, -1);
02491    }
02492    ast_cli(a->fd, "\n\n");
02493 
02494    return CLI_SUCCESS;
02495 }
02496    
02497 /*! \brief display fax stats */
02498 static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02499 {
02500    struct fax_module *fax;
02501    
02502    switch (cmd) {
02503    case CLI_INIT:
02504       e->command = "fax show stats";
02505       e->usage =
02506          "Usage: fax show stats\n"
02507          "       Shows a statistical summary of FAX transmissions\n";
02508       return NULL;
02509    case CLI_GENERATE:
02510       return NULL;
02511    }
02512 
02513    ast_cli(a->fd, "\nFAX Statistics:\n---------------\n\n");
02514    ast_cli(a->fd, "%-20.20s : %d\n", "Current Sessions", faxregistry.active_sessions);
02515    ast_cli(a->fd, "%-20.20s : %d\n", "Reserved Sessions", faxregistry.reserved_sessions);
02516    ast_cli(a->fd, "%-20.20s : %d\n", "Transmit Attempts", faxregistry.fax_tx_attempts);
02517    ast_cli(a->fd, "%-20.20s : %d\n", "Receive Attempts", faxregistry.fax_rx_attempts);
02518    ast_cli(a->fd, "%-20.20s : %d\n", "Completed FAXes", faxregistry.fax_complete);
02519    ast_cli(a->fd, "%-20.20s : %d\n", "Failed FAXes", faxregistry.fax_failures);
02520    AST_RWLIST_RDLOCK(&faxmodules);
02521    AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
02522       fax->tech->cli_show_stats(a->fd);
02523    }
02524    AST_RWLIST_UNLOCK(&faxmodules);
02525    ast_cli(a->fd, "\n\n");
02526 
02527    return CLI_SUCCESS;
02528 }
02529 
02530 /*! \brief display fax sessions */
02531 static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02532 {
02533    struct ast_fax_session *s;
02534    struct ao2_iterator i;
02535    int session_count;
02536    char *filenames;
02537 
02538    switch (cmd) {
02539    case CLI_INIT:
02540       e->command = "fax show sessions";
02541       e->usage =
02542          "Usage: fax show sessions\n"
02543          "       Shows the current FAX sessions\n";
02544       return NULL;
02545    case CLI_GENERATE:
02546       return NULL;
02547    }
02548 
02549    ast_cli(a->fd, "\nCurrent FAX Sessions:\n\n");
02550    ast_cli(a->fd, "%-20.20s %-10.10s %-10.10s %-5.5s %-10.10s %-15.15s %-30.30s\n",
02551       "Channel", "Tech", "FAXID", "Type", "Operation", "State", "File(s)");
02552    i = ao2_iterator_init(faxregistry.container, 0);
02553    while ((s = ao2_iterator_next(&i))) {
02554       ao2_lock(s);
02555 
02556       if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
02557          ast_log(LOG_ERROR, "error printing filenames for 'fax show sessions' command");
02558          ao2_unlock(s);
02559          ao2_ref(s, -1);
02560          ao2_iterator_destroy(&i);
02561          return CLI_FAILURE;
02562       }
02563 
02564       ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
02565          s->channame, s->tech->type, s->id,
02566          (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
02567          (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
02568          ast_fax_state_to_str(s->state), filenames);
02569 
02570       ast_free(filenames);
02571       ao2_unlock(s);
02572       ao2_ref(s, -1);
02573    }
02574    ao2_iterator_destroy(&i);
02575    session_count = ao2_container_count(faxregistry.container);
02576    ast_cli(a->fd, "\n%d FAX sessions\n\n", session_count);
02577 
02578    return CLI_SUCCESS;
02579 }
02580 
02581 static struct ast_cli_entry fax_cli[] = {
02582    AST_CLI_DEFINE(cli_fax_show_version, "Show versions of FAX For Asterisk components"),
02583    AST_CLI_DEFINE(cli_fax_set_debug, "Enable/Disable FAX debugging on new FAX sessions"),
02584    AST_CLI_DEFINE(cli_fax_show_capabilities, "Show the capabilities of the registered FAX technology modules"),
02585    AST_CLI_DEFINE(cli_fax_show_settings, "Show the global settings and defaults of both the FAX core and technology modules"),
02586    AST_CLI_DEFINE(cli_fax_show_session, "Show the status of the named FAX sessions"),
02587    AST_CLI_DEFINE(cli_fax_show_sessions, "Show the current FAX sessions"),
02588    AST_CLI_DEFINE(cli_fax_show_stats, "Summarize FAX session history"),
02589 };
02590 
02591 /*! \brief configure res_fax */
02592 static int set_config(const char *config_file)
02593 {
02594    struct ast_config *cfg;
02595    struct ast_variable *v;
02596    struct ast_flags config_flags = { 0 };
02597    char modems[128] = "";
02598 
02599    /* set defaults */   
02600    general_options.minrate = RES_FAX_MINRATE;
02601    general_options.maxrate = RES_FAX_MAXRATE;   
02602    general_options.statusevents = RES_FAX_STATUSEVENTS;
02603    general_options.modems = RES_FAX_MODEM;
02604    general_options.ecm = AST_FAX_OPTFLAG_TRUE;
02605 
02606    /* read configuration */
02607    if (!(cfg = ast_config_load2(config_file, "res_fax", config_flags))) {
02608       ast_log(LOG_NOTICE, "Configuration file '%s' not found, using default options.\n", config_file);
02609       return 0;
02610    }
02611 
02612    if (cfg == CONFIG_STATUS_FILEINVALID) {
02613       ast_log(LOG_NOTICE, "Configuration file '%s' is invalid, using default options.\n", config_file);
02614       return 0;
02615    }
02616 
02617    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
02618       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
02619       cfg = ast_config_load2(config_file, "res_fax", config_flags);
02620    }
02621 
02622    /* create configuration */
02623    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
02624       int rate;
02625 
02626       if (!strcasecmp(v->name, "minrate")) {
02627          ast_debug(3, "reading minrate '%s' from configuration file\n", v->value);
02628          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02629             ast_config_destroy(cfg);
02630             return -1;
02631          }
02632          general_options.minrate = rate;
02633       } else if (!strcasecmp(v->name, "maxrate")) {
02634          ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value);
02635          if ((rate = fax_rate_str_to_int(v->value)) == 0) {
02636             ast_config_destroy(cfg);
02637             return -1;
02638          }
02639          general_options.maxrate = rate;
02640       } else if (!strcasecmp(v->name, "statusevents")) {
02641          ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value);
02642          general_options.statusevents = ast_true(v->value);
02643       } else if (!strcasecmp(v->name, "ecm")) {
02644          ast_debug(3, "reading ecm '%s' from configuration file\n", v->value);
02645          general_options.ecm = ast_true(v->value);
02646       } else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
02647          general_options.modems = 0;
02648          update_modem_bits(&general_options.modems, v->value);
02649       }
02650    }
02651 
02652    ast_config_destroy(cfg);
02653 
02654    if (general_options.maxrate < general_options.minrate) {
02655       ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", general_options.maxrate, general_options.minrate);
02656       return -1;
02657    }
02658 
02659    if (check_modem_rate(general_options.modems, general_options.minrate)) {
02660       ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02661       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, general_options.minrate);
02662       return -1;
02663    }
02664 
02665    if (check_modem_rate(general_options.modems, general_options.maxrate)) {
02666       ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
02667       ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, general_options.maxrate);
02668       return -1;
02669    }
02670 
02671    return 0;
02672 }
02673 
02674 /*! \brief FAXOPT read function returns the contents of a FAX option */
02675 static int acf_faxopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
02676 {
02677    struct ast_fax_session_details *details = find_details(chan);
02678    int res = 0;
02679    char *filenames;
02680 
02681    if (!details) {
02682       ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02683       return -1;
02684    }
02685    if (!strcasecmp(data, "ecm")) {
02686       ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
02687    } else if (!strcasecmp(data, "error")) {
02688       ast_copy_string(buf, details->error, len);
02689    } else if (!strcasecmp(data, "filename")) {
02690       if (AST_LIST_EMPTY(&details->documents)) {
02691          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02692          res = -1;
02693       } else {
02694          ast_copy_string(buf, AST_LIST_FIRST(&details->documents)->filename, len);
02695       }
02696    } else if (!strcasecmp(data, "filenames")) {
02697       if (AST_LIST_EMPTY(&details->documents)) {
02698          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
02699          res = -1;
02700       } else if ((filenames = generate_filenames_string(details, "", ","))) {
02701          ast_copy_string(buf, filenames, len);
02702          ast_free(filenames);
02703       } else {
02704          ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s), there was an error generating the filenames list.\n", chan->name, data);
02705          res = -1;
02706       }
02707    } else if (!strcasecmp(data, "headerinfo")) {
02708       ast_copy_string(buf, details->headerinfo, len);
02709    } else if (!strcasecmp(data, "localstationid")) {
02710       ast_copy_string(buf, details->localstationid, len);
02711    } else if (!strcasecmp(data, "maxrate")) {
02712       snprintf(buf, len, "%d", details->maxrate);
02713    } else if (!strcasecmp(data, "minrate")) {
02714       snprintf(buf, len, "%d", details->minrate);
02715    } else if (!strcasecmp(data, "pages")) {
02716       snprintf(buf, len, "%d", details->pages_transferred);
02717    } else if (!strcasecmp(data, "rate")) {
02718       ast_copy_string(buf, details->transfer_rate, len);
02719    } else if (!strcasecmp(data, "remotestationid")) {
02720       ast_copy_string(buf, details->remotestationid, len);
02721    } else if (!strcasecmp(data, "resolution")) {
02722       ast_copy_string(buf, details->resolution, len);
02723    } else if (!strcasecmp(data, "sessionid")) {
02724       snprintf(buf, len, "%d", details->id);
02725    } else if (!strcasecmp(data, "status")) {
02726       ast_copy_string(buf, details->result, len);
02727    } else if (!strcasecmp(data, "statusstr")) {
02728       ast_copy_string(buf, details->resultstr, len);
02729    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02730       ast_fax_modem_to_str(details->modems, buf, len);
02731    } else {
02732       ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", chan->name, data);
02733       res = -1;
02734    }
02735    ao2_ref(details, -1);
02736 
02737    return res;
02738 }
02739 
02740 /*! \brief FAXOPT write function modifies the contents of a FAX option */
02741 static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
02742 {
02743    int res = 0;
02744    struct ast_fax_session_details *details;
02745 
02746    if (!(details = find_or_create_details(chan))) {
02747       ast_log(LOG_WARNING, "channel '%s' can't set FAXOPT(%s) to '%s' because it failed to create a datastore.\n", chan->name, data, value);
02748       return -1;
02749    }
02750    ast_debug(3, "channel '%s' setting FAXOPT(%s) to '%s'\n", chan->name, data, value);
02751 
02752    if (!strcasecmp(data, "ecm")) {
02753       const char *val = ast_skip_blanks(value);
02754       if (ast_true(val)) {
02755          details->option.ecm = AST_FAX_OPTFLAG_TRUE;
02756       } else if (ast_false(val)) {
02757          details->option.ecm = AST_FAX_OPTFLAG_FALSE;
02758       } else {
02759          ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
02760       }
02761    } else if (!strcasecmp(data, "headerinfo")) {
02762       ast_string_field_set(details, headerinfo, value);
02763    } else if (!strcasecmp(data, "localstationid")) {
02764       ast_string_field_set(details, localstationid, value);
02765    } else if (!strcasecmp(data, "maxrate")) {
02766       details->maxrate = fax_rate_str_to_int(value);
02767       if (!details->maxrate) {
02768          details->maxrate = ast_fax_maxrate();
02769       }
02770    } else if (!strcasecmp(data, "minrate")) {
02771       details->minrate = fax_rate_str_to_int(value);
02772       if (!details->minrate) {
02773          details->minrate = ast_fax_minrate();
02774       }
02775    } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
02776       update_modem_bits(&details->modems, value);
02777    } else {
02778       ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", chan->name, data, value);
02779       res = -1;
02780    }
02781 
02782    ao2_ref(details, -1);
02783 
02784    return res;
02785 }
02786 
02787 /*! \brief FAXOPT dialplan function */
02788 struct ast_custom_function acf_faxopt = {
02789    .name = "FAXOPT",
02790    .read = acf_faxopt_read,
02791    .write = acf_faxopt_write,
02792 };
02793 
02794 /*! \brief unload res_fax */
02795 static int unload_module(void)
02796 {
02797    ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
02798    
02799    if (ast_custom_function_unregister(&acf_faxopt) < 0) {
02800       ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
02801    }
02802 
02803    if (ast_unregister_application(app_sendfax) < 0) {
02804       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_sendfax);
02805    }
02806 
02807    if (ast_unregister_application(app_receivefax) < 0) {
02808       ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
02809    }
02810 
02811    if (fax_logger_level != -1) {
02812       ast_logger_unregister_level("FAX");
02813    }
02814 
02815    ao2_ref(faxregistry.container, -1);
02816 
02817    return 0;
02818 }
02819 
02820 /*! \brief load res_fax */
02821 static int load_module(void)
02822 {
02823    int res;
02824 
02825    /* initialize the registry */
02826    faxregistry.active_sessions = 0;
02827    faxregistry.reserved_sessions = 0;
02828    if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
02829       return AST_MODULE_LOAD_DECLINE;
02830    }
02831    
02832    if (set_config(config) < 0) {
02833       ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
02834       ao2_ref(faxregistry.container, -1);
02835       return AST_MODULE_LOAD_DECLINE;
02836    }
02837 
02838    /* register CLI operations and applications */
02839    if (ast_register_application_xml(app_sendfax, sendfax_exec) < 0) {
02840       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_sendfax);
02841       ao2_ref(faxregistry.container, -1);
02842       return AST_MODULE_LOAD_DECLINE;
02843    }
02844    if (ast_register_application_xml(app_receivefax, receivefax_exec) < 0) {
02845       ast_log(LOG_WARNING, "failed to register '%s'.\n", app_receivefax);
02846       ast_unregister_application(app_sendfax);
02847       ao2_ref(faxregistry.container, -1);
02848       return AST_MODULE_LOAD_DECLINE;
02849    }
02850    ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
02851    res = ast_custom_function_register(&acf_faxopt);   
02852    fax_logger_level = ast_logger_register_level("FAX");
02853 
02854    return res;
02855 }
02856 
02857 
02858 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic FAX Applications",
02859       .load = load_module,
02860       .unload = unload_module,
02861       .load_pri = AST_MODPRI_APP_DEPEND,
02862           );

Generated on Mon Mar 19 11:30:29 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7