00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "asterisk.h"
00020
00021 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 177785 $")
00022
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <inttypes.h>
00027 #include <pthread.h>
00028 #include <errno.h>
00029 #include <tiffio.h>
00030
00031 #include <spandsp.h>
00032 #ifdef HAVE_SPANDSP_EXPOSE_H
00033 #include <spandsp/expose.h>
00034 #endif
00035 #include <spandsp/version.h>
00036
00037 #include "asterisk/lock.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/dsp.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/manager.h"
00046
00047 static char *app_sndfax_name = "SendFAX";
00048 static char *app_sndfax_synopsis = "Send a FAX";
00049 static char *app_sndfax_desc =
00050 " SendFAX(filename[|options]):\n"
00051 "Send a given TIFF file to the channel as a FAX.\n"
00052 "The option string may contain zero or more of the following characters:\n"
00053 " 'a' - makes the application behave as an answering machine\n"
00054 " The default behaviour is to behave as a calling machine.\n"
00055 "\n"
00056 "This application uses following variables:\n"
00057 " LOCALSTATIONID to identify itself to the remote end.\n"
00058 " LOCALHEADERINFO to generate a header line on each page.\n"
00059 "\n"
00060 "This application sets the following channel variables upon completion:\n"
00061 " FAXSTATUS - status of operation:\n"
00062 " SUCCESS | FAILED\n"
00063 " FAXERROR - Error when FAILED\n"
00064 " FAXMODE - Mode used:\n"
00065 " audio | T38\n"
00066 " REMOTESTATIONID - CSID of the remote side.\n"
00067 " FAXPAGES - number of pages sent.\n"
00068 " FAXBITRATE - transmition rate.\n"
00069 " FAXRESOLUTION - resolution.\n"
00070 "\n"
00071 "Returns -1 in case of user hang up or any channel error.\n"
00072 "Returns 0 on success.\n";
00073
00074 static char *app_rcvfax_name = "ReceiveFAX";
00075 static char *app_rcvfax_synopsis = "Receive a FAX";
00076 static char *app_rcvfax_desc =
00077 " ReceiveFAX(filename[|options]):\n"
00078 "Receives a fax from the channel into the given filename overwriting\n"
00079 "the file if it already exists. File created will have TIFF format.\n"
00080 "The option string may contain zero or more of the following characters:\n"
00081 " 'c' -- makes the application behave as a calling machine\n"
00082 " The default behaviour is to behave as an answering machine.\n"
00083 "\n"
00084 "This application uses following variables:\n"
00085 " LOCALSTATIONID to identify itself to the remote end.\n"
00086 " LOCALHEADERINFO to generate a header line on each page.\n"
00087 "\n"
00088 "This application sets the following channel variables upon completion:\n"
00089 " FAXSTATUS - status of operation:\n"
00090 " SUCCESS | FAILED\n"
00091 " FAXERROR - Error when FAILED\n"
00092 " FAXMODE - Mode used:\n"
00093 " audio | T38\n"
00094 " REMOTESTATIONID - CSID of the remote side.\n"
00095 " FAXPAGES - number of pages sent.\n"
00096 " FAXBITRATE - transmition rate.\n"
00097 " FAXRESOLUTION - resolution.\n"
00098 "\n"
00099 "Returns -1 in case of user hang up or any channel error.\n"
00100 "Returns 0 on success.\n";
00101
00102 #define MAX_SAMPLES 240
00103
00104
00105
00106
00107
00108
00109
00110 #define WATCHDOG_TOTAL_TIMEOUT 30 * 60
00111 #define WATCHDOG_STATE_TIMEOUT 5 * 60
00112
00113 typedef struct {
00114 struct ast_channel *chan;
00115 enum ast_t38_state t38state;
00116 int direction;
00117 int caller_mode;
00118 char *file_name;
00119
00120 volatile int finished;
00121 } fax_session;
00122
00123 static void span_message(int level, const char *msg)
00124 {
00125 if (level == SPAN_LOG_ERROR) {
00126 ast_log(LOG_ERROR, "%s", msg);
00127 } else if (level == SPAN_LOG_WARNING) {
00128 ast_log(LOG_WARNING, "%s", msg);
00129 } else {
00130 ast_log(LOG_DEBUG, "%s", msg);
00131 }
00132 }
00133
00134 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
00135 {
00136 struct ast_channel *chan = (struct ast_channel *) user_data;
00137
00138 struct ast_frame outf = {
00139 .frametype = AST_FRAME_MODEM,
00140 .subclass = AST_MODEM_T38,
00141 .src = __FUNCTION__,
00142 };
00143
00144
00145
00146
00147 AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
00148
00149 if (ast_write(chan, &outf) < 0) {
00150 ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
00151 return -1;
00152 }
00153
00154 return 0;
00155 }
00156
00157 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
00158 {
00159 const char *local_ident;
00160 const char *far_ident;
00161 char buf[20];
00162 fax_session *s = (fax_session *) user_data;
00163 t30_stats_t stat;
00164 int pages_transferred;
00165
00166 ast_debug(1, "Fax phase E handler. result=%d\n", result);
00167
00168 t30_get_transfer_statistics(f, &stat);
00169
00170 s = (fax_session *) user_data;
00171
00172 if (result != T30_ERR_OK) {
00173 s->finished = -1;
00174
00175
00176 pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
00177
00178 ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
00179
00180 return;
00181 }
00182
00183 s->finished = 1;
00184
00185 local_ident = t30_get_tx_ident(f);
00186 far_ident = t30_get_rx_ident(f);
00187 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
00188 pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
00189 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
00190 #if SPANDSP_RELEASE_DATE >= 20090220
00191 pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
00192 #else
00193 pages_transferred = stat.pages_transferred;
00194 #endif
00195 snprintf(buf, sizeof(buf), "%d", pages_transferred);
00196 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
00197 snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
00198 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
00199 snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
00200 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);
00201
00202 ast_debug(1, "Fax transmitted successfully.\n");
00203 ast_debug(1, " Remote station ID: %s\n", far_ident);
00204 ast_debug(1, " Pages transferred: %d\n", pages_transferred);
00205 ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
00206 ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
00207
00208 manager_event(EVENT_FLAG_CALL,
00209 s->direction ? "FaxSent" : "FaxReceived",
00210 "Channel: %s\r\n"
00211 "Exten: %s\r\n"
00212 "CallerID: %s\r\n"
00213 "RemoteStationID: %s\r\n"
00214 "LocalStationID: %s\r\n"
00215 "PagesTransferred: %d\r\n"
00216 "Resolution: %d\r\n"
00217 "TransferRate: %d\r\n"
00218 "FileName: %s\r\n",
00219 s->chan->name,
00220 s->chan->exten,
00221 S_OR(s->chan->cid.cid_num, ""),
00222 far_ident,
00223 local_ident,
00224 pages_transferred,
00225 stat.y_resolution,
00226 stat.bit_rate,
00227 s->file_name);
00228 }
00229
00230
00231
00232
00233 static int set_logging(logging_state_t *state)
00234 {
00235 int level = SPAN_LOG_WARNING + option_debug;
00236
00237 span_log_set_message_handler(state, span_message);
00238 span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
00239
00240 return 0;
00241 }
00242
00243 static void set_local_info(t30_state_t *state, fax_session *s)
00244 {
00245 const char *x;
00246
00247 x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
00248 if (!ast_strlen_zero(x))
00249 t30_set_tx_ident(state, x);
00250
00251 x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
00252 if (!ast_strlen_zero(x))
00253 t30_set_tx_page_header_info(state, x);
00254 }
00255
00256 static void set_file(t30_state_t *state, fax_session *s)
00257 {
00258 if (s->direction)
00259 t30_set_tx_file(state, s->file_name, -1, -1);
00260 else
00261 t30_set_rx_file(state, s->file_name, -1);
00262 }
00263
00264 static void set_ecm(t30_state_t *state, int ecm)
00265 {
00266 t30_set_ecm_capability(state, ecm);
00267 t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
00268 }
00269
00270
00271
00272
00273
00274 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
00275 {
00276 return params;
00277 }
00278
00279 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
00280 {
00281 fax_state_t *fax = (fax_state_t*) data;
00282 uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
00283 int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
00284
00285 struct ast_frame outf = {
00286 .frametype = AST_FRAME_VOICE,
00287 .subclass = AST_FORMAT_SLINEAR,
00288 .src = __FUNCTION__,
00289 };
00290
00291 if (samples > MAX_SAMPLES) {
00292 ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
00293 samples = MAX_SAMPLES;
00294 }
00295
00296 if ((len = fax_tx(fax, buf, samples)) > 0) {
00297 outf.samples = len;
00298 AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
00299
00300 if (ast_write(chan, &outf) < 0) {
00301 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00302 return -1;
00303 }
00304 }
00305
00306 return 0;
00307 }
00308
00309 struct ast_generator generator = {
00310 alloc: fax_generator_alloc,
00311 generate: fax_generator_generate,
00312 };
00313
00314
00315
00316
00317 static int transmit_audio(fax_session *s)
00318 {
00319 int res = -1;
00320 int original_read_fmt = AST_FORMAT_SLINEAR;
00321 int original_write_fmt = AST_FORMAT_SLINEAR;
00322 fax_state_t fax;
00323 t30_state_t *t30state;
00324 struct ast_dsp *dsp = NULL;
00325 int detect_tone = 0;
00326 struct ast_frame *inf = NULL;
00327 struct ast_frame *fr;
00328 int last_state = 0;
00329 struct timeval now, start, state_change;
00330 enum ast_control_t38 t38control;
00331
00332 #if SPANDSP_RELEASE_DATE >= 20081012
00333
00334 t30state = &fax.t30;
00335 #else
00336
00337 t30state = &fax.t30_state;
00338 #endif
00339
00340 original_read_fmt = s->chan->readformat;
00341 if (original_read_fmt != AST_FORMAT_SLINEAR) {
00342 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
00343 if (res < 0) {
00344 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
00345 goto done;
00346 }
00347 }
00348
00349 original_write_fmt = s->chan->writeformat;
00350 if (original_write_fmt != AST_FORMAT_SLINEAR) {
00351 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
00352 if (res < 0) {
00353 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
00354 goto done;
00355 }
00356 }
00357
00358
00359 fax_init(&fax, s->caller_mode);
00360
00361
00362 set_logging(&fax.logging);
00363 set_logging(&t30state->logging);
00364
00365
00366 set_local_info(t30state, s);
00367 set_file(t30state, s);
00368 set_ecm(t30state, TRUE);
00369
00370 fax_set_transmit_on_idle(&fax, TRUE);
00371
00372 t30_set_phase_e_handler(t30state, phase_e_handler, s);
00373
00374 if (s->t38state == T38_STATE_UNAVAILABLE) {
00375 ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
00376 } else if (!s->direction) {
00377
00378
00379 ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
00380 dsp = ast_dsp_new();
00381 ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
00382 ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
00383 detect_tone = 1;
00384 }
00385
00386 start = state_change = ast_tvnow();
00387
00388 ast_activate_generator(s->chan, &generator, &fax);
00389
00390 while (!s->finished) {
00391 res = ast_waitfor(s->chan, 20);
00392 if (res < 0)
00393 break;
00394 else if (res > 0)
00395 res = 0;
00396
00397 inf = ast_read(s->chan);
00398 if (inf == NULL) {
00399 ast_debug(1, "Channel hangup\n");
00400 res = -1;
00401 break;
00402 }
00403
00404 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00405
00406
00407 if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
00408
00409 fr = ast_frdup(inf);
00410
00411
00412 fr = ast_dsp_process(NULL, dsp, fr);
00413 if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
00414 ast_debug(1, "Fax tone detected. Requesting T38\n");
00415 t38control = AST_T38_REQUEST_NEGOTIATE;
00416 ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
00417 detect_tone = 0;
00418 }
00419
00420 ast_frfree(fr);
00421 }
00422
00423
00424
00425
00426
00427 if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
00428
00429 if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
00430
00431 ast_log(LOG_WARNING, "fax_rx returned error\n");
00432 res = -1;
00433 break;
00434 }
00435
00436
00437 if (last_state != t30state->state) {
00438 state_change = ast_tvnow();
00439 last_state = t30state->state;
00440 }
00441 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
00442 inf->datalen == sizeof(enum ast_control_t38)) {
00443 t38control =*((enum ast_control_t38 *) inf->data.ptr);
00444 if (t38control == AST_T38_NEGOTIATED) {
00445
00446 ast_debug(1, "T38 negotiated, finishing audio loop\n");
00447 res = 1;
00448 break;
00449 }
00450 }
00451
00452 ast_frfree(inf);
00453 inf = NULL;
00454
00455
00456 now = ast_tvnow();
00457 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00458 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00459 res = -1;
00460 break;
00461 }
00462 }
00463
00464 ast_debug(1, "Loop finished, res=%d\n", res);
00465
00466 if (inf)
00467 ast_frfree(inf);
00468
00469 if (dsp)
00470 ast_dsp_free(dsp);
00471
00472 ast_deactivate_generator(s->chan);
00473
00474
00475
00476
00477 if (res > 0) {
00478 t30_set_phase_e_handler(t30state, NULL, NULL);
00479 }
00480
00481 t30_terminate(t30state);
00482 fax_release(&fax);
00483
00484 done:
00485 if (original_write_fmt != AST_FORMAT_SLINEAR) {
00486 if (ast_set_write_format(s->chan, original_write_fmt) < 0)
00487 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
00488 }
00489
00490 if (original_read_fmt != AST_FORMAT_SLINEAR) {
00491 if (ast_set_read_format(s->chan, original_read_fmt) < 0)
00492 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
00493 }
00494
00495 return res;
00496
00497 }
00498
00499 static int transmit_t38(fax_session *s)
00500 {
00501 int res = 0;
00502 t38_terminal_state_t t38;
00503 struct ast_frame *inf = NULL;
00504 int last_state = 0;
00505 struct timeval now, start, state_change, last_frame;
00506 enum ast_control_t38 t38control;
00507
00508 t30_state_t *t30state;
00509 t38_core_state_t *t38state;
00510
00511 #if SPANDSP_RELEASE_DATE >= 20081012
00512
00513 t30state = &t38.t30;
00514 t38state = &t38.t38_fe.t38;
00515 #else
00516
00517 t30state = &t38.t30_state;
00518 t38state = &t38.t38;
00519 #endif
00520
00521
00522 memset(&t38, 0, sizeof(t38));
00523 if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
00524 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
00525 return -1;
00526 }
00527
00528
00529 set_logging(&t38.logging);
00530 set_logging(&t30state->logging);
00531 set_logging(&t38state->logging);
00532
00533
00534 set_local_info(t30state, s);
00535 set_file(t30state, s);
00536 set_ecm(t30state, TRUE);
00537
00538 t30_set_phase_e_handler(t30state, phase_e_handler, s);
00539
00540 now = start = state_change = ast_tvnow();
00541
00542 while (!s->finished) {
00543
00544 res = ast_waitfor(s->chan, 20);
00545 if (res < 0)
00546 break;
00547 else if (res > 0)
00548 res = 0;
00549
00550 last_frame = now;
00551 now = ast_tvnow();
00552 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
00553
00554 inf = ast_read(s->chan);
00555 if (inf == NULL) {
00556 ast_debug(1, "Channel hangup\n");
00557 res = -1;
00558 break;
00559 }
00560
00561 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00562
00563 if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
00564 t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
00565
00566
00567 if (last_state != t30state->state) {
00568 state_change = ast_tvnow();
00569 last_state = t30state->state;
00570 }
00571 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
00572 inf->datalen == sizeof(enum ast_control_t38)) {
00573
00574 t38control = *((enum ast_control_t38 *) inf->data.ptr);
00575
00576 if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
00577 ast_debug(1, "T38 down, terminating\n");
00578 res = -1;
00579 break;
00580 }
00581 }
00582
00583 ast_frfree(inf);
00584 inf = NULL;
00585
00586
00587 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00588 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00589 res = -1;
00590 break;
00591 }
00592 }
00593
00594 ast_debug(1, "Loop finished, res=%d\n", res);
00595
00596 if (inf)
00597 ast_frfree(inf);
00598
00599 t30_terminate(t30state);
00600 t38_terminal_release(&t38);
00601
00602 return res;
00603 }
00604
00605 static int transmit(fax_session *s)
00606 {
00607 int res = 0;
00608
00609
00610
00611 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
00612 pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
00613
00614 pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
00615 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
00616 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
00617 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
00618 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
00619
00620 if (s->chan->_state != AST_STATE_UP) {
00621
00622
00623 res = ast_answer(s->chan);
00624 if (res) {
00625 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
00626 return res;
00627 }
00628 }
00629
00630 s->t38state = ast_channel_get_t38_state(s->chan);
00631 if (s->t38state != T38_STATE_NEGOTIATED) {
00632
00633 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio");
00634 res = transmit_audio(s);
00635 if (res > 0) {
00636
00637 s->t38state = ast_channel_get_t38_state(s->chan);
00638 if (s->t38state != T38_STATE_NEGOTIATED) {
00639 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
00640 }
00641 }
00642 }
00643
00644 if (s->t38state == T38_STATE_NEGOTIATED) {
00645 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38");
00646 res = transmit_t38(s);
00647 }
00648
00649 if (res) {
00650 ast_log(LOG_WARNING, "Transmission error\n");
00651 res = -1;
00652 } else if (s->finished < 0) {
00653 ast_log(LOG_WARNING, "Transmission failed\n");
00654 } else if (s->finished > 0) {
00655 ast_debug(1, "Transmission finished Ok\n");
00656 }
00657
00658 return res;
00659 }
00660
00661
00662
00663 static int sndfax_exec(struct ast_channel *chan, void *data)
00664 {
00665 int res = 0;
00666 char *parse;
00667 fax_session session;
00668
00669 AST_DECLARE_APP_ARGS(args,
00670 AST_APP_ARG(file_name);
00671 AST_APP_ARG(options);
00672 );
00673
00674 if (chan == NULL) {
00675 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00676 return -1;
00677 }
00678
00679
00680 if (ast_strlen_zero(data)) {
00681
00682 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
00683 return -1;
00684 }
00685
00686 parse = ast_strdupa(data);
00687 AST_STANDARD_APP_ARGS(args, parse);
00688
00689 session.caller_mode = TRUE;
00690
00691 if (args.options) {
00692 if (strchr(args.options, 'a'))
00693 session.caller_mode = FALSE;
00694 }
00695
00696
00697 session.direction = 1;
00698 session.file_name = args.file_name;
00699 session.chan = chan;
00700 session.finished = 0;
00701
00702 res = transmit(&session);
00703
00704 return res;
00705 }
00706
00707 static int rcvfax_exec(struct ast_channel *chan, void *data)
00708 {
00709 int res = 0;
00710 char *parse;
00711 fax_session session;
00712
00713 AST_DECLARE_APP_ARGS(args,
00714 AST_APP_ARG(file_name);
00715 AST_APP_ARG(options);
00716 );
00717
00718 if (chan == NULL) {
00719 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00720 return -1;
00721 }
00722
00723
00724 if (ast_strlen_zero(data)) {
00725
00726 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
00727 return -1;
00728 }
00729
00730 parse = ast_strdupa(data);
00731 AST_STANDARD_APP_ARGS(args, parse);
00732
00733 session.caller_mode = FALSE;
00734
00735 if (args.options) {
00736 if (strchr(args.options, 'c'))
00737 session.caller_mode = TRUE;
00738 }
00739
00740
00741 session.direction = 0;
00742 session.file_name = args.file_name;
00743 session.chan = chan;
00744 session.finished = 0;
00745
00746 res = transmit(&session);
00747
00748 return res;
00749 }
00750
00751 static int unload_module(void)
00752 {
00753 int res;
00754
00755 res = ast_unregister_application(app_sndfax_name);
00756 res |= ast_unregister_application(app_rcvfax_name);
00757
00758 return res;
00759 }
00760
00761 static int load_module(void)
00762 {
00763 int res ;
00764
00765 res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
00766 res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
00767
00768
00769 span_set_message_handler(NULL);
00770
00771 return res;
00772 }
00773
00774
00775 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
00776 .load = load_module,
00777 .unload = unload_module,
00778 );
00779
00780