]>
Commit | Line | Data |
---|---|---|
d7e66fb6 | 1 | /* |
b568f055 CM |
2 | * Application to send a TIFF file as a FAX |
3 | * based on app_txfax.c from: Copyright (C) 2003, Steve Underwood <steveu@coppice.org> | |
4 | * PATCHED BY (C) 20007 by Antonio Gallo <agx@linux.it> | |
5 | * - added ECM support | |
6 | * - added more env variables | |
7 | * - added logging to external file | |
d7e66fb6 | 8 | */ |
b568f055 CM |
9 | |
10 | /*** MODULEINFO | |
11 | Depends: libspandsp | |
12 | Desciption: Send a FAX file | |
13 | DisplayName: TxFAX | |
14 | ***/ | |
d7e66fb6 | 15 | |
b568f055 CM |
16 | #include "asterisk.h" |
17 | ||
18 | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | |
19 | ||
d7e66fb6 | 20 | #include <string.h> |
21 | #include <stdlib.h> | |
22 | #include <stdio.h> | |
23 | #include <inttypes.h> | |
24 | #include <pthread.h> | |
25 | #include <errno.h> | |
26 | #include <tiffio.h> | |
27 | ||
28 | #include <spandsp.h> | |
b568f055 | 29 | #include <spandsp/version.h> |
d7e66fb6 | 30 | |
31 | #include "asterisk/lock.h" | |
32 | #include "asterisk/file.h" | |
33 | #include "asterisk/logger.h" | |
34 | #include "asterisk/channel.h" | |
35 | #include "asterisk/pbx.h" | |
36 | #include "asterisk/module.h" | |
b568f055 | 37 | #include "asterisk/manager.h" |
d7e66fb6 | 38 | |
b568f055 CM |
39 | #ifndef AST_MODULE |
40 | #define AST_MODULE "app_txfax" | |
41 | #endif | |
d7e66fb6 | 42 | |
43 | static char *app = "TxFAX"; | |
44 | ||
45 | static char *synopsis = "Send a FAX file"; | |
46 | ||
47 | static char *descrip = | |
b568f055 CM |
48 | " TxFAX(filename[|caller][|debug][|ecm]): Send a given TIFF file to the channel as a FAX.\n" |
49 | "The \"caller\" option makes the application behave as a calling machine,\n" | |
50 | "rather than the answering machine. The default behaviour is to behave as\n" | |
51 | "an answering machine.\n" | |
52 | "The \"ecm\" option enables ECM.\n" | |
53 | "Uses LOCALSTATIONID to identify itself to the remote end.\n" | |
54 | " LOCALHEADERINFO to generate a header line on each page.\n" | |
55 | "Sets REMOTESTATIONID to the receiver CSID.\n" | |
56 | " FAXPAGES to the number of pages sent.\n" | |
57 | " FAXBITRATE to the transmition rate.\n" | |
58 | " FAXRESOLUTION to the resolution.\n" | |
59 | " PHASEESTATUS to the phase E result status.\n" | |
60 | " PHASEESTRING to the phase E result string.\n" | |
61 | "Returns -1 when the user hangs up, or if the file does not exist.\n" | |
62 | "Returns 0 otherwise.\n"; | |
d7e66fb6 | 63 | |
b568f055 | 64 | #define MAX_BLOCK_SIZE 240 |
d7e66fb6 | 65 | |
b568f055 | 66 | static FILE *txfax_logfile = NULL; |
d7e66fb6 | 67 | |
b568f055 CM |
68 | static void file_log(const char *msg) |
69 | { | |
70 | if (msg==NULL) | |
71 | return; | |
72 | if (txfax_logfile==NULL) | |
73 | return; | |
74 | fprintf(txfax_logfile, msg); | |
75 | } | |
d7e66fb6 | 76 | |
77 | static void span_message(int level, const char *msg) | |
78 | { | |
b568f055 CM |
79 | if (msg==NULL) return; |
80 | int ast_level; | |
81 | if (level == SPAN_LOG_ERROR) | |
82 | ast_level = __LOG_ERROR; | |
83 | else if (level == SPAN_LOG_WARNING) | |
84 | ast_level = __LOG_WARNING; | |
85 | else | |
86 | ast_level = __LOG_DEBUG; | |
87 | ast_log(ast_level, _A_, "%s", msg); | |
88 | file_log(msg); | |
d7e66fb6 | 89 | } |
90 | /*- End of function --------------------------------------------------------*/ | |
91 | ||
b568f055 CM |
92 | typedef struct { |
93 | struct ast_channel *chan; | |
94 | fax_state_t fax; | |
95 | volatile int finished; | |
96 | } fax_session; | |
97 | ||
98 | static void phase_b_handler(t30_state_t *s, void *user_data, int result) | |
d7e66fb6 | 99 | { |
b568f055 CM |
100 | if (txfax_logfile!=NULL) { |
101 | fprintf( txfax_logfile, "[phase_b_handler] mark\n" ); | |
102 | fflush(txfax_logfile); | |
103 | } | |
d7e66fb6 | 104 | } |
d7e66fb6 | 105 | |
106 | static void phase_e_handler(t30_state_t *s, void *user_data, int result) | |
107 | { | |
b568f055 CM |
108 | struct ast_channel *chan; |
109 | char local_ident[21]; | |
110 | char far_ident[21]; | |
111 | char buf[128]; | |
112 | t30_stats_t t; | |
d7e66fb6 | 113 | |
b568f055 CM |
114 | fax_session *fax = (fax_session *) user_data; |
115 | chan = fax->chan; | |
116 | t30_get_transfer_statistics(s, &t); | |
d7e66fb6 | 117 | |
b568f055 CM |
118 | t30_get_local_ident(s, local_ident); |
119 | t30_get_far_ident(s, far_ident); | |
120 | pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident); | |
121 | snprintf(buf, sizeof(buf), "%d", t.pages_transferred); | |
122 | pbx_builtin_setvar_helper(chan, "FAXPAGES", buf); | |
123 | snprintf(buf, sizeof(buf), "%d", t.y_resolution); | |
124 | pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf); | |
125 | snprintf(buf, sizeof(buf), "%d", t.bit_rate); | |
126 | pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf); | |
127 | snprintf(buf, sizeof(buf), "%d", result); | |
128 | pbx_builtin_setvar_helper(chan, "PHASEESTATUS", buf); | |
129 | snprintf(buf, sizeof(buf), "%s", t30_completion_code_to_str(result)); | |
130 | pbx_builtin_setvar_helper(chan, "PHASEESTRING", buf); | |
131 | ||
132 | // This is to tell asterisk later that the fax has finished (with or without error) | |
133 | fax->finished = 1; | |
134 | ||
135 | ast_log(LOG_DEBUG, "==============================================================================\n"); | |
136 | if (result == T30_ERR_OK) | |
137 | { | |
138 | ast_log(LOG_DEBUG, "Fax successfully sent.\n"); | |
139 | ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident); | |
140 | ast_log(LOG_DEBUG, "Local station id: %s\n", local_ident); | |
141 | ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred); | |
142 | ast_log(LOG_DEBUG, "Image resolution: %i x %i\n", t.x_resolution, t.y_resolution); | |
143 | ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate); | |
144 | manager_event(EVENT_FLAG_CALL, | |
145 | "FaxSent", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n", | |
146 | chan->name, | |
147 | chan->exten, | |
148 | (chan->cid.cid_num) ? chan->cid.cid_num : "", | |
149 | far_ident, | |
150 | local_ident, | |
151 | t.pages_transferred, | |
152 | t.y_resolution, | |
153 | t.bit_rate, | |
154 | s->rx_file); | |
155 | if (txfax_logfile!=NULL) { | |
156 | fprintf( txfax_logfile, "\n[FAX OK] Remote: %s Local: %s Pages: %i Speed: %i\n\n", | |
157 | far_ident, local_ident, t.pages_transferred, t.bit_rate | |
158 | ); | |
159 | fflush(txfax_logfile); | |
160 | } | |
161 | } | |
162 | else | |
163 | { | |
164 | ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result)); | |
165 | if (txfax_logfile!=NULL) { | |
166 | fprintf( txfax_logfile, "\n[FAX ERROR] code: %d %s\n\n", result, t30_completion_code_to_str(result) ); | |
167 | fflush(txfax_logfile); | |
168 | } | |
169 | } | |
170 | ast_log(LOG_DEBUG, "==============================================================================\n"); | |
d7e66fb6 | 171 | } |
172 | /*- End of function --------------------------------------------------------*/ | |
173 | ||
b568f055 | 174 | static void phase_d_handler(t30_state_t *s, void *user_data, int result) |
d7e66fb6 | 175 | { |
b568f055 CM |
176 | // struct ast_channel *chan; |
177 | t30_stats_t t; | |
178 | ||
179 | // chan = (struct ast_channel *) user_data; | |
180 | if (result) | |
181 | { | |
182 | t30_get_transfer_statistics(s, &t); | |
183 | ast_log(LOG_DEBUG, "[ TXFAX ]=====================================================================\n"); | |
184 | ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred); | |
185 | ast_log(LOG_DEBUG, "Image size: %i x %i\n", t.width, t.length); | |
186 | ast_log(LOG_DEBUG, "Image resolution %i x %i\n", t.x_resolution, t.y_resolution); | |
187 | ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate); | |
188 | ast_log(LOG_DEBUG, "Bad rows %i\n", t.bad_rows); | |
189 | ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run); | |
190 | ast_log(LOG_DEBUG, "Compression type %s\n", t4_encoding_to_str(t.encoding)); | |
191 | ast_log(LOG_DEBUG, "Image size (bytes) %i\n", t.image_size); | |
192 | ast_log(LOG_DEBUG, "==============================================================================\n"); | |
193 | if (txfax_logfile!=NULL) { | |
194 | fprintf( txfax_logfile, "\n[phase_d_handler] Page: %i at %i\n\n", t.pages_transferred, t.bit_rate ); | |
195 | fflush(txfax_logfile); | |
196 | } | |
197 | } | |
d7e66fb6 | 198 | } |
199 | /*- End of function --------------------------------------------------------*/ | |
200 | ||
b568f055 | 201 | static int txfax_exec(struct ast_channel *chan, void *data) |
d7e66fb6 | 202 | { |
b568f055 CM |
203 | int res = 0; |
204 | char source_file[256]; | |
205 | int samples; | |
206 | char *s; | |
207 | char *t; | |
208 | char *v; | |
209 | const char *x; | |
210 | int option; | |
211 | int len; | |
212 | fax_state_t fax; | |
213 | struct ast_frame *inf = NULL; | |
214 | struct ast_frame outf; | |
215 | int calling_party; | |
216 | int verbose; | |
217 | int ecm = FALSE; | |
218 | ||
219 | struct ast_module_user *u; | |
220 | ||
221 | int original_read_fmt; | |
222 | int original_write_fmt; | |
223 | ||
224 | fax_session session; | |
225 | session.chan = chan; | |
226 | session.finished = 0; | |
227 | ||
228 | /* Basic initial checkings */ | |
229 | ||
230 | if (chan == NULL) { | |
231 | ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n"); | |
232 | file_log("ERROR: Fax receive channel is NULL. Giving up.\n"); | |
233 | return -1; | |
234 | } | |
235 | ||
236 | span_set_message_handler(span_message); | |
237 | /* make sure they are initialized to zero */ | |
238 | memset( &fax, 0, sizeof(fax)); | |
239 | ||
240 | /* Resetting channel variables related to T38 */ | |
241 | pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", ""); | |
242 | pbx_builtin_setvar_helper(chan, "FAXPAGES", ""); | |
243 | pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", ""); | |
244 | pbx_builtin_setvar_helper(chan, "FAXBITRATE", ""); | |
245 | pbx_builtin_setvar_helper(chan, "PHASEESTATUS", ""); | |
246 | pbx_builtin_setvar_helper(chan, "PHASEESTRING", ""); | |
247 | ||
248 | /* Parsig parameters */ | |
249 | ||
250 | /* The next few lines of code parse out the filename and header from the input string */ | |
251 | if (data == NULL) | |
252 | { | |
253 | /* No data implies no filename or anything is present */ | |
254 | ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n"); | |
255 | file_log("ERROR: Txfax requires an argument (filename)\n"); | |
256 | return -1; | |
257 | } | |
258 | ||
259 | calling_party = FALSE; | |
260 | verbose = FALSE; | |
261 | source_file[0] = '\0'; | |
262 | ||
263 | char tbuf[256]; | |
264 | for (option = 0, v = s = data; v; option++, s++) { | |
265 | t = s; | |
266 | v = strchr(s, '|'); | |
267 | s = (v) ? v : s + strlen(s); | |
268 | strncpy((char *) tbuf, t, s - t); | |
269 | tbuf[s - t] = '\0'; | |
270 | if (option == 0) { | |
271 | /* The first option is always the file name */ | |
272 | len = s - t; | |
273 | if (len > 255) | |
274 | len = 255; | |
275 | strncpy(source_file, t, len); | |
276 | source_file[len] = '\0'; | |
277 | } else if (strncmp("caller", t, s - t) == 0) { | |
278 | calling_party = TRUE; | |
279 | } else if (strncmp("debug", t, s - t) == 0) { | |
280 | verbose = TRUE; | |
281 | } else if (strncmp("ecm", t, s - t) == 0) { | |
282 | ecm = TRUE; | |
283 | } | |
284 | } | |
285 | ||
286 | /* Done parsing */ | |
287 | ||
288 | u = ast_module_user_add(chan); | |
289 | ||
290 | if (chan->_state != AST_STATE_UP) | |
291 | { | |
292 | /* Shouldn't need this, but checking to see if channel is already answered | |
293 | * Theoretically asterisk should already have answered before running the app */ | |
294 | res = ast_answer(chan); | |
295 | /* NO NEED TO WARN ANYMORE | |
296 | if (!res) | |
297 | { | |
298 | ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); | |
299 | file_log("Could not answer channel\n" ); | |
300 | } | |
301 | */ | |
302 | } | |
303 | ||
304 | /* Setting read and write formats */ | |
305 | ||
306 | original_read_fmt = chan->readformat; | |
307 | if (original_read_fmt != AST_FORMAT_SLINEAR) | |
308 | { | |
309 | res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); | |
310 | if (res < 0) | |
311 | { | |
312 | ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); | |
313 | file_log("ERROR: Unable to set to linear read mode, giving up\n"); | |
314 | ast_module_user_remove(u); | |
315 | return -1; | |
316 | } | |
317 | } | |
318 | ||
319 | original_write_fmt = chan->writeformat; | |
320 | if (original_write_fmt != AST_FORMAT_SLINEAR) | |
321 | { | |
322 | res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); | |
323 | if (res < 0) | |
324 | { | |
325 | ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); | |
326 | file_log("Unable to set to linear write mode, giving up\n"); | |
327 | res = ast_set_read_format(chan, original_read_fmt); | |
328 | if (res) | |
329 | ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); | |
330 | ast_module_user_remove(u); | |
331 | return -1; | |
332 | } | |
333 | } | |
334 | ||
335 | /* Remove any app level gain adjustments and disable echo cancel. */ | |
336 | signed char sc; | |
337 | sc = 0; | |
338 | ast_channel_setoption(chan, AST_OPTION_RXGAIN, &sc, sizeof(sc), 0); | |
339 | ast_channel_setoption(chan, AST_OPTION_TXGAIN, &sc, sizeof(sc), 0); | |
340 | ast_channel_setoption(chan, AST_OPTION_ECHOCAN, &sc, sizeof(sc), 0); | |
341 | ||
342 | /* This is the main loop */ | |
343 | ||
344 | uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET]; | |
345 | uint8_t *buf = __buf + AST_FRIENDLY_OFFSET; | |
346 | ||
347 | memset(&fax, 0, sizeof(fax)); | |
348 | ||
349 | if (fax_init(&fax, calling_party) == NULL) | |
350 | { | |
351 | ast_log(LOG_WARNING, "Unable to start FAX\n"); | |
352 | file_log("Unable to set to start fax_init\n"); | |
353 | ast_module_user_remove(u); | |
354 | return -1; | |
355 | } | |
356 | fax_set_transmit_on_idle(&fax, TRUE); | |
357 | span_log_set_message_handler(&fax.logging, span_message); | |
358 | span_log_set_message_handler(&fax.t30_state.logging, span_message); | |
359 | if (verbose) | |
360 | { | |
361 | span_log_set_level(&fax.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |
362 | span_log_set_level(&fax.t30_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |
363 | } | |
364 | x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"); | |
365 | if (x && x[0]) | |
366 | t30_set_local_ident(&fax.t30_state, x); | |
367 | x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"); | |
368 | if (x && x[0]) | |
369 | t30_set_header_info(&fax.t30_state, x); | |
370 | t30_set_tx_file(&fax.t30_state, source_file, -1, -1); | |
371 | t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan); | |
372 | t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan); | |
373 | t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, &session); | |
374 | ||
375 | x = pbx_builtin_getvar_helper(chan, "FAX_DISABLE_V17"); | |
376 | if (x && x[0]) | |
377 | t30_set_supported_modems(&(fax.t30_state), T30_SUPPORT_V29 | T30_SUPPORT_V27TER); | |
378 | else | |
379 | t30_set_supported_modems(&(fax.t30_state), T30_SUPPORT_V29 | T30_SUPPORT_V27TER | T30_SUPPORT_V17 ); | |
380 | ||
381 | /* Support for different image sizes && resolutions*/ | |
382 | t30_set_supported_image_sizes(&fax.t30_state, T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH | |
383 | | T30_SUPPORT_215MM_WIDTH | T30_SUPPORT_255MM_WIDTH | T30_SUPPORT_303MM_WIDTH); | |
384 | t30_set_supported_resolutions(&fax.t30_state, T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION | |
385 | | T30_SUPPORT_R8_RESOLUTION | T30_SUPPORT_R16_RESOLUTION); | |
386 | if (ecm) { | |
387 | t30_set_ecm_capability(&(fax.t30_state), TRUE); | |
388 | t30_set_supported_compressions(&(fax.t30_state), T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); | |
389 | ast_log(LOG_DEBUG, "Enabling ECM mode for app_txfax\n" ); | |
390 | file_log("Enabling ECM mode for app_rxfax\n" ); | |
391 | } | |
392 | ||
393 | ||
394 | /* This is the main loop */ | |
395 | ||
396 | res = 0; | |
397 | while ( (!session.finished) && chan ) | |
398 | { | |
399 | if (ast_check_hangup(chan)) { | |
400 | ast_log(LOG_WARNING, "TXFAX: Channel has been hanged at fax.\n"); | |
401 | file_log("INFO: Channel has been hanged at fax.\n"); | |
402 | res = 0; | |
403 | break; | |
404 | } | |
405 | ||
406 | if ((res = ast_waitfor(chan, 20)) < 0) { | |
407 | ast_log(LOG_WARNING, "TXFAX: ast_waitfor returned less then 0.\n"); | |
408 | file_log("WARNING: Channel ast_waitfor < 0.\n"); | |
409 | res = 0; | |
410 | break; | |
411 | } | |
412 | ||
413 | /*if ((fax.current_rx_type == T30_MODEM_DONE) || (fax.current_tx_type == T30_MODEM_DONE)) { | |
414 | ast_log(LOG_WARNING, "Channel T30 DONE < 0.\n"); | |
415 | file_log("Channel T30 DONE.\n"); | |
416 | res = 0; | |
417 | break; | |
418 | }*/ | |
419 | ||
420 | inf = ast_read(chan); | |
421 | if (inf == NULL) | |
422 | { | |
423 | //ast_log(LOG_WARNING, "TXFAX: transmission done with ast_read(chan) == NULL\n"); | |
424 | ast_log(LOG_WARNING, "Channel INF is NULL.\n"); | |
425 | file_log("DEBUG: Channel INF is NULL.\n"); | |
426 | ||
427 | // While trasmiitting i got: Received a DCN from remote after sending a page | |
428 | // at last page | |
429 | continue; | |
430 | #ifdef AGX_DEBUGGING | |
431 | res = 0; | |
432 | break; | |
433 | #endif | |
434 | } | |
435 | ||
436 | /* We got a frame */ | |
437 | //if (inf->frametype == AST_FRAME_VOICE) { | |
438 | /* Check the frame type. Format also must be checked because there is a chance | |
439 | that a frame in old format was already queued before we set chanel format | |
440 | to slinear so it will still be received by ast_read */ | |
441 | if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) { | |
442 | if (fax_rx(&fax, inf->data, inf->samples)) { | |
443 | ast_log(LOG_WARNING, "TXFAX: fax_rx returned error\n"); | |
444 | res = -1; | |
445 | break; | |
446 | } | |
447 | ||
448 | samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; | |
449 | len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples); | |
450 | if (len>0) { | |
451 | /*if (len <= 0) { | |
452 | ast_log(LOG_WARNING, "len <=0 using samples.\n"); | |
453 | file_log("len <= 0 using samples.\n"); | |
454 | len = samples; | |
455 | }*/ | |
456 | memset(&outf, 0, sizeof(outf)); | |
457 | outf.frametype = AST_FRAME_VOICE; | |
458 | outf.subclass = AST_FORMAT_SLINEAR; | |
459 | outf.datalen = len*sizeof(int16_t); | |
460 | outf.samples = len; | |
461 | outf.data = &buf[AST_FRIENDLY_OFFSET]; | |
462 | outf.offset = AST_FRIENDLY_OFFSET; | |
463 | outf.src = "TxFAX"; | |
464 | /*if (len <= 0) { | |
465 | memset(&buf[AST_FRIENDLY_OFFSET], 0, outf.datalen); | |
466 | }*/ | |
467 | if (ast_write(chan, &outf) < 0) | |
468 | { | |
469 | ast_log(LOG_WARNING, "TXFAX: Unable to write frame to channel; %s\n", strerror(errno)); | |
470 | file_log("FATAL ERROR: Unable to write frame to channel\n"); | |
471 | res = -1; | |
472 | break; | |
473 | } | |
474 | } | |
475 | } | |
476 | ast_frfree(inf); | |
477 | inf = NULL; | |
478 | /* TODO put a Watchdog here */ | |
479 | } | |
480 | ||
481 | if (inf != NULL) | |
482 | { | |
483 | ast_frfree(inf); | |
484 | inf = NULL; | |
485 | } | |
486 | ||
487 | t30_terminate(&fax.t30_state); | |
488 | fax_release(&fax); | |
489 | if (session.finished > 0) { | |
490 | ast_log(LOG_WARNING, "Fax Transmission complete, check return code\n"); | |
491 | res = 0; | |
492 | } else { | |
493 | ast_log(LOG_WARNING, "Fax Transmission INCOMPLETE, check error code\n"); | |
494 | res = -1; | |
495 | } | |
496 | if (res!=0) { | |
497 | ast_log(LOG_WARNING, "Transmission RES error\n"); | |
498 | } | |
499 | ||
500 | /* Restoring initial channel formats. */ | |
501 | ||
502 | if (original_read_fmt != AST_FORMAT_SLINEAR) | |
503 | { | |
504 | res = ast_set_read_format(chan, original_read_fmt); | |
505 | if (res) | |
506 | ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); | |
507 | } | |
508 | if (original_write_fmt != AST_FORMAT_SLINEAR) | |
509 | { | |
510 | res = ast_set_write_format(chan, original_write_fmt); | |
511 | if (res) | |
512 | ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name); | |
513 | } | |
514 | ast_module_user_remove(u); | |
515 | return res; | |
d7e66fb6 | 516 | } |
517 | /*- End of function --------------------------------------------------------*/ | |
518 | ||
b568f055 | 519 | static int unload_module(void) |
d7e66fb6 | 520 | { |
b568f055 CM |
521 | int res; |
522 | ast_module_user_hangup_all(); | |
523 | res = ast_unregister_application(app); | |
524 | if (txfax_logfile) { | |
525 | fclose(txfax_logfile); | |
526 | txfax_logfile = NULL; | |
527 | } | |
528 | return res; | |
d7e66fb6 | 529 | } |
530 | /*- End of function --------------------------------------------------------*/ | |
531 | ||
b568f055 | 532 | static int load_module(void) |
d7e66fb6 | 533 | { |
b568f055 CM |
534 | ast_log(LOG_NOTICE, "TxFax using spandsp %i %i\n", SPANDSP_RELEASE_DATE, SPANDSP_RELEASE_TIME ); |
535 | txfax_logfile = fopen("/var/log/txfax.log", "w+" ); | |
536 | if (txfax_logfile) | |
537 | ast_log(LOG_WARNING, "TxFax output also available in /var/log/txfax.log\n" ); | |
538 | return ast_register_application(app, txfax_exec, synopsis, descrip); | |
d7e66fb6 | 539 | } |
540 | /*- End of function --------------------------------------------------------*/ | |
b568f055 CM |
541 | |
542 | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Transmit Application"); | |
543 | ||
d7e66fb6 | 544 | /*- End of file ------------------------------------------------------------*/ |