Sun Oct 16 2011 08:41:45

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