Wed Apr 6 11:29:47 2011

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

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