freeswitch/libs/spandsp/src/t30_api.c

779 lines
23 KiB
C
Raw Normal View History

/*
* SpanDSP - a series of DSP components for telephony
*
* t30_api.c - ITU T.30 FAX transfer processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#if defined(HAVE_TGMATH_H)
#include <tgmath.h>
#endif
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#include "floating_fudge.h"
#include <tiffio.h>
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
#include "spandsp/bit_operations.h"
#include "spandsp/queue.h"
#include "spandsp/power_meter.h"
#include "spandsp/complex.h"
#include "spandsp/tone_generate.h"
#include "spandsp/async.h"
#include "spandsp/hdlc.h"
#include "spandsp/fsk.h"
#include "spandsp/v29rx.h"
#include "spandsp/v29tx.h"
#include "spandsp/v27ter_rx.h"
#include "spandsp/v27ter_tx.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#endif
#include "spandsp/t4_t6_decode.h"
#include "spandsp/t4_t6_encode.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
#include "spandsp/t30_api.h"
#include "spandsp/t30_logging.h"
#include "spandsp/private/logging.h"
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/private/t81_t82_arith_coding.h"
#include "spandsp/private/t85.h"
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "t30_local.h"
SPAN_DECLARE(int) t30_set_tx_ident(t30_state_t *s, const char *id)
{
if (id == NULL)
{
s->tx_info.ident[0] = '\0';
return 0;
}
if (strlen(id) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.ident, id);
t4_tx_set_local_ident(&s->t4.tx, s->tx_info.ident);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_ident(t30_state_t *s)
{
if (s->tx_info.ident[0] == '\0')
return NULL;
return s->tx_info.ident;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_ident(t30_state_t *s)
{
if (s->rx_info.ident[0] == '\0')
return NULL;
return s->rx_info.ident;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_sub_address(t30_state_t *s, const char *sub_address)
{
if (sub_address == NULL)
{
s->tx_info.sub_address[0] = '\0';
return 0;
}
if (strlen(sub_address) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.sub_address, sub_address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_sub_address(t30_state_t *s)
{
if (s->tx_info.sub_address[0] == '\0')
return NULL;
return s->tx_info.sub_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_sub_address(t30_state_t *s)
{
if (s->rx_info.sub_address[0] == '\0')
return NULL;
return s->rx_info.sub_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_selective_polling_address(t30_state_t *s, const char *selective_polling_address)
{
if (selective_polling_address == NULL)
{
s->tx_info.selective_polling_address[0] = '\0';
return 0;
}
if (strlen(selective_polling_address) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.selective_polling_address, selective_polling_address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_selective_polling_address(t30_state_t *s)
{
if (s->tx_info.selective_polling_address[0] == '\0')
return NULL;
return s->tx_info.selective_polling_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_selective_polling_address(t30_state_t *s)
{
if (s->rx_info.selective_polling_address[0] == '\0')
return NULL;
return s->rx_info.selective_polling_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_polled_sub_address(t30_state_t *s, const char *polled_sub_address)
{
if (polled_sub_address == NULL)
{
s->tx_info.polled_sub_address[0] = '\0';
return 0;
}
if (strlen(polled_sub_address) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.polled_sub_address, polled_sub_address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_polled_sub_address(t30_state_t *s)
{
if (s->tx_info.polled_sub_address[0] == '\0')
return NULL;
return s->tx_info.polled_sub_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_polled_sub_address(t30_state_t *s)
{
if (s->rx_info.polled_sub_address[0] == '\0')
return NULL;
return s->rx_info.polled_sub_address;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_sender_ident(t30_state_t *s, const char *sender_ident)
{
if (sender_ident == NULL)
{
s->tx_info.sender_ident[0] = '\0';
return 0;
}
if (strlen(sender_ident) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.sender_ident, sender_ident);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_sender_ident(t30_state_t *s)
{
if (s->tx_info.sender_ident[0] == '\0')
return NULL;
return s->tx_info.sender_ident;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_sender_ident(t30_state_t *s)
{
if (s->rx_info.sender_ident[0] == '\0')
return NULL;
return s->rx_info.sender_ident;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_password(t30_state_t *s, const char *password)
{
if (password == NULL)
{
s->tx_info.password[0] = '\0';
return 0;
}
if (strlen(password) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.password, password);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_tx_password(t30_state_t *s)
{
if (s->tx_info.password[0] == '\0')
return NULL;
return s->tx_info.password;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_password(t30_state_t *s)
{
if (s->rx_info.password[0] == '\0')
return NULL;
return s->rx_info.password;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len)
{
if (s->tx_info.nsf)
free(s->tx_info.nsf);
if (nsf && len > 0 && (s->tx_info.nsf = malloc(len + 3)))
{
memcpy(s->tx_info.nsf + 3, nsf, len);
s->tx_info.nsf_len = len;
}
else
{
s->tx_info.nsf = NULL;
s->tx_info.nsf_len = 0;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_nsf(t30_state_t *s, const uint8_t *nsf[])
{
if (nsf)
*nsf = s->tx_info.nsf;
return s->tx_info.nsf_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_nsf(t30_state_t *s, const uint8_t *nsf[])
{
if (nsf)
*nsf = s->rx_info.nsf;
return s->rx_info.nsf_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len)
{
if (s->tx_info.nsc)
free(s->tx_info.nsc);
if (nsc && len > 0 && (s->tx_info.nsc = malloc(len + 3)))
{
memcpy(s->tx_info.nsc + 3, nsc, len);
s->tx_info.nsc_len = len;
}
else
{
s->tx_info.nsc = NULL;
s->tx_info.nsc_len = 0;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_nsc(t30_state_t *s, const uint8_t *nsc[])
{
if (nsc)
*nsc = s->tx_info.nsc;
return s->tx_info.nsc_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_nsc(t30_state_t *s, const uint8_t *nsc[])
{
if (nsc)
*nsc = s->rx_info.nsc;
return s->rx_info.nsc_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len)
{
if (s->tx_info.nss)
free(s->tx_info.nss);
if (nss && len > 0 && (s->tx_info.nss = malloc(len + 3)))
{
memcpy(s->tx_info.nss + 3, nss, len);
s->tx_info.nss_len = len;
}
else
{
s->tx_info.nss = NULL;
s->tx_info.nss_len = 0;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_nss(t30_state_t *s, const uint8_t *nss[])
{
if (nss)
*nss = s->tx_info.nss;
return s->tx_info.nss_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_nss(t30_state_t *s, const uint8_t *nss[])
{
if (nss)
*nss = s->rx_info.nss;
return s->rx_info.nss_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_tsa(t30_state_t *s, int type, const char *address, int len)
{
if (s->tx_info.tsa)
free(s->tx_info.tsa);
if (address == NULL || len == 0)
{
s->tx_info.tsa = NULL;
s->tx_info.tsa_len = 0;
return 0;
}
s->tx_info.tsa_type = type;
if (len < 0)
len = strlen(address);
if ((s->tx_info.tsa = malloc(len)))
{
memcpy(s->tx_info.tsa, address, len);
s->tx_info.tsa_len = len;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_tsa(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->tx_info.tsa_type;
if (address)
*address = s->tx_info.tsa;
return s->tx_info.tsa_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_tsa(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->rx_info.tsa_type;
if (address)
*address = s->rx_info.tsa;
return s->rx_info.tsa_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_ira(t30_state_t *s, int type, const char *address, int len)
{
if (s->tx_info.ira)
free(s->tx_info.ira);
if (address == NULL)
{
s->tx_info.ira = NULL;
return 0;
}
s->tx_info.ira = strdup(address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_ira(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->tx_info.ira_type;
if (address)
*address = s->tx_info.ira;
return s->tx_info.ira_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_ira(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->rx_info.ira_type;
if (address)
*address = s->rx_info.ira;
return s->rx_info.ira_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_cia(t30_state_t *s, int type, const char *address, int len)
{
if (s->tx_info.cia)
free(s->tx_info.cia);
if (address == NULL)
{
s->tx_info.cia = NULL;
return 0;
}
s->tx_info.cia = strdup(address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_cia(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->tx_info.cia_type;
if (address)
*address = s->tx_info.cia;
return s->tx_info.cia_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_cia(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->rx_info.cia_type;
if (address)
*address = s->rx_info.cia;
return s->rx_info.cia_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_isp(t30_state_t *s, int type, const char *address, int len)
{
if (s->tx_info.isp)
free(s->tx_info.isp);
if (address == NULL)
{
s->tx_info.isp = NULL;
return 0;
}
s->tx_info.isp = strdup(address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_isp(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->tx_info.isp_type;
if (address)
*address = s->tx_info.isp;
return s->tx_info.isp_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_isp(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->rx_info.isp_type;
if (address)
*address = s->rx_info.isp;
return s->rx_info.isp_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_csa(t30_state_t *s, int type, const char *address, int len)
{
if (s->tx_info.csa)
free(s->tx_info.csa);
if (address == NULL)
{
s->tx_info.csa = NULL;
return 0;
}
s->tx_info.csa = strdup(address);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_csa(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->tx_info.csa_type;
if (address)
*address = s->tx_info.csa;
return s->tx_info.csa_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_rx_csa(t30_state_t *s, int *type, const char *address[])
{
if (type)
*type = s->rx_info.csa_type;
if (address)
*address = s->rx_info.csa;
return s->rx_info.csa_len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_page_header_overlays_image(t30_state_t *s, int header_overlays_image)
{
#if 0
s->header_overlays_image = header_overlays_image;
t4_tx_set_header_overlays_image(&s->t4.tx, s->header_overlays_image);
#endif
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_page_header_info(t30_state_t *s, const char *info)
{
if (info == NULL)
{
s->header_info[0] = '\0';
return 0;
}
if (strlen(info) > T30_MAX_PAGE_HEADER_INFO)
return -1;
strcpy(s->header_info, info);
t4_tx_set_header_info(&s->t4.tx, s->header_info);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_tx_page_header_tz(t30_state_t *s, const char *tzstring)
{
t4_tx_set_header_tz(&s->t4.tx, tzstring);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(size_t) t30_get_tx_page_header_info(t30_state_t *s, char *info)
{
if (info)
strcpy(info, s->header_info);
return strlen(s->header_info);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_country(t30_state_t *s)
{
return s->country;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_vendor(t30_state_t *s)
{
return s->vendor;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_get_rx_model(t30_state_t *s)
{
return s->model;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_rx_file(t30_state_t *s, const char *file, int stop_page)
{
strncpy(s->rx_file, file, sizeof(s->rx_file));
s->rx_file[sizeof(s->rx_file) - 1] = '\0';
s->rx_stop_page = stop_page;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_tx_file(t30_state_t *s, const char *file, int start_page, int stop_page)
{
strncpy(s->tx_file, file, sizeof(s->tx_file));
s->tx_file[sizeof(s->tx_file) - 1] = '\0';
s->tx_start_page = start_page;
s->tx_stop_page = stop_page;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_iaf_mode(t30_state_t *s, int iaf)
{
s->iaf = iaf;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled)
{
s->ecm_allowed = enabled;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_rx_encoding(t30_state_t *s, int encoding)
{
switch (encoding)
{
case T4_COMPRESSION_ITU_T4_1D:
case T4_COMPRESSION_ITU_T4_2D:
case T4_COMPRESSION_ITU_T6:
s->output_encoding = encoding;
return 0;
}
return -1;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_minimum_scan_line_time(t30_state_t *s, int min_time)
{
/* There are only certain possible times supported, so we need to select
the code which best matches the request. */
if (min_time == 0)
s->local_min_scan_time_code = 7;
else if (min_time <= 5)
s->local_min_scan_time_code = 1;
else if (min_time <= 10)
s->local_min_scan_time_code = 2;
else if (min_time <= 20)
s->local_min_scan_time_code = 0;
else if (min_time <= 40)
s->local_min_scan_time_code = 4;
else
return -1;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_supported_modems(t30_state_t *s, int supported_modems)
{
s->supported_modems = supported_modems;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_compressions)
{
int mask;
/* Mask out the ones we actually support today. */
mask = T30_SUPPORT_T4_1D_COMPRESSION
| T30_SUPPORT_T4_2D_COMPRESSION
| T30_SUPPORT_T6_COMPRESSION
#if defined(SPANDSP_SUPPORT_T85)
| T30_SUPPORT_T85_COMPRESSION
| T30_SUPPORT_T85_L0_COMPRESSION;
#else
| 0;
#endif
s->supported_compressions = supported_compressions & mask;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_supported_resolutions(t30_state_t *s, int supported_resolutions)
{
s->supported_resolutions = supported_resolutions;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_supported_image_sizes(t30_state_t *s, int supported_image_sizes)
{
s->supported_image_sizes = supported_image_sizes;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_supported_t30_features(t30_state_t *s, int supported_t30_features)
{
s->supported_t30_features = supported_t30_features;
t30_build_dis_or_dtc(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_status(t30_state_t *s, int status)
{
s->current_status = status;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_receiver_not_ready(t30_state_t *s, int count)
{
s->receiver_not_ready_count = count;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_phase_b_handler(t30_state_t *s, t30_phase_b_handler_t *handler, void *user_data)
{
s->phase_b_handler = handler;
s->phase_b_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_phase_d_handler(t30_state_t *s, t30_phase_d_handler_t *handler, void *user_data)
{
s->phase_d_handler = handler;
s->phase_d_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_phase_e_handler(t30_state_t *s, t30_phase_e_handler_t *handler, void *user_data)
{
s->phase_e_handler = handler;
s->phase_e_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_document_handler(t30_state_t *s, t30_document_handler_t *handler, void *user_data)
{
s->document_handler = handler;
s->document_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_set_real_time_frame_handler(t30_state_t *s, t30_real_time_frame_handler_t *handler, void *user_data)
{
s->real_time_frame_handler = handler;
s->real_time_frame_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(logging_state_t *) t30_get_logging_state(t30_state_t *s)
{
return &s->logging;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/