]> git.pld-linux.org Git - packages/asterisk.git/blame - app_rxfax.c
- build with system mlxm
[packages/asterisk.git] / app_rxfax.c
CommitLineData
d7e66fb6 1/*
2 * Asterisk -- A telephony toolkit for Linux.
3 *
4 * Trivial application to receive a TIFF FAX file
5 *
6 * Copyright (C) 2003, Steve Underwood
7 *
8 * Steve Underwood <steveu@coppice.org>
9 *
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
12 */
13
14#include <string.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <inttypes.h>
18#include <pthread.h>
19#include <errno.h>
20#include <tiffio.h>
21
22#include <spandsp.h>
23
24#include "asterisk.h"
25
26ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
27
28#include "asterisk/lock.h"
29#include "asterisk/file.h"
30#include "asterisk/logger.h"
31#include "asterisk/channel.h"
32#include "asterisk/pbx.h"
33#include "asterisk/module.h"
34#include "asterisk/translate.h"
35#include "asterisk/dsp.h"
36#include "asterisk/manager.h"
37
38static char *tdesc = "Trivial FAX Receive Application";
39
40static char *app = "RxFAX";
41
42static char *synopsis = "Receive a FAX to a file";
43
44static char *descrip =
45" RxFAX(filename[|caller][|debug]): Receives a FAX from the channel into the\n"
46"given filename. If the file exists it will be overwritten. The file\n"
47"should be in TIFF/F format.\n"
48"The \"caller\" option makes the application behave as a calling machine,\n"
49"rather than the answering machine. The default behaviour is to behave as\n"
50"an answering machine.\n"
51"Uses LOCALSTATIONID to identify itself to the remote end.\n"
52" LOCALHEADERINFO to generate a header line on each page.\n"
53"Sets REMOTESTATIONID to the sender CSID.\n"
54" FAXPAGES to the number of pages received.\n"
55" FAXBITRATE to the transmition rate.\n"
56" FAXRESOLUTION to the resolution.\n"
57"Returns -1 when the user hangs up.\n"
58"Returns 0 otherwise.\n";
59
60STANDARD_LOCAL_USER;
61
62LOCAL_USER_DECL;
63
64#define MAX_BLOCK_SIZE 240
65
66static void span_message(int level, const char *msg)
67{
68 int ast_level;
69
70 if (level == SPAN_LOG_WARNING)
71 ast_level = __LOG_WARNING;
72 else if (level == SPAN_LOG_WARNING)
73 ast_level = __LOG_WARNING;
74 else
75 ast_level = __LOG_DEBUG;
76 ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
77}
78/*- End of function --------------------------------------------------------*/
79
80static void t30_flush(t30_state_t *s, int which)
81{
82 //TODO:
83}
84/*- End of function --------------------------------------------------------*/
85
86static void phase_e_handler(t30_state_t *s, void *user_data, int result)
87{
88 struct ast_channel *chan;
89 t30_stats_t t;
90 char local_ident[21];
91 char far_ident[21];
92 char buf[11];
93
94 chan = (struct ast_channel *) user_data;
95 if (result == T30_ERR_OK)
96 {
97 t30_get_transfer_statistics(s, &t);
98 t30_get_far_ident(s, far_ident);
99 t30_get_local_ident(s, local_ident);
100 ast_log(LOG_DEBUG, "==============================================================================\n");
101 ast_log(LOG_DEBUG, "Fax successfully received.\n");
102 ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident);
103 ast_log(LOG_DEBUG, "Local station id: %s\n", local_ident);
104 ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
105 ast_log(LOG_DEBUG, "Image resolution: %i x %i\n", t.column_resolution, t.row_resolution);
106 ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
107 ast_log(LOG_DEBUG, "==============================================================================\n");
108 manager_event(EVENT_FLAG_CALL,
109 "FaxReceived", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n",
110 chan->name,
111 chan->exten,
112 (chan->cid.cid_num) ? chan->cid.cid_num : "",
113 far_ident,
114 local_ident,
115 t.pages_transferred,
116 t.row_resolution,
117 t.bit_rate,
118 s->rx_file);
119 pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
120 snprintf(buf, sizeof(buf), "%i", t.pages_transferred);
121 pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
122 snprintf(buf, sizeof(buf), "%i", t.row_resolution);
123 pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf);
124 snprintf(buf, sizeof(buf), "%i", t.bit_rate);
125 pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf);
126 }
127 else
128 {
129 ast_log(LOG_DEBUG, "==============================================================================\n");
130 ast_log(LOG_DEBUG, "Fax receive not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
131 ast_log(LOG_DEBUG, "==============================================================================\n");
132 }
133}
134/*- End of function --------------------------------------------------------*/
135
136static void phase_d_handler(t30_state_t *s, void *user_data, int result)
137{
138 struct ast_channel *chan;
139 t30_stats_t t;
140
141 chan = (struct ast_channel *) user_data;
142 if (result)
143 {
144 t30_get_transfer_statistics(s, &t);
145 ast_log(LOG_DEBUG, "==============================================================================\n");
146 ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
147 ast_log(LOG_DEBUG, "Image size: %i x %i\n", t.columns, t.rows);
148 ast_log(LOG_DEBUG, "Image resolution %i x %i\n", t.column_resolution, t.row_resolution);
149 ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
150 ast_log(LOG_DEBUG, "Bad rows %i\n", t.bad_rows);
151 ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run);
152 ast_log(LOG_DEBUG, "Compression type %i\n", t.encoding);
153 ast_log(LOG_DEBUG, "Image size (bytes) %i\n", t.image_size);
154 ast_log(LOG_DEBUG, "==============================================================================\n");
155 }
156}
157/*- End of function --------------------------------------------------------*/
158
159static int rxfax_exec(struct ast_channel *chan, void *data)
160{
161 int res = 0;
162 char template_file[256];
163 char target_file[256];
164 char *s;
165 char *t;
166 char *v;
167 char *x;
168 int option;
169 int len;
170 int i;
171 t30_state_t fax;
172 int calling_party;
173 int verbose;
174 int samples;
175
176 struct localuser *u;
177 struct ast_frame *inf = NULL;
178 struct ast_frame outf;
179
180 int original_read_fmt;
181 int original_write_fmt;
182
183 uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
184 uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
185
186 if (chan == NULL)
187 {
188 ast_log(LOG_WARNING, "Fax receive channel is NULL. Giving up.\n");
189 return -1;
190 }
191
192 span_set_message_handler(span_message);
193
194 /* The next few lines of code parse out the filename and header from the input string */
195 if (data == NULL)
196 {
197 /* No data implies no filename or anything is present */
198 ast_log(LOG_WARNING, "Rxfax requires an argument (filename)\n");
199 return -1;
200 }
201
202 calling_party = FALSE;
203 verbose = FALSE;
204 target_file[0] = '\0';
205
206 for (option = 0, v = s = data; v; option++, s++)
207 {
208 t = s;
209 v = strchr(s, '|');
210 s = (v) ? v : s + strlen(s);
211 strncpy((char *) buf, t, s - t);
212 buf[s - t] = '\0';
213 if (option == 0)
214 {
215 /* The first option is always the file name */
216 len = s - t;
217 if (len > 255)
218 len = 255;
219 strncpy(target_file, t, len);
220 target_file[len] = '\0';
221 /* Allow the use of %d in the file name for a wild card of sorts, to
222 create a new file with the specified name scheme */
223 if ((x = strchr(target_file, '%')) && x[1] == 'd')
224 {
225 strcpy(template_file, target_file);
226 i = 0;
227 do
228 {
229 snprintf(target_file, 256, template_file, 1);
230 i++;
231 }
232 while (ast_fileexists(target_file, "", chan->language) != -1);
233 }
234 }
235 else if (strncmp("caller", t, s - t) == 0)
236 {
237 calling_party = TRUE;
238 }
239 else if (strncmp("debug", t, s - t) == 0)
240 {
241 verbose = TRUE;
242 }
243 }
244
245 /* Done parsing */
246
247 LOCAL_USER_ADD(u);
248
249 if (chan->_state != AST_STATE_UP)
250 {
251 /* Shouldn't need this, but checking to see if channel is already answered
252 * Theoretically asterisk should already have answered before running the app */
253 res = ast_answer(chan);
254 }
255
256 if (!res)
257 {
258 original_read_fmt = chan->readformat;
259 if (original_read_fmt != AST_FORMAT_SLINEAR)
260 {
261 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
262 if (res < 0)
263 {
264 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
265 return -1;
266 }
267 }
268 original_write_fmt = chan->writeformat;
269 if (original_write_fmt != AST_FORMAT_SLINEAR)
270 {
271 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
272 if (res < 0)
273 {
274 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
275 res = ast_set_read_format(chan, original_read_fmt);
276 if (res)
277 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
278 return -1;
279 }
280 }
281 fax_init(&fax, calling_party, NULL);
282 if (verbose)
283 fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
284 x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
285 if (x && x[0])
286 t30_set_local_ident(&fax, x);
287 x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
288 if (x && x[0])
289 t30_set_header_info(&fax, x);
290 t30_set_rx_file(&fax, target_file, -1);
291 //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
292 t30_set_phase_d_handler(&fax, phase_d_handler, chan);
293 t30_set_phase_e_handler(&fax, phase_e_handler, chan);
294 while (ast_waitfor(chan, -1) > -1)
295 {
296 inf = ast_read(chan);
297 if (inf == NULL)
298 {
299 res = -1;
300 break;
301 }
302 if (inf->frametype == AST_FRAME_VOICE)
303 {
304 if (fax_rx(&fax, inf->data, inf->samples))
305 break;
306 samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE;
307 len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
308 if (len)
309 {
310 memset(&outf, 0, sizeof(outf));
311 outf.frametype = AST_FRAME_VOICE;
312 outf.subclass = AST_FORMAT_SLINEAR;
313 outf.datalen = len*sizeof(int16_t);
314 outf.samples = len;
315 outf.data = &buf[AST_FRIENDLY_OFFSET];
316 outf.offset = AST_FRIENDLY_OFFSET;
317 outf.src = "RxFAX";
318 if (ast_write(chan, &outf) < 0)
319 {
320 ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
321 break;
322 }
323 }
324 }
325 ast_frfree(inf);
326 }
327 if (inf == NULL)
328 {
329 ast_log(LOG_DEBUG, "Got hangup\n");
330 res = -1;
331 }
332 if (original_read_fmt != AST_FORMAT_SLINEAR)
333 {
334 res = ast_set_read_format(chan, original_read_fmt);
335 if (res)
336 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
337 }
338 if (original_write_fmt != AST_FORMAT_SLINEAR)
339 {
340 res = ast_set_write_format(chan, original_write_fmt);
341 if (res)
342 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
343 }
344 fax_release(&fax);
345 }
346 else
347 {
348 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
349 }
350 LOCAL_USER_REMOVE(u);
351 return res;
352}
353/*- End of function --------------------------------------------------------*/
354
355int unload_module(void)
356{
357 STANDARD_HANGUP_LOCALUSERS;
358 return ast_unregister_application(app);
359}
360/*- End of function --------------------------------------------------------*/
361
362int load_module(void)
363{
364 return ast_register_application(app, rxfax_exec, synopsis, descrip);
365}
366
367char *description(void)
368{
369 return tdesc;
370}
371/*- End of function --------------------------------------------------------*/
372
373int usecount(void)
374{
375 int res;
376 STANDARD_USECOUNT(res);
377 return res;
378}
379/*- End of function --------------------------------------------------------*/
380
381char *key(void)
382{
383 return ASTERISK_GPL_KEY;
384}
385/*- End of function --------------------------------------------------------*/
386/*- End of file ------------------------------------------------------------*/
This page took 0.067534 seconds and 4 git commands to generate.