app_queue: Cleanup queue_ref / queue_unref routines.
[asterisk/asterisk.git] / apps / app_fax.c
index 3183a56..c5d0f51 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
  * Simple fax applications
- * 
+ *
  * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
  *
  * Code based on original implementation by Steve Underwood <steveu@coppice.org>
        <defaultenabled>no</defaultenabled>
        <depend>spandsp</depend>
        <conflict>res_fax</conflict>
-       <support_level>extended</support_level>
+       <support_level>deprecated</support_level>
+       <replacement>res_fax</replacement>
 ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -43,7 +42,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/dsp.h"
 #include "asterisk/module.h"
-#include "asterisk/manager.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
        <application name="SendFAX" language="en_US" module="app_fax">
@@ -100,12 +101,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                <para>Filename of TIFF file save incoming fax</para>
                        </parameter>
                        <parameter name="c" required="false">
-                               <para>Makes the application behave as the calling machine</para> 
+                               <para>Makes the application behave as the calling machine</para>
                                <para>(Default behavior is as answering machine)</para>
                        </parameter>
                </syntax>
                <description>
-                       <para>Receives a FAX from the channel into the given filename 
+                       <para>Receives a FAX from the channel into the given filename
                        overwriting the file if it already exists.</para>
                        <para>File created will be in TIFF format.</para>
 
@@ -202,6 +203,9 @@ static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uin
 
 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
 {
+       RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+       RAII_VAR(struct ast_json *, json_filenames, NULL, ast_json_unref);
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
        const char *local_ident;
        const char *far_ident;
        char buf[20];
@@ -251,32 +255,24 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
        ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
        ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
 
-       ast_manager_event(s->chan, EVENT_FLAG_CALL,
-               s->direction ? "FaxSent" : "FaxReceived",
-               "Channel: %s\r\n"
-               "Exten: %s\r\n"
-               "CallerID: %s\r\n"
-               "CallerIDName: %s\r\n"
-               "ConnectedLineNum: %s\r\n"
-               "ConnectedLineName: %s\r\n"
-               "RemoteStationID: %s\r\n"
-               "LocalStationID: %s\r\n"
-               "PagesTransferred: %d\r\n"
-               "Resolution: %d\r\n"
-               "TransferRate: %d\r\n"
-               "FileName: %s\r\n",
-               ast_channel_name(s->chan),
-               ast_channel_exten(s->chan),
-               S_COR(s->chan->caller.id.number.valid, s->chan->caller.id.number.str, ""),
-               S_COR(s->chan->caller.id.name.valid, s->chan->caller.id.name.str, ""),
-               S_COR(s->chan->connected.id.number.valid, s->chan->connected.id.number.str, ""),
-               S_COR(s->chan->connected.id.name.valid, s->chan->connected.id.name.str, ""),
-               far_ident,
-               local_ident,
-               pages_transferred,
-               stat.y_resolution,
-               stat.bit_rate,
-               s->file_name);
+       json_filenames = ast_json_pack("[s]", s->file_name);
+       if (!json_filenames) {
+               return;
+       }
+       ast_json_ref(json_filenames);
+       json_object = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: i, s: o}",
+               "type", s->direction ? "send" : "receive",
+               "remote_station_id", AST_JSON_UTF8_VALIDATE(far_ident),
+               "local_station_id", AST_JSON_UTF8_VALIDATE(local_ident),
+               "fax_pages", pages_transferred,
+               "fax_resolution", stat.y_resolution,
+               "fax_bitrate", stat.bit_rate,
+               "filenames", json_filenames);
+       message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(s->chan), ast_channel_fax_type(), json_object);
+       if (!message) {
+               return;
+       }
+       stasis_publish(ast_channel_topic(s->chan), message);
 }
 
 /* === Helper functions to configure fax === */
@@ -287,7 +283,7 @@ static int set_logging(logging_state_t *state)
        int level = SPAN_LOG_WARNING + option_debug;
 
        span_log_set_message_handler(state, span_message);
-       span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 
+       span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
 
        return 0;
 }
@@ -333,18 +329,18 @@ static int fax_generator_generate(struct ast_channel *chan, void *data, int len,
        fax_state_t *fax = (fax_state_t*) data;
        uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
        int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
-    
+
        struct ast_frame outf = {
                .frametype = AST_FRAME_VOICE,
+               .subclass.format = ast_format_slin,
                .src = __FUNCTION__,
        };
-       ast_format_set(&outf.subclass.format, AST_FORMAT_SLINEAR, 0);
 
        if (samples > MAX_SAMPLES) {
                ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
                samples = MAX_SAMPLES;
        }
-       
+
        if ((len = fax_tx(fax, buf, samples)) > 0) {
                outf.samples = len;
                AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
@@ -359,8 +355,8 @@ static int fax_generator_generate(struct ast_channel *chan, void *data, int len,
 }
 
 static struct ast_generator generator = {
-       alloc:          fax_generator_alloc,
-       generate:       fax_generator_generate,
+       .alloc = fax_generator_alloc,
+       .generate = fax_generator_generate,
 };
 
 
@@ -369,8 +365,8 @@ static struct ast_generator generator = {
 static int transmit_audio(fax_session *s)
 {
        int res = -1;
-       struct ast_format original_read_fmt;
-       struct ast_format original_write_fmt;
+       struct ast_format *original_read_fmt;
+       struct ast_format *original_write_fmt = NULL;
        fax_state_t fax;
        t30_state_t *t30state;
        struct ast_frame *inf = NULL;
@@ -390,9 +386,6 @@ static int transmit_audio(fax_session *s)
 */
        };
 
-       ast_format_clear(&original_read_fmt);
-       ast_format_clear(&original_write_fmt);
-
        /* if in called party mode, try to use T.38 */
        if (s->caller_mode == FALSE) {
                /* check if we are already in T.38 mode (unlikely), or if we can request
@@ -465,22 +458,18 @@ static int transmit_audio(fax_session *s)
         t30state = &fax.t30_state;
 #endif
 
-       ast_format_copy(&original_read_fmt, &s->chan->readformat);
-       if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
-               res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
-                       goto done;
-               }
+    original_read_fmt = ao2_bump(ast_channel_readformat(s->chan));
+       res = ast_set_read_format(s->chan, ast_format_slin);
+       if (res < 0) {
+               ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+               goto done;
        }
 
-       ast_format_copy(&original_write_fmt, &s->chan->writeformat);
-       if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
-               res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
-                       goto done;
-               }
+       original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan));
+       res = ast_set_write_format(s->chan, ast_format_slin);
+       if (res < 0) {
+               ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+               goto done;
        }
 
        /* Initialize T30 terminal */
@@ -533,12 +522,13 @@ static int transmit_audio(fax_session *s)
                        break;
                }
 
-               ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen);
+               ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen);
 
                /* Check the frame type. Format also must be checked because there is a chance
                   that a frame in old format was already queued before we set channel format
                   to slinear so it will still be received by ast_read */
-               if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) {
+               if (inf->frametype == AST_FRAME_VOICE &&
+                       (ast_format_cmp(inf->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
                        if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
                                /* I know fax_rx never returns errors. The check here is for good style only */
                                ast_log(LOG_WARNING, "fax_rx returned error\n");
@@ -592,14 +582,16 @@ static int transmit_audio(fax_session *s)
        fax_release(&fax);
 
 done:
-       if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
-               if (ast_set_write_format(s->chan, &original_write_fmt) < 0)
+       if (original_write_fmt) {
+               if (ast_set_write_format(s->chan, original_write_fmt) < 0)
                        ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan));
+               ao2_ref(original_write_fmt, -1);
        }
 
-       if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
-               if (ast_set_read_format(s->chan, &original_read_fmt) < 0)
+       if (original_read_fmt) {
+               if (ast_set_read_format(s->chan, original_read_fmt) < 0)
                        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan));
+               ao2_ref(original_read_fmt, -1);
        }
 
        return res;
@@ -788,16 +780,16 @@ static int transmit(fax_session *s)
 
        /* Clear all channel variables which to be set by the application.
           Pre-set status to error so in case of any problems we can just leave */
-       pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
-       pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
+       pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
+       pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
 
        pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
        pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
        pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0");
        pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
-       pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
+       pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
 
-       if (s->chan->_state != AST_STATE_UP) {
+       if (ast_channel_state(s->chan) != AST_STATE_UP) {
                /* Shouldn't need this, but checking to see if channel is already answered
                 * Theoretically asterisk should already have answered before running the app */
                res = ast_answer(s->chan);
@@ -809,8 +801,8 @@ static int transmit(fax_session *s)
 
        s->t38state = ast_channel_get_t38_state(s->chan);
        if (s->t38state != T38_STATE_NEGOTIATED) {
-               /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ 
-               pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
+               /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
+               pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio");
                res = transmit_audio(s);
                if (res > 0) {
                        /* transmit_audio reports switchover to T38. Update t38state */
@@ -822,7 +814,7 @@ static int transmit(fax_session *s)
        }
 
        if (s->t38state == T38_STATE_NEGOTIATED) {
-               pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
+               pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38");
                res = transmit_t38(s);
        }
 
@@ -866,7 +858,7 @@ static int sndfax_exec(struct ast_channel *chan, const char *data)
 
        parse = ast_strdupa(data);
        AST_STANDARD_APP_ARGS(args, parse);
-       
+
        session.caller_mode = TRUE;
 
        if (args.options) {
@@ -935,7 +927,7 @@ static int rcvfax_exec(struct ast_channel *chan, const char *data)
 
        parse = ast_strdupa(data);
        AST_STANDARD_APP_ARGS(args, parse);
-       
+
        session.caller_mode = FALSE;
 
        if (args.options) {
@@ -982,8 +974,8 @@ static int unload_module(void)
 {
        int res;
 
-       res = ast_unregister_application(app_sndfax_name);      
-       res |= ast_unregister_application(app_rcvfax_name);     
+       res = ast_unregister_application(app_sndfax_name);
+       res |= ast_unregister_application(app_rcvfax_name);
 
        return res;
 }
@@ -1003,8 +995,7 @@ static int load_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
-               .load = load_module,
-               .unload = unload_module,
-               );
-
-
+       .support_level = AST_MODULE_SUPPORT_DEPRECATED,
+       .load = load_module,
+       .unload = unload_module,
+);