Sat Sep 16 05:47:40 2006

Asterisk developer's documentation


app_txfax.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Trivial application to send a TIFF file as a FAX
00005  * 
00006  * Copyright (C) 2003, Steve Underwood
00007  *
00008  * Steve Underwood <steveu@coppice.org>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013  
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include <stdio.h>
00017 #include <inttypes.h>
00018 #include <pthread.h>
00019 #include <errno.h>
00020 #include <tiffio.h>
00021 
00022 #include <spandsp.h>
00023 
00024 #include "asterisk.h"
00025 
00026 ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
00027 
00028 #include "asterisk/lock.h"
00029 #include "asterisk/file.h"
00030 #include "asterisk/logger.h"
00031 #include "asterisk/channel.h"
00032 #include "asterisk/pbx.h"
00033 #include "asterisk/module.h"
00034 #include "asterisk/translate.h"
00035 
00036 static char *tdesc = "Trivial FAX Transmit Application";
00037 
00038 static char *app = "TxFAX";
00039 
00040 static char *synopsis = "Send a FAX file";
00041 
00042 static char *descrip = 
00043 "  TxFAX(filename[|caller][|debug]):  Send a given TIFF file to the channel as a FAX.\n"
00044 "The \"caller\" option makes the application behave as a calling machine,\n"
00045 "rather than the answering machine. The default behaviour is to behave as\n"
00046 "an answering machine.\n"
00047 "Uses LOCALSTATIONID to identify itself to the remote end.\n"
00048 "     LOCALHEADERINFO to generate a header line on each page.\n"
00049 "Sets REMOTESTATIONID to the receiver CSID.\n"
00050 "Returns -1 when the user hangs up, or if the file does not exist.\n"
00051 "Returns 0 otherwise.\n";
00052 
00053 STANDARD_LOCAL_USER;
00054 
00055 LOCAL_USER_DECL;
00056 
00057 #define MAX_BLOCK_SIZE 240
00058 
00059 static void span_message(int level, const char *msg)
00060 {
00061     int ast_level;
00062     
00063     if (level == SPAN_LOG_WARNING)
00064         ast_level = __LOG_WARNING;
00065     else if (level == SPAN_LOG_WARNING)
00066         ast_level = __LOG_WARNING;
00067     else
00068         ast_level = __LOG_DEBUG;
00069     ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
00070 }
00071 /*- End of function --------------------------------------------------------*/
00072 
00073 static void t30_flush(t30_state_t *s, int which)
00074 {
00075     //TODO:
00076 }
00077 /*- End of function --------------------------------------------------------*/
00078 
00079 static void phase_e_handler(t30_state_t *s, void *user_data, int result)
00080 {
00081     struct ast_channel *chan;
00082     char far_ident[21];
00083     
00084     chan = (struct ast_channel *) user_data;
00085     if (result == T30_ERR_OK)
00086     {
00087         t30_get_far_ident(s, far_ident);
00088         pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
00089     }
00090     else
00091     {
00092         ast_log(LOG_DEBUG, "==============================================================================\n");
00093         ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
00094         ast_log(LOG_DEBUG, "==============================================================================\n");
00095     }
00096 }
00097 /*- End of function --------------------------------------------------------*/
00098 
00099 static int txfax_exec(struct ast_channel *chan, void *data)
00100 {
00101     int res = 0;
00102     char source_file[256];
00103     char *x;
00104     char *s;
00105     char *t;
00106     char *v;
00107     int option;
00108     int len;
00109     t30_state_t fax;
00110     int calling_party;
00111     int verbose;
00112     int samples;
00113     
00114     struct localuser *u;
00115     struct ast_frame *inf = NULL;
00116     struct ast_frame outf;
00117 
00118     int original_read_fmt;
00119     int original_write_fmt;
00120     
00121     uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
00122     uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
00123 
00124     if (chan == NULL)
00125     {
00126         ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
00127         return -1;
00128     }
00129 
00130     span_set_message_handler(span_message);
00131 
00132     /* The next few lines of code parse out the filename and header from the input string */
00133     if (data == NULL)
00134     {
00135         /* No data implies no filename or anything is present */
00136         ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
00137         return -1;
00138     }
00139     
00140     calling_party = FALSE;
00141     verbose = FALSE;
00142     source_file[0] = '\0'; 
00143 
00144     for (option = 0, v = s = data;  v;  option++, s++)
00145     {
00146         t = s;
00147         v = strchr(s, '|');
00148         s = (v)  ?  v  :  s + strlen(s);
00149         strncpy((char *) buf, t, s - t);
00150         buf[s - t] = '\0';
00151         if (option == 0)
00152         {
00153             /* The first option is always the file name */
00154             len = s - t;
00155             if (len > 255)
00156                 len = 255;
00157             strncpy(source_file, t, len);
00158             source_file[len] = '\0';
00159         }
00160         else if (strncmp("caller", t, s - t) == 0)
00161         {
00162             calling_party = TRUE;
00163         }
00164         else if (strncmp("debug", t, s - t) == 0)
00165         {
00166             verbose = TRUE;
00167         }
00168     }
00169 
00170     /* Done parsing */
00171 
00172     LOCAL_USER_ADD(u);
00173 
00174     if (chan->_state != AST_STATE_UP)
00175     {
00176         /* Shouldn't need this, but checking to see if channel is already answered
00177          * Theoretically asterisk should already have answered before running the app */
00178         res = ast_answer(chan);
00179     }
00180     
00181     if (!res)
00182     {
00183         original_read_fmt = chan->readformat;
00184         if (original_read_fmt != AST_FORMAT_SLINEAR)
00185         {
00186             res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00187             if (res < 0)
00188             {
00189                 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
00190                 return -1;
00191             }
00192         }
00193         original_write_fmt = chan->writeformat;
00194         if (original_write_fmt != AST_FORMAT_SLINEAR)
00195         {
00196             res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
00197             if (res < 0)
00198             {
00199                 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
00200                 res = ast_set_read_format(chan, original_read_fmt);
00201                 if (res)
00202                     ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
00203                 return -1;
00204             }
00205         }
00206         fax_init(&fax, calling_party, NULL);
00207         if (verbose)
00208        fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
00209 
00210         x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
00211         if (x  &&  x[0])
00212             t30_set_local_ident(&fax, x);
00213         x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
00214         if (x  &&  x[0])
00215             t30_set_header_info(&fax, x);
00216         t30_set_tx_file(&fax, source_file, -1, -1);
00217         //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
00218         //t30_set_phase_d_handler(&fax, phase_d_handler, chan);
00219         t30_set_phase_e_handler(&fax, phase_e_handler, chan);
00220         while (ast_waitfor(chan, -1) > -1)
00221         {
00222             inf = ast_read(chan);
00223             if (inf == NULL)
00224             {
00225                 res = -1;
00226                 break;
00227             }
00228             if (inf->frametype == AST_FRAME_VOICE)
00229             {
00230                 if (fax_rx(&fax, inf->data, inf->samples))
00231                     break;
00232                 samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
00233                 len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
00234                 if (len)
00235                 {
00236                     memset(&outf, 0, sizeof(outf));
00237                     outf.frametype = AST_FRAME_VOICE;
00238                     outf.subclass = AST_FORMAT_SLINEAR;
00239                     outf.datalen = len*sizeof(int16_t);
00240                     outf.samples = len;
00241                     outf.data = &buf[AST_FRIENDLY_OFFSET];
00242                     outf.offset = AST_FRIENDLY_OFFSET;
00243                     if (ast_write(chan, &outf) < 0)
00244                     {
00245                         ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
00246                         break;
00247                     }
00248                 }
00249             }
00250             ast_frfree(inf);
00251         }
00252         if (inf == NULL)
00253         {
00254             ast_log(LOG_DEBUG, "Got hangup\n");
00255             res = -1;
00256         }
00257         if (original_read_fmt != AST_FORMAT_SLINEAR)
00258         {
00259             res = ast_set_read_format(chan, original_read_fmt);
00260             if (res)
00261                 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
00262         }
00263         if (original_write_fmt != AST_FORMAT_SLINEAR)
00264         {
00265             res = ast_set_write_format(chan, original_write_fmt);
00266             if (res)
00267                 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
00268         }
00269         fax_release(&fax);
00270     }
00271     else
00272     {
00273         ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
00274     }
00275     LOCAL_USER_REMOVE(u);
00276     return res;
00277 }
00278 /*- End of function --------------------------------------------------------*/
00279 
00280 int unload_module(void)
00281 {
00282     STANDARD_HANGUP_LOCALUSERS;
00283     return ast_unregister_application(app);
00284 }
00285 /*- End of function --------------------------------------------------------*/
00286 
00287 int load_module(void)
00288 {
00289     return ast_register_application(app, txfax_exec, synopsis, descrip);
00290 }
00291 /*- End of function --------------------------------------------------------*/
00292 
00293 char *description(void)
00294 {
00295     return tdesc;
00296 }
00297 /*- End of function --------------------------------------------------------*/
00298 
00299 int usecount(void)
00300 {
00301     int res;
00302 
00303     STANDARD_USECOUNT(res);
00304     return res;
00305 }
00306 /*- End of function --------------------------------------------------------*/
00307 
00308 char *key(void)
00309 {
00310     return ASTERISK_GPL_KEY;
00311 }
00312 /*- End of function --------------------------------------------------------*/
00313 /*- End of file ------------------------------------------------------------*/

Generated on Sat Sep 16 05:47:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7