/*! Clear a specified bit within a DIS, DTC or DCS frame */
#define clr_ctrl_bit(s,bit) (s)[3 + ((bit - 1)/8)] &= ~(1 << ((bit - 1)%8))
+static int find_fallback_entry(int dcs_code)
+{
+ int i;
+
+ /* The table is short, and not searched often, so a brain-dead linear scan seems OK */
+ for (i = 0; fallback_sequence[i].bit_rate; i++)
+ {
+ if (fallback_sequence[i].dcs_code == dcs_code)
+ break;
+ }
+ if (fallback_sequence[i].bit_rate == 0)
+ return -1;
+ return i;
+}
+/*- End of function --------------------------------------------------------*/
+
static int terminate_operation_in_progress(t30_state_t *s)
{
/* Make sure any FAX in progress is tidied up. If the tidying up has
}
/*- End of function --------------------------------------------------------*/
-static int set_dis_or_dtc(t30_state_t *s)
-{
- /* Whether we use a DIS or a DTC is determined by whether we have received a DIS.
- We just need to edit the prebuilt message. */
- s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received);
- /* If we have a file name to receive into, then we are receive capable */
- if (s->rx_file[0])
- set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT);
- else
- clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT);
- /* If we have a file name to transmit, then we are ready to transmit (polling) */
- if (s->tx_file[0])
- set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT);
- else
- clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int prune_dis_dtc(t30_state_t *s)
-{
- int i;
-
- /* Find the last octet that is really needed, set the extension bits, and trim the message length */
- for (i = 18; i >= 6; i--)
- {
- /* Strip the top bit */
- s->local_dis_dtc_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7);
- /* Check if there is some real message content here */
- if (s->local_dis_dtc_frame[i])
- break;
- }
- s->local_dis_dtc_len = i + 1;
- /* Fill in any required extension bits */
- s->local_dis_dtc_frame[i] &= ~DISBIT8;
- for (i--; i > 4; i--)
- s->local_dis_dtc_frame[i] |= DISBIT8;
- t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
- return s->local_dis_dtc_len;
-}
-/*- End of function --------------------------------------------------------*/
-
int t30_build_dis_or_dtc(t30_state_t *s)
{
int i;
s->local_dis_dtc_frame[0] = ADDRESS_FIELD;
s->local_dis_dtc_frame[1] = CONTROL_FIELD_FINAL_FRAME;
s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received);
- for (i = 3; i < 19; i++)
+ for (i = 3; i < T30_MAX_DIS_DTC_DCS_LEN; i++)
s->local_dis_dtc_frame[i] = 0x00;
/* Always say 256 octets per ECM frame preferred, as 64 is never used in the
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE);
/* No scan-line padding required, but some may be specified by the application. */
- set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, 21);
+ set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_1);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T4_2D))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE);
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE);
/* No T.88/T.89 profile */
s->local_dis_dtc_len = 19;
- //t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
return 0;
}
/*- End of function --------------------------------------------------------*/
+static int set_dis_or_dtc(t30_state_t *s)
+{
+ /* Whether we use a DIS or a DTC is determined by whether we have received a DIS.
+ We just need to edit the prebuilt message. */
+ s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received);
+ /* If we have a file name to receive into, then we are receive capable */
+ if (s->rx_file[0])
+ set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT);
+ else
+ clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT);
+ /* If we have a file name to transmit, then we are ready to transmit (polling) */
+ if (s->tx_file[0])
+ set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT);
+ else
+ clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int prune_dis_dtc(t30_state_t *s)
+{
+ int i;
+
+ /* Find the last octet that is really needed, set the extension bits, and trim the message length */
+ for (i = T30_MAX_DIS_DTC_DCS_LEN - 1; i >= 6; i--)
+ {
+ /* Strip the top bit */
+ s->local_dis_dtc_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7);
+ /* Check if there is some real message content here */
+ if (s->local_dis_dtc_frame[i])
+ break;
+ }
+ s->local_dis_dtc_len = i + 1;
+ /* Fill in any required extension bits */
+ s->local_dis_dtc_frame[i] &= ~DISBIT8;
+ for (i--; i > 4; i--)
+ s->local_dis_dtc_frame[i] |= DISBIT8;
+ t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
+ return s->local_dis_dtc_len;
+}
+/*- End of function --------------------------------------------------------*/
+
static int build_dcs(t30_state_t *s)
{
int i;
s->dcs_frame[0] = ADDRESS_FIELD;
s->dcs_frame[1] = CONTROL_FIELD_FINAL_FRAME;
s->dcs_frame[2] = (uint8_t) (T30_DCS | s->dis_received);
- for (i = 3; i < 19; i++)
+ for (i = 3; i < T30_MAX_DIS_DTC_DCS_LEN; i++)
s->dcs_frame[i] = 0x00;
+ /* We have a file to send, so tell the far end to go into receive mode. */
+ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT);
+
#if 0
/* Check for T.37 simple mode. */
- if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37))
+ if ((s->iaf & T30_IAF_MODE_T37) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T37);
/* Check for T.38 mode. */
- if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38))
+ if ((s->iaf & T30_IAF_MODE_T38) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38);
#endif
/* Set to required modem rate */
s->dcs_frame[4] |= fallback_sequence[s->current_fallback].dcs_code;
- /* We have a file to send, so tell the far end to go into receive mode. */
- set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT);
-
/* Select the compression to use. */
use_bilevel = TRUE;
switch (s->line_encoding)
{
+ case T4_COMPRESSION_T4_1D:
+ /* There is nothing to set to select this encoding. */
+ set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
+ break;
+ case T4_COMPRESSION_T4_2D:
+ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_2D_MODE);
+ set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
+ break;
+ case T4_COMPRESSION_T6:
+ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
+ break;
+ case T4_COMPRESSION_T85:
+ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
+ break;
+ case T4_COMPRESSION_T85_L0:
+ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
+ break;
case T4_COMPRESSION_T42_T81:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T81_MODE);
//if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT);
//if (???????? & T4_COMPRESSION_?????))
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING);
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
use_bilevel = FALSE;
break;
#if defined(SPANDSP_SUPPORT_T43)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT);
//if (???????? & T4_COMPRESSION_?????))
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING);
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
use_bilevel = FALSE;
break;
#endif
- case T4_COMPRESSION_T85_L0:
- set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE);
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
- break;
- case T4_COMPRESSION_T85:
- set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE);
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
- break;
- case T4_COMPRESSION_T6:
- set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE);
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
- break;
- case T4_COMPRESSION_T4_2D:
- set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_2D_MODE);
- set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, 21);
- break;
- case T4_COMPRESSION_T4_1D:
- set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, 21);
- break;
default:
- set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
+ set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
break;
}
/* Set the Y resolution bits */
- bad = T30_ERR_NORESSUPPORT;
row_squashing_ratio = 1;
+ bad = T30_ERR_NORESSUPPORT;
if (use_bilevel)
{
switch (s->y_resolution)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38_FAX_MODE);
}
s->dcs_len = 19;
- //t30_decode_dis_dtc_dcs(s, s->dcs_frame, s->dcs_len);
return 0;
}
/*- End of function --------------------------------------------------------*/
int i;
/* Find the last octet that is really needed, set the extension bits, and trim the message length */
- for (i = 18; i >= 6; i--)
+ for (i = T30_MAX_DIS_DTC_DCS_LEN - 1; i >= 6; i--)
{
/* Strip the top bit */
s->dcs_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7);
}
/*- End of function --------------------------------------------------------*/
-static int step_fallback_entry(t30_state_t *s)
+static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
{
- int min_row_bits;
-
- while (fallback_sequence[++s->current_fallback].which)
+ t30_decode_dis_dtc_dcs(s, msg, len);
+ if (len < 6)
{
- if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems))
- break;
- }
- if (fallback_sequence[s->current_fallback].which == 0)
+ span_log(&s->logging, SPAN_LOG_FLOW, "Short DIS/DTC frame\n");
return -1;
- /* TODO: This only sets the minimum row time for future pages. It doesn't fix up the
- current page, though it is benign - fallback will only result in an excessive
- minimum. */
- min_row_bits = set_min_scan_time_code(s);
- t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits);
- /* We need to rebuild the DCS message we will send. */
- build_dcs(s);
- return s->current_fallback;
-}
-/*- End of function --------------------------------------------------------*/
+ }
-static int find_fallback_entry(int dcs_code)
-{
- int i;
+ if (msg[2] == T30_DIS)
+ s->dis_received = TRUE;
- /* The table is short, and not searched often, so a brain-dead linear scan seems OK */
- for (i = 0; fallback_sequence[i].bit_rate; i++)
+ /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows
+ us to simply pick out the bits, without worrying about whether they were set from the remote side. */
+ if (len > T30_MAX_DIS_DTC_DCS_LEN)
+ len = T30_MAX_DIS_DTC_DCS_LEN;
+ memcpy(s->far_dis_dtc_frame, msg, len);
+ if (len < T30_MAX_DIS_DTC_DCS_LEN)
+ memset(s->far_dis_dtc_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len);
+
+ s->error_correcting_mode = (s->ecm_allowed && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE));
+ /* Always use 256 octets per ECM frame, whatever the other end says it is capable of */
+ s->octets_per_ecm_frame = 256;
+
+ /* Now we know if we are going to use ECM, select the compressions which we can use. */
+ s->mutual_compressions = s->supported_compressions;
+ if (!s->error_correcting_mode)
{
- if (fallback_sequence[i].dcs_code == dcs_code)
- break;
+ /* Remove any compression schemes which need error correction to work. */
+ s->mutual_compressions &= (0xF0000000 | T30_SUPPORT_COMPRESSION_NONE | T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D);
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D;
}
- if (fallback_sequence[i].bit_rate == 0)
- return -1;
- return i;
-}
-/*- End of function --------------------------------------------------------*/
+ else
+ {
+ /* Check the bi-level capabilities */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T6;
+ /* T.85 L0 capable without T.85 capable is an invalid combination, so let
+ just zap both capabilities if the far end is not T.85 capable. */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE))
+ s->mutual_compressions &= ~(T30_SUPPORT_COMPRESSION_T85 | T30_SUPPORT_COMPRESSION_T85_L0);
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T85_L0;
-static void send_dcn(t30_state_t *s)
-{
- queue_phase(s, T30_PHASE_D_TX);
- set_state(s, T30_STATE_C);
- send_simple_frame(s, T30_DCN);
-}
-/*- End of function --------------------------------------------------------*/
+ /* Check for full colour or only gray-scale from the multi-level codecs */
+ //if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE))
+ // s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_COLOUR;
-static void return_to_phase_b(t30_state_t *s, int with_fallback)
-{
- /* This is what we do after things like T30_EOM is exchanged. */
-#if 0
- if (step_fallback_entry(s) < 0)
+ /* Check the colour capabilities */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T42_T81;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_SYCC_T81;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T43;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T45;
+
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE))
+ s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_12BIT;
+ //if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING))
+ // ???? = T4_COMPRESSION_T42_T81_SUBSAMPLING;
+
+ /* bit74 custom illuminant */
+ /* bit75 custom gamut range */
+ }
+
+ s->mutual_bilevel_resolutions = s->supported_bilevel_resolutions;
+ s->mutual_colour_resolutions = s->supported_colour_resolutions;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE))
{
- /* We have fallen back as far as we can go. Give up. */
- s->current_fallback = 0;
- t30_set_status(s, T30_ERR_CANNOT_TRAIN);
- send_dcn(s);
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
}
else
{
- if (s->calling_party)
- set_state(s, T30_STATE_T);
- else
- set_state(s, T30_STATE_R);
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_1200_1200_CAPABLE))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
+ }
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_600_1200;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE))
+ {
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
}
-#else
- if (s->calling_party)
- set_state(s, T30_STATE_T);
else
- set_state(s, T30_STATE_R);
-#endif
-}
-/*- End of function --------------------------------------------------------*/
-
-static int send_dis_or_dtc_sequence(t30_state_t *s, int start)
-{
- /* (NSF) (CSI) DIS */
- /* (NSC) (CIG) (PWD) (SEP) (PSA) (CIA) (ISP) DTC */
- if (start)
{
- set_dis_or_dtc(s);
- set_state(s, T30_STATE_R);
- s->step = 0;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_600_600_CAPABLE))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
}
- if (!s->dis_received)
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_400_800;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE))
{
- /* DIS sequence */
- switch (s->step)
- {
- case 0:
- s->step++;
- if (send_nsf_frame(s))
- break;
- /* Fall through */
- case 1:
- s->step++;
- if (send_ident_frame(s, T30_CSI))
- break;
- /* Fall through */
- case 2:
- s->step++;
- prune_dis_dtc(s);
- send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
- break;
- case 3:
- s->step++;
- shut_down_hdlc_tx(s);
- break;
- default:
- return -1;
- }
+ s->mutual_bilevel_resolutions &= ~(T4_SUPPORT_RESOLUTION_400_400 | T4_SUPPORT_RESOLUTION_R16_SUPERFINE);
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_400_400;
}
else
{
- /* DTC sequence */
- switch (s->step)
- {
- case 0:
- s->step++;
- if (send_nsc_frame(s))
- break;
- /* Fall through */
- case 1:
- s->step++;
- if (send_ident_frame(s, T30_CIG))
- break;
- /* Fall through */
- case 2:
- s->step++;
- if (send_pwd_frame(s))
- break;
- /* Fall through */
- case 3:
- s->step++;
- if (send_sep_frame(s))
- break;
- /* Fall through */
- case 4:
- s->step++;
- if (send_psa_frame(s))
- break;
- /* Fall through */
- case 5:
- s->step++;
- if (send_cia_frame(s))
- break;
- /* Fall through */
- case 6:
- s->step++;
- if (send_isp_frame(s))
- break;
- /* Fall through */
- case 7:
- s->step++;
- prune_dis_dtc(s);
- send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
- break;
- case 8:
- s->step++;
- shut_down_hdlc_tx(s);
- break;
- default:
- return -1;
- }
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_400_400;
}
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_300_600;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE))
+ {
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
+ }
+ else
+ {
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
+ }
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
+ {
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_400;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_R8_SUPERFINE;
+ }
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
+ {
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_R8_FINE;
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
+ }
+ else
+ {
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
+ }
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
+ s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_100;
+ /* Never suppress T4_SUPPORT_RESOLUTION_R8_STANDARD */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE))
+ s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_100_100;
-static int send_dcs_sequence(t30_state_t *s, int start)
-{
- /* (NSS) (TSI) (SUB) (SID) (TSA) (IRA) DCS */
- /* Schedule training after the messages */
- if (start)
+ s->mutual_image_sizes = s->supported_image_sizes;
+ /* 215mm wide is always supported */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE))
{
- prune_dcs(s);
- set_state(s, T30_STATE_D);
- s->step = 0;
+ s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_303MM;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE))
+ s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_255MM;
}
- switch (s->step)
+ /* A4 is always supported. */
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE))
{
- case 0:
- s->step++;
- if (send_nss_frame(s))
- break;
- /* Fall through */
- case 1:
- s->step++;
- if (send_ident_frame(s, T30_TSI))
- break;
- /* Fall through */
- case 2:
- s->step++;
- if (send_sub_frame(s))
- break;
- /* Fall through */
- case 3:
- s->step++;
- if (send_sid_frame(s))
- break;
- /* Fall through */
- case 4:
- s->step++;
- if (send_tsa_frame(s))
+ s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_UNLIMITED;
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE))
+ s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4;
+ }
+ if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE))
+ s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LETTER;
+ if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE))
+ s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LEGAL;
+
+ switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
+ {
+ case (DISBIT6 | DISBIT4 | DISBIT3):
+ if ((s->supported_modems & T30_SUPPORT_V17))
+ {
+ s->current_permitted_modems = T30_SUPPORT_V17 | T30_SUPPORT_V29 | T30_SUPPORT_V27TER;
+ s->current_fallback = T30_V17_FALLBACK_START;
break;
+ }
/* Fall through */
- case 5:
- s->step++;
- if (send_ira_frame(s))
+ case (DISBIT4 | DISBIT3):
+ if ((s->supported_modems & T30_SUPPORT_V29))
+ {
+ s->current_permitted_modems = T30_SUPPORT_V29 | T30_SUPPORT_V27TER;
+ s->current_fallback = T30_V29_FALLBACK_START;
break;
+ }
/* Fall through */
- case 6:
- s->step++;
- prune_dcs(s);
- send_frame(s, s->dcs_frame, s->dcs_len);
+ case DISBIT4:
+ s->current_permitted_modems = T30_SUPPORT_V27TER;
+ s->current_fallback = T30_V27TER_FALLBACK_START;
break;
- case 7:
- s->step++;
- shut_down_hdlc_tx(s);
+ case 0:
+ s->current_permitted_modems = T30_SUPPORT_V27TER;
+ s->current_fallback = T30_V27TER_FALLBACK_START + 1;
break;
+ case DISBIT3:
+ if ((s->supported_modems & T30_SUPPORT_V29))
+ {
+ /* TODO: this doesn't allow for skipping the V.27ter modes */
+ s->current_permitted_modems = T30_SUPPORT_V29;
+ s->current_fallback = T30_V29_FALLBACK_START;
+ break;
+ }
+ /* Fall through */
default:
+ span_log(&s->logging, SPAN_LOG_FLOW, "Remote does not support a compatible modem\n");
+ /* We cannot talk to this machine! */
+ t30_set_status(s, T30_ERR_INCOMPATIBLE);
return -1;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
-static int send_cfr_sequence(t30_state_t *s, int start)
-{
- /* (CSA) CFR */
- /* CFR is usually a simple frame, but can become a sequence with Internet
- FAXing. */
- send_simple_frame(s, T30_CFR);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void disconnect(t30_state_t *s)
-{
- span_log(&s->logging, SPAN_LOG_FLOW, "Disconnecting\n");
- /* Make sure any FAX in progress is tidied up. If the tidying up has
- already happened, repeating it here is harmless. */
- terminate_operation_in_progress(s);
- s->timer_t0_t1 = 0;
- s->timer_t2_t4 = 0;
- s->timer_t3 = 0;
- s->timer_t5 = 0;
- set_phase(s, T30_PHASE_E);
- set_state(s, T30_STATE_B);
-}
-/*- End of function --------------------------------------------------------*/
-
-static int set_min_scan_time_code(t30_state_t *s)
+static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
{
- /* Translation between the codes for the minimum scan times the other end needs,
- and the codes for what we say will be used. We need 0 minimum. */
- static const uint8_t translate_min_scan_time[3][8] =
+ static const int widths[6][4] =
{
- {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_0MS}, /* normal */
- {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS}, /* fine */
- {T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS} /* superfine, when half fine time is selected */
+ { T4_WIDTH_100_A4, T4_WIDTH_100_B4, T4_WIDTH_100_A3, -1}, /* 100/inch */
+ { T4_WIDTH_200_A4, T4_WIDTH_200_B4, T4_WIDTH_200_A3, -1}, /* 200/inch / R8 resolution */
+ { T4_WIDTH_300_A4, T4_WIDTH_300_B4, T4_WIDTH_300_A3, -1}, /* 300/inch resolution */
+ { T4_WIDTH_400_A4, T4_WIDTH_400_B4, T4_WIDTH_400_A3, -1}, /* 400/inch / R16 resolution */
+ { T4_WIDTH_600_A4, T4_WIDTH_600_B4, T4_WIDTH_600_A3, -1}, /* 600/inch resolution */
+ {T4_WIDTH_1200_A4, T4_WIDTH_1200_B4, T4_WIDTH_1200_A3, -1} /* 1200/inch resolution */
};
- /* Translation between the codes for the minimum scan time we will use, and milliseconds. */
- static const int min_scan_times[8] =
+ uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN];
+ int i;
+ int x;
+
+ t30_decode_dis_dtc_dcs(s, msg, len);
+ if (len < 6)
{
- 20, 5, 10, 0, 40, 0, 0, 0
- };
- int min_bits_field;
+ span_log(&s->logging, SPAN_LOG_FLOW, "Short DCS frame\n");
+ return -1;
+ }
- /* Set the minimum scan time bits */
- if (s->error_correcting_mode)
- min_bits_field = T30_MIN_SCAN_0MS;
- else
- min_bits_field = (s->far_dis_dtc_frame[5] >> 4) & 7;
- switch (s->y_resolution)
- {
- case T4_Y_RESOLUTION_SUPERFINE:
- if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
- {
- s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field];
- break;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n");
- /* Fall through */
- case T4_Y_RESOLUTION_FINE:
- if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
- {
- s->min_scan_time_code = translate_min_scan_time[1][min_bits_field];
- break;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n");
- /* Fall through */
- default:
- case T4_Y_RESOLUTION_STANDARD:
- s->min_scan_time_code = translate_min_scan_time[0][min_bits_field];
- break;
- }
- if (!s->error_correcting_mode && (s->iaf & T30_IAF_MODE_NO_FILL_BITS))
- return 0;
- return fallback_sequence[s->current_fallback].bit_rate*min_scan_times[s->min_scan_time_code]/1000;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int start_sending_document(t30_state_t *s)
-{
- int min_row_bits;
-
- if (s->tx_file[0] == '\0')
- {
- /* There is nothing to send */
- span_log(&s->logging, SPAN_LOG_FLOW, "No document to send\n");
- return -1;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "Start sending document\n");
- if (t4_tx_init(&s->t4.tx, s->tx_file, s->tx_start_page, s->tx_stop_page) == NULL)
- {
- span_log(&s->logging, SPAN_LOG_WARNING, "Cannot open source TIFF file '%s'\n", s->tx_file);
- t30_set_status(s, T30_ERR_FILEERROR);
- return -1;
- }
- s->operation_in_progress = OPERATION_IN_PROGRESS_T4_TX;
- t4_tx_get_pages_in_file(&s->t4.tx);
- t4_tx_set_tx_encoding(&s->t4.tx, s->line_encoding);
- t4_tx_set_local_ident(&s->t4.tx, s->tx_info.ident);
- t4_tx_set_header_info(&s->t4.tx, s->header_info);
- if (s->use_own_tz)
- t4_tx_set_header_tz(&s->t4.tx, &s->tz);
-
- if (tx_start_page(s))
- {
- span_log(&s->logging, SPAN_LOG_WARNING, "Something seems to be wrong in the file\n");
- t30_set_status(s, T30_ERR_FILEERROR);
- return -1;
- }
-
- s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx);
- s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx);
- s->image_width = t4_tx_get_image_width(&s->t4.tx);
- /* The minimum scan time to be used can't be evaluated until we know the Y resolution, and
- must be evaluated before the minimum scan row bits can be evaluated. */
- if ((min_row_bits = set_min_scan_time_code(s)) < 0)
- {
- terminate_operation_in_progress(s);
- return -1;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "Minimum bits per row will be %d\n", min_row_bits);
- t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits);
+ /* Make an ASCII string format copy of the message, for logging in the
+ received file. This string does not include the frame header octets. */
+ sprintf(s->rx_dcs_string, "%02X", bit_reverse8(msg[3]));
+ for (i = 4; i < len; i++)
+ sprintf(s->rx_dcs_string + 3*i - 10, " %02X", bit_reverse8(msg[i]));
- if (s->error_correcting_mode)
- {
- if (get_partial_ecm_page(s) == 0)
- span_log(&s->logging, SPAN_LOG_WARNING, "No image data to send\n");
- }
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
+ /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows
+ us to simply pick out the bits, without worrying about whether they were set from the remote side. */
+ if (len > T30_MAX_DIS_DTC_DCS_LEN)
+ len = T30_MAX_DIS_DTC_DCS_LEN;
+ memcpy(dcs_frame, msg, len);
+ if (len < T30_MAX_DIS_DTC_DCS_LEN)
+ memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len);
-static int restart_sending_document(t30_state_t *s)
-{
- t4_tx_restart_page(&s->t4.tx);
- s->retries = 0;
- s->ecm_block = 0;
- send_dcs_sequence(s, TRUE);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
+ s->error_correcting_mode = (test_ctrl_bit(dcs_frame, T30_DCS_BIT_ECM_MODE) != 0);
+ s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, T30_DCS_BIT_64_OCTET_ECM_FRAMES) ? 256 : 64;
-static int start_receiving_document(t30_state_t *s)
-{
- if (s->rx_file[0] == '\0')
+ s->x_resolution = -1;
+ s->y_resolution = -1;
+ s->current_page_resolution = 0;
+ x = -1;
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
{
- /* There is nothing to receive to */
- span_log(&s->logging, SPAN_LOG_FLOW, "No document to receive\n");
- return -1;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "Start receiving document\n");
- queue_phase(s, T30_PHASE_B_TX);
- s->ecm_block = 0;
- send_dis_or_dtc_sequence(s, TRUE);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void unexpected_non_final_frame(t30_state_t *s, const uint8_t *msg, int len)
-{
- span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]);
- if (s->current_status == T30_ERR_OK)
- t30_set_status(s, T30_ERR_UNEXPECTED);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void unexpected_final_frame(t30_state_t *s, const uint8_t *msg, int len)
-{
- span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]);
- if (s->current_status == T30_ERR_OK)
- t30_set_status(s, T30_ERR_UNEXPECTED);
- send_dcn(s);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void unexpected_frame_length(t30_state_t *s, const uint8_t *msg, int len)
-{
- span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len);
- if (s->current_status == T30_ERR_OK)
- t30_set_status(s, T30_ERR_UNEXPECTED);
- send_dcn(s);
-}
-/*- End of function --------------------------------------------------------*/
-
-static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
-{
- int new_status;
+ /* Gray scale or colour image */
- t30_decode_dis_dtc_dcs(s, msg, len);
- if (len < 6)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Short DIS/DTC frame\n");
- return -1;
- }
+ /* Note 35 of Table 2/T.30 */
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
+ {
+ /* We are going to work in full colour mode */
+ }
- if (msg[2] == T30_DIS)
- s->dis_received = TRUE;
- /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows
- us to simply pick out the bits, without worrying about whether they were set from the remote side. */
- s->far_dis_dtc_len = (len > T30_MAX_DIS_DTC_DCS_LEN) ? T30_MAX_DIS_DTC_DCS_LEN : len;
- memcpy(s->far_dis_dtc_frame, msg, s->far_dis_dtc_len);
- if (s->far_dis_dtc_len < T30_MAX_DIS_DTC_DCS_LEN)
- memset(s->far_dis_dtc_frame + s->far_dis_dtc_len, 0, T30_MAX_DIS_DTC_DCS_LEN - s->far_dis_dtc_len);
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT))
+ {
+ /* We are going to work in 12 bit mode */
+ }
- s->error_correcting_mode = (s->ecm_allowed && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE));
- /* 256 octets per ECM frame */
- s->octets_per_ecm_frame = 256;
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING))
+ {
+ //???? = T30_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING;
+ }
- /* Now we know if we are going to use ECM, select the compressions which we can use. */
- s->mutual_compressions = s->supported_compressions;
- if (!s->error_correcting_mode)
- {
- /* Remove any compression schemes which need error correction to work. */
- s->mutual_compressions &= (0xF0000000 | T30_SUPPORT_COMPRESSION_NONE | T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D);
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
- s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D;
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_1200_1200))
+ {
+ s->x_resolution = T4_X_RESOLUTION_1200;
+ s->y_resolution = T4_Y_RESOLUTION_1200;
+ s->current_page_resolution = T4_RESOLUTION_1200_1200;
+ x = 5;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_600_600))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_600_600))
+ {
+ s->x_resolution = T4_X_RESOLUTION_600;
+ s->y_resolution = T4_Y_RESOLUTION_600;
+ s->current_page_resolution = T4_RESOLUTION_600_600;
+ x = 4;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_400_400))
+ {
+ s->x_resolution = T4_X_RESOLUTION_400;
+ s->y_resolution = T4_Y_RESOLUTION_400;
+ s->current_page_resolution = T4_RESOLUTION_400_400;
+ x = 3;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_300_300))
+ {
+ s->x_resolution = T4_X_RESOLUTION_300;
+ s->y_resolution = T4_Y_RESOLUTION_300;
+ s->current_page_resolution = T4_RESOLUTION_300_300;
+ x = 2;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_200_200))
+ {
+ s->x_resolution = T4_X_RESOLUTION_200;
+ s->y_resolution = T4_Y_RESOLUTION_200;
+ s->current_page_resolution = T4_RESOLUTION_200_200;
+ x = 1;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_100_100))
+ {
+ if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_100_100))
+ {
+ s->x_resolution = T4_X_RESOLUTION_100;
+ s->y_resolution = T4_Y_RESOLUTION_100;
+ s->current_page_resolution = T4_RESOLUTION_100_100;
+ x = 0;
+ }
+ }
}
else
{
- /* Check the bi-level capabilities */
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
- s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE))
- s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T6;
- /* T.85 L0 capable without T.85 capable is an invalid combination, so let
- just zap both capabilities if the far end is not T.85 capable. */
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE))
- s->mutual_compressions &= ~(T30_SUPPORT_COMPRESSION_T85 | T30_SUPPORT_COMPRESSION_T85_L0);
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE))
- s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T85_L0;
+ /* Bi-level image */
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_1200_1200))
+ {
+ s->x_resolution = T4_X_RESOLUTION_1200;
+ s->y_resolution = T4_Y_RESOLUTION_1200;
+ s->current_page_resolution = T4_RESOLUTION_1200_1200;
+ x = 5;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_1200))
+ {
+ s->x_resolution = T4_X_RESOLUTION_600;
+ s->y_resolution = T4_Y_RESOLUTION_1200;
+ s->current_page_resolution = T4_RESOLUTION_600_1200;
+ x = 4;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_600))
+ {
+ s->x_resolution = T4_X_RESOLUTION_600;
+ s->y_resolution = T4_Y_RESOLUTION_600;
+ s->current_page_resolution = T4_RESOLUTION_600_600;
+ x = 4;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_800))
+ {
+ s->x_resolution = T4_X_RESOLUTION_400;
+ s->y_resolution = T4_Y_RESOLUTION_800;
+ s->current_page_resolution = T4_RESOLUTION_400_800;
+ x = 3;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400))
+ {
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_400))
+ {
+ s->x_resolution = T4_X_RESOLUTION_400;
+ s->y_resolution = T4_Y_RESOLUTION_400;
+ s->current_page_resolution = T4_RESOLUTION_400_400;
+ x = 3;
+ }
+ }
+ else
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R16_SUPERFINE))
+ {
+ s->x_resolution = T4_X_RESOLUTION_R16;
+ s->y_resolution = T4_Y_RESOLUTION_SUPERFINE;
+ s->current_page_resolution = T4_RESOLUTION_R16_SUPERFINE;
+ x = 3;
+ }
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_600))
+ {
+ s->x_resolution = T4_X_RESOLUTION_300;
+ s->y_resolution = T4_Y_RESOLUTION_600;
+ s->current_page_resolution = T4_RESOLUTION_300_600;
+ x = 2;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_300))
+ {
+ s->x_resolution = T4_X_RESOLUTION_300;
+ s->y_resolution = T4_Y_RESOLUTION_300;
+ s->current_page_resolution = T4_RESOLUTION_300_300;
+ x = 2;
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_400))
+ {
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_400))
+ {
+ s->x_resolution = T4_X_RESOLUTION_200;
+ s->y_resolution = T4_Y_RESOLUTION_400;
+ s->current_page_resolution = T4_RESOLUTION_200_400;
+ x = 1;
+ }
+ }
+ else
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE))
+ {
+ s->x_resolution = T4_X_RESOLUTION_R8;
+ s->y_resolution = T4_Y_RESOLUTION_SUPERFINE;
+ s->current_page_resolution = T4_RESOLUTION_R8_SUPERFINE;
+ x = 1;
+ }
+ }
+ }
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200))
+ {
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200))
+ {
+ s->x_resolution = T4_X_RESOLUTION_200;
+ s->y_resolution = T4_Y_RESOLUTION_200;
+ s->current_page_resolution = T4_RESOLUTION_200_200;
+ x = 1;
+ }
+ }
+ else
+ {
+ if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_FINE))
+ {
+ s->x_resolution = T4_X_RESOLUTION_R8;
+ s->y_resolution = T4_Y_RESOLUTION_FINE;
+ s->current_page_resolution = T4_RESOLUTION_R8_FINE;
+ x = 1;
+ }
+ }
+ }
+ else
+ {
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
+ {
+ s->x_resolution = T4_X_RESOLUTION_200;
+ s->y_resolution = T4_Y_RESOLUTION_100;
+ s->current_page_resolution = T4_RESOLUTION_200_100;
+ x = 1;
+ }
+ else
+ {
+ s->x_resolution = T4_X_RESOLUTION_R8;
+ s->y_resolution = T4_Y_RESOLUTION_STANDARD;
+ s->current_page_resolution = T4_RESOLUTION_R8_STANDARD;
+ x = 1;
+ }
+ }
}
- /* Choose a compression scheme from amongst those mutually available */
- if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85_L0))
- s->line_encoding = T4_COMPRESSION_T85_L0;
- else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85))
- s->line_encoding = T4_COMPRESSION_T85;
- else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T6))
- s->line_encoding = T4_COMPRESSION_T6;
- else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T4_2D))
- s->line_encoding = T4_COMPRESSION_T4_2D;
- else
- s->line_encoding = T4_COMPRESSION_T4_1D;
+ if (x < 0)
+ {
+ t30_set_status(s, T30_ERR_NORESSUPPORT);
+ return -1;
+ }
- span_log(&s->logging, SPAN_LOG_FLOW, "Choose compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
+ s->image_width = widths[x][dcs_frame[5] & (DISBIT2 | DISBIT1)];
- s->mutual_bilevel_resolutions = s->supported_bilevel_resolutions;
- s->mutual_colour_resolutions = s->supported_colour_resolutions;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE))
+ /* Check which compression the far end has decided to use. */
+#if defined(SPANDSP_SUPPORT_T42)
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
{
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
+ s->line_encoding = T4_COMPRESSION_T42_T81;
}
else
+#endif
+#if defined(SPANDSP_SUPPORT_T43)
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_1200_1200_CAPABLE))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_1200_1200;
- }
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_600_1200;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE))
- {
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
+ s->line_encoding = T4_COMPRESSION_T43;
}
else
+#endif
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE))
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_600_600_CAPABLE))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_600_600;
+ s->line_encoding = T4_COMPRESSION_T85_L0;
}
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_400_800;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE))
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE))
{
- s->mutual_bilevel_resolutions &= ~(T4_SUPPORT_RESOLUTION_400_400 | T4_SUPPORT_RESOLUTION_R16_SUPERFINE);
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_400_400;
+ s->line_encoding = T4_COMPRESSION_T85;
}
- else
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE))
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_400_400;
+ s->line_encoding = T4_COMPRESSION_T6;
}
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_300_600;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE))
+ else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE))
{
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
+ s->line_encoding = T4_COMPRESSION_T4_2D;
}
else
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_300_300;
- }
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
- {
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_400;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_R8_SUPERFINE;
+ s->line_encoding = T4_COMPRESSION_T4_1D;
}
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
+ span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
+ if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT))
+ span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n");
+
+ if ((s->current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0)
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_R8_FINE;
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
+ span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n");
+ return -1;
}
- else
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int step_fallback_entry(t30_state_t *s)
+{
+ int min_row_bits;
+
+ while (fallback_sequence[++s->current_fallback].which)
{
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_200_200;
+ if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems))
+ break;
}
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
- s->mutual_bilevel_resolutions &= ~T4_SUPPORT_RESOLUTION_200_100;
- /* Never suppress T4_SUPPORT_RESOLUTION_R8_STANDARD */
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE))
- s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_100_100;
+ if (fallback_sequence[s->current_fallback].which == 0)
+ return -1;
+ /* TODO: This only sets the minimum row time for future pages. It doesn't fix up the
+ current page, though it is benign - fallback will only result in an excessive
+ minimum. */
+ min_row_bits = set_min_scan_time_code(s);
+ t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits);
+ /* We need to rebuild the DCS message we will send. */
+ build_dcs(s);
+ return s->current_fallback;
+}
+/*- End of function --------------------------------------------------------*/
- s->mutual_image_sizes = s->supported_image_sizes;
- /* 215mm wide is always supported */
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE))
- {
- s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_303MM;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE))
- s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_255MM;
- }
- /* A4 is always supported. */
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE))
+static void send_dcn(t30_state_t *s)
+{
+ queue_phase(s, T30_PHASE_D_TX);
+ set_state(s, T30_STATE_C);
+ send_simple_frame(s, T30_DCN);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void return_to_phase_b(t30_state_t *s, int with_fallback)
+{
+ /* This is what we do after things like T30_EOM is exchanged. */
+ if (s->calling_party)
+ set_state(s, T30_STATE_T);
+ else
+ set_state(s, T30_STATE_R);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int send_dis_or_dtc_sequence(t30_state_t *s, int start)
+{
+ /* (NSF) (CSI) DIS */
+ /* (NSC) (CIG) (PWD) (SEP) (PSA) (CIA) (ISP) DTC */
+ if (start)
{
- s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_UNLIMITED;
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE))
- s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4;
+ set_dis_or_dtc(s);
+ set_state(s, T30_STATE_R);
+ s->step = 0;
}
- if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE))
- s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LETTER;
- if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE))
- s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LEGAL;
-
- switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
+ if (!s->dis_received)
{
- case (DISBIT6 | DISBIT4 | DISBIT3):
- if ((s->supported_modems & T30_SUPPORT_V17))
- {
- s->current_permitted_modems = T30_SUPPORT_V17 | T30_SUPPORT_V29 | T30_SUPPORT_V27TER;
- s->current_fallback = T30_V17_FALLBACK_START;
- break;
- }
- /* Fall through */
- case (DISBIT4 | DISBIT3):
- if ((s->supported_modems & T30_SUPPORT_V29))
+ /* DIS sequence */
+ switch (s->step)
{
- s->current_permitted_modems = T30_SUPPORT_V29 | T30_SUPPORT_V27TER;
- s->current_fallback = T30_V29_FALLBACK_START;
+ case 0:
+ s->step++;
+ if (send_nsf_frame(s))
+ break;
+ /* Fall through */
+ case 1:
+ s->step++;
+ if (send_ident_frame(s, T30_CSI))
+ break;
+ /* Fall through */
+ case 2:
+ s->step++;
+ prune_dis_dtc(s);
+ send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
break;
- }
- /* Fall through */
- case DISBIT4:
- s->current_permitted_modems = T30_SUPPORT_V27TER;
- s->current_fallback = T30_V27TER_FALLBACK_START;
- break;
- case 0:
- s->current_permitted_modems = T30_SUPPORT_V27TER;
- s->current_fallback = T30_V27TER_FALLBACK_START + 1;
- break;
- case DISBIT3:
- if ((s->supported_modems & T30_SUPPORT_V29))
- {
- /* TODO: this doesn't allow for skipping the V.27ter modes */
- s->current_permitted_modems = T30_SUPPORT_V29;
- s->current_fallback = T30_V29_FALLBACK_START;
+ case 3:
+ s->step++;
+ shut_down_hdlc_tx(s);
break;
- }
- /* Fall through */
- default:
- span_log(&s->logging, SPAN_LOG_FLOW, "Remote does not support a compatible modem\n");
- /* We cannot talk to this machine! */
- t30_set_status(s, T30_ERR_INCOMPATIBLE);
- return -1;
- }
- if (s->phase_b_handler)
- {
- new_status = s->phase_b_handler(s, s->phase_b_user_data, msg[2]);
- if (new_status != T30_ERR_OK)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Application rejected DIS/DTC - '%s'\n", t30_completion_code_to_str(new_status));
- t30_set_status(s, new_status);
- /* TODO: If FNV is allowed, process it here */
- send_dcn(s);
- return -1;
- }
- }
- queue_phase(s, T30_PHASE_B_TX);
- /* Try to send something */
- if (s->tx_file[0])
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Trying to send file '%s'\n", s->tx_file);
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT))
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot receive\n", t30_frametype(msg[2]));
- t30_set_status(s, T30_ERR_RX_INCAPABLE);
- send_dcn(s);
- }
- if (start_sending_document(s))
- {
- send_dcn(s);
- return -1;
- }
- if (build_dcs(s))
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "The far end is incompatible\n", s->tx_file);
- send_dcn(s);
+ default:
return -1;
}
- s->retries = 0;
- send_dcs_sequence(s, TRUE);
- return 0;
}
- span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to send\n", t30_frametype(msg[2]));
- /* ... then try to receive something */
- if (s->rx_file[0])
+ else
{
- span_log(&s->logging, SPAN_LOG_FLOW, "Trying to receive file '%s'\n", s->rx_file);
- if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT))
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot transmit\n", t30_frametype(msg[2]));
- t30_set_status(s, T30_ERR_TX_INCAPABLE);
- send_dcn(s);
- return -1;
- }
- if (start_receiving_document(s))
- {
- send_dcn(s);
- return -1;
- }
- if (set_dis_or_dtc(s))
+ /* DTC sequence */
+ switch (s->step)
{
- t30_set_status(s, T30_ERR_INCOMPATIBLE);
- send_dcn(s);
+ case 0:
+ s->step++;
+ if (send_nsc_frame(s))
+ break;
+ /* Fall through */
+ case 1:
+ s->step++;
+ if (send_ident_frame(s, T30_CIG))
+ break;
+ /* Fall through */
+ case 2:
+ s->step++;
+ if (send_pwd_frame(s))
+ break;
+ /* Fall through */
+ case 3:
+ s->step++;
+ if (send_sep_frame(s))
+ break;
+ /* Fall through */
+ case 4:
+ s->step++;
+ if (send_psa_frame(s))
+ break;
+ /* Fall through */
+ case 5:
+ s->step++;
+ if (send_cia_frame(s))
+ break;
+ /* Fall through */
+ case 6:
+ s->step++;
+ if (send_isp_frame(s))
+ break;
+ /* Fall through */
+ case 7:
+ s->step++;
+ prune_dis_dtc(s);
+ send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len);
+ break;
+ case 8:
+ s->step++;
+ shut_down_hdlc_tx(s);
+ break;
+ default:
return -1;
}
- s->retries = 0;
- send_dis_or_dtc_sequence(s, TRUE);
- return 0;
}
- span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to receive\n", t30_frametype(msg[2]));
- /* There is nothing to do, or nothing we are able to do. */
- send_dcn(s);
- return -1;
+ return 0;
}
/*- End of function --------------------------------------------------------*/
-static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
+static int send_dcs_sequence(t30_state_t *s, int start)
{
- static const int widths[6][4] =
- {
- { T4_WIDTH_100_A4, T4_WIDTH_100_B4, T4_WIDTH_100_A3, -1}, /* 100/inch */
- { T4_WIDTH_200_A4, T4_WIDTH_200_B4, T4_WIDTH_200_A3, -1}, /* 200/inch / R8 resolution */
- { T4_WIDTH_300_A4, T4_WIDTH_300_B4, T4_WIDTH_300_A3, -1}, /* 300/inch resolution */
- { T4_WIDTH_400_A4, T4_WIDTH_400_B4, T4_WIDTH_400_A3, -1}, /* 400/inch / R16 resolution */
- { T4_WIDTH_600_A4, T4_WIDTH_600_B4, T4_WIDTH_600_A3, -1}, /* 600/inch resolution */
- {T4_WIDTH_1200_A4, T4_WIDTH_1200_B4, T4_WIDTH_1200_A3, -1} /* 1200/inch resolution */
- };
- uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN];
- int i;
- int x;
- int new_status;
-
- t30_decode_dis_dtc_dcs(s, msg, len);
-
- /* Check DCS frame from remote */
- if (len < 6)
+ /* (NSS) (TSI) (SUB) (SID) (TSA) (IRA) DCS */
+ /* Schedule training after the messages */
+ if (start)
{
- span_log(&s->logging, SPAN_LOG_FLOW, "Short DCS frame\n");
- return -1;
+ prune_dcs(s);
+ set_state(s, T30_STATE_D);
+ s->step = 0;
}
-
- /* Make an ASCII string format copy of the message, for logging in the
- received file. This string does not include the frame header octets. */
- sprintf(s->rx_dcs_string, "%02X", bit_reverse8(msg[3]));
- for (i = 4; i < len; i++)
- sprintf(s->rx_dcs_string + 3*i - 10, " %02X", bit_reverse8(msg[i]));
- /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows
- us to simply pick out the bits, without worrying about whether they were set from the remote side. */
- if (len > T30_MAX_DIS_DTC_DCS_LEN)
- {
- memcpy(dcs_frame, msg, T30_MAX_DIS_DTC_DCS_LEN);
- }
- else
+ switch (s->step)
{
- memcpy(dcs_frame, msg, len);
- if (len < T30_MAX_DIS_DTC_DCS_LEN)
- memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len);
+ case 0:
+ s->step++;
+ if (send_nss_frame(s))
+ break;
+ /* Fall through */
+ case 1:
+ s->step++;
+ if (send_ident_frame(s, T30_TSI))
+ break;
+ /* Fall through */
+ case 2:
+ s->step++;
+ if (send_sub_frame(s))
+ break;
+ /* Fall through */
+ case 3:
+ s->step++;
+ if (send_sid_frame(s))
+ break;
+ /* Fall through */
+ case 4:
+ s->step++;
+ if (send_tsa_frame(s))
+ break;
+ /* Fall through */
+ case 5:
+ s->step++;
+ if (send_ira_frame(s))
+ break;
+ /* Fall through */
+ case 6:
+ s->step++;
+ prune_dcs(s);
+ send_frame(s, s->dcs_frame, s->dcs_len);
+ break;
+ case 7:
+ s->step++;
+ shut_down_hdlc_tx(s);
+ break;
+ default:
+ return -1;
}
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
- s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, T30_DCS_BIT_64_OCTET_ECM_FRAMES) ? 256 : 64;
-
- s->x_resolution = -1;
- s->y_resolution = -1;
- s->current_page_resolution = 0;
- x = -1;
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
- {
- /* Gray scale or colour image */
-
- /* Note 35 of Table 2/T.30 */
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
- {
- /* We are going to work in full colour mode */
- }
+static int send_cfr_sequence(t30_state_t *s, int start)
+{
+ /* (CSA) CFR */
+ /* CFR is usually a simple frame, but can become a sequence with Internet
+ FAXing. */
+ send_simple_frame(s, T30_CFR);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT))
- {
- /* We are going to work in 12 bit mode */
- }
+static void disconnect(t30_state_t *s)
+{
+ span_log(&s->logging, SPAN_LOG_FLOW, "Disconnecting\n");
+ /* Make sure any FAX in progress is tidied up. If the tidying up has
+ already happened, repeating it here is harmless. */
+ terminate_operation_in_progress(s);
+ s->timer_t0_t1 = 0;
+ s->timer_t2_t4 = 0;
+ s->timer_t3 = 0;
+ s->timer_t5 = 0;
+ set_phase(s, T30_PHASE_E);
+ set_state(s, T30_STATE_B);
+}
+/*- End of function --------------------------------------------------------*/
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING))
- {
- //???? = T30_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING;
- }
+static int set_min_scan_time_code(t30_state_t *s)
+{
+ /* Translation between the codes for the minimum scan times the other end needs,
+ and the codes for what we say will be used. We need 0 minimum. */
+ static const uint8_t translate_min_scan_time[3][8] =
+ {
+ {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_0MS}, /* normal */
+ {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS}, /* fine */
+ {T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS} /* superfine, when half fine time is selected */
+ };
+ /* Translation between the codes for the minimum scan time we will use, and milliseconds. */
+ static const int min_scan_times[8] =
+ {
+ 20, 5, 10, 0, 40, 0, 0, 0
+ };
+ int min_bits_field;
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_1200_1200))
- {
- s->x_resolution = T4_X_RESOLUTION_1200;
- s->y_resolution = T4_Y_RESOLUTION_1200;
- s->current_page_resolution = T4_RESOLUTION_1200_1200;
- x = 5;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_600_600))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_600_600))
- {
- s->x_resolution = T4_X_RESOLUTION_600;
- s->y_resolution = T4_Y_RESOLUTION_600;
- s->current_page_resolution = T4_RESOLUTION_600_600;
- x = 4;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_400_400))
- {
- s->x_resolution = T4_X_RESOLUTION_400;
- s->y_resolution = T4_Y_RESOLUTION_400;
- s->current_page_resolution = T4_RESOLUTION_400_400;
- x = 3;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_300_300))
- {
- s->x_resolution = T4_X_RESOLUTION_300;
- s->y_resolution = T4_Y_RESOLUTION_300;
- s->current_page_resolution = T4_RESOLUTION_300_300;
- x = 2;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_200_200))
- {
- s->x_resolution = T4_X_RESOLUTION_200;
- s->y_resolution = T4_Y_RESOLUTION_200;
- s->current_page_resolution = T4_RESOLUTION_200_200;
- x = 1;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_100_100))
- {
- if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_100_100))
- {
- s->x_resolution = T4_X_RESOLUTION_100;
- s->y_resolution = T4_Y_RESOLUTION_100;
- s->current_page_resolution = T4_RESOLUTION_100_100;
- x = 0;
- }
- }
- }
+ /* Set the minimum scan time bits */
+ if (s->error_correcting_mode)
+ min_bits_field = T30_MIN_SCAN_0MS;
else
- {
- /* Bi-level image */
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_1200_1200))
- {
- s->x_resolution = T4_X_RESOLUTION_1200;
- s->y_resolution = T4_Y_RESOLUTION_1200;
- s->current_page_resolution = T4_RESOLUTION_1200_1200;
- x = 5;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_1200))
- {
- s->x_resolution = T4_X_RESOLUTION_600;
- s->y_resolution = T4_Y_RESOLUTION_1200;
- s->current_page_resolution = T4_RESOLUTION_600_1200;
- x = 4;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_600))
- {
- s->x_resolution = T4_X_RESOLUTION_600;
- s->y_resolution = T4_Y_RESOLUTION_600;
- s->current_page_resolution = T4_RESOLUTION_600_600;
- x = 4;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_800))
- {
- s->x_resolution = T4_X_RESOLUTION_400;
- s->y_resolution = T4_Y_RESOLUTION_800;
- s->current_page_resolution = T4_RESOLUTION_400_800;
- x = 3;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400))
- {
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_400))
- {
- s->x_resolution = T4_X_RESOLUTION_400;
- s->y_resolution = T4_Y_RESOLUTION_400;
- s->current_page_resolution = T4_RESOLUTION_400_400;
- x = 3;
- }
- }
- else
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R16_SUPERFINE))
- {
- s->x_resolution = T4_X_RESOLUTION_R16;
- s->y_resolution = T4_Y_RESOLUTION_SUPERFINE;
- s->current_page_resolution = T4_RESOLUTION_R16_SUPERFINE;
- x = 3;
- }
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_600))
- {
- s->x_resolution = T4_X_RESOLUTION_300;
- s->y_resolution = T4_Y_RESOLUTION_600;
- s->current_page_resolution = T4_RESOLUTION_300_600;
- x = 2;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_300))
- {
- s->x_resolution = T4_X_RESOLUTION_300;
- s->y_resolution = T4_Y_RESOLUTION_300;
- s->current_page_resolution = T4_RESOLUTION_300_300;
- x = 2;
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_400))
- {
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_400))
- {
- s->x_resolution = T4_X_RESOLUTION_200;
- s->y_resolution = T4_Y_RESOLUTION_400;
- s->current_page_resolution = T4_RESOLUTION_200_400;
- x = 1;
- }
- }
- else
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE))
- {
- s->x_resolution = T4_X_RESOLUTION_R8;
- s->y_resolution = T4_Y_RESOLUTION_SUPERFINE;
- s->current_page_resolution = T4_RESOLUTION_R8_SUPERFINE;
- x = 1;
- }
- }
- }
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200))
- {
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200))
- {
- s->x_resolution = T4_X_RESOLUTION_200;
- s->y_resolution = T4_Y_RESOLUTION_200;
- s->current_page_resolution = T4_RESOLUTION_200_200;
- x = 1;
- }
- }
- else
- {
- if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_FINE))
- {
- s->x_resolution = T4_X_RESOLUTION_R8;
- s->y_resolution = T4_Y_RESOLUTION_FINE;
- s->current_page_resolution = T4_RESOLUTION_R8_FINE;
- x = 1;
- }
- }
+ min_bits_field = (s->far_dis_dtc_frame[5] >> 4) & 7;
+ switch (s->y_resolution)
+ {
+ case T4_Y_RESOLUTION_SUPERFINE:
+ if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
+ {
+ s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field];
+ break;
}
- else
+ span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n");
+ /* Fall through */
+ case T4_Y_RESOLUTION_FINE:
+ if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
{
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION))
- {
- s->x_resolution = T4_X_RESOLUTION_200;
- s->y_resolution = T4_Y_RESOLUTION_100;
- s->current_page_resolution = T4_RESOLUTION_200_100;
- x = 1;
- }
- else
- {
- s->x_resolution = T4_X_RESOLUTION_R8;
- s->y_resolution = T4_Y_RESOLUTION_STANDARD;
- s->current_page_resolution = T4_RESOLUTION_R8_STANDARD;
- x = 1;
- }
+ s->min_scan_time_code = translate_min_scan_time[1][min_bits_field];
+ break;
}
+ span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n");
+ /* Fall through */
+ default:
+ case T4_Y_RESOLUTION_STANDARD:
+ s->min_scan_time_code = translate_min_scan_time[0][min_bits_field];
+ break;
}
+ if (!s->error_correcting_mode && (s->iaf & T30_IAF_MODE_NO_FILL_BITS))
+ return 0;
+ return fallback_sequence[s->current_fallback].bit_rate*min_scan_times[s->min_scan_time_code]/1000;
+}
+/*- End of function --------------------------------------------------------*/
- if (x < 0)
+static int start_sending_document(t30_state_t *s)
+{
+ int min_row_bits;
+
+ if (s->tx_file[0] == '\0')
{
- t30_set_status(s, T30_ERR_NORESSUPPORT);
+ /* There is nothing to send */
+ span_log(&s->logging, SPAN_LOG_FLOW, "No document to send\n");
return -1;
}
+ span_log(&s->logging, SPAN_LOG_FLOW, "Start sending document\n");
+ if (t4_tx_init(&s->t4.tx, s->tx_file, s->tx_start_page, s->tx_stop_page) == NULL)
+ {
+ span_log(&s->logging, SPAN_LOG_WARNING, "Cannot open source TIFF file '%s'\n", s->tx_file);
+ t30_set_status(s, T30_ERR_FILEERROR);
+ return -1;
+ }
+ s->operation_in_progress = OPERATION_IN_PROGRESS_T4_TX;
+ t4_tx_get_pages_in_file(&s->t4.tx);
+ t4_tx_set_tx_encoding(&s->t4.tx, s->line_encoding);
+ t4_tx_set_local_ident(&s->t4.tx, s->tx_info.ident);
+ t4_tx_set_header_info(&s->t4.tx, s->header_info);
+ if (s->use_own_tz)
+ t4_tx_set_header_tz(&s->t4.tx, &s->tz);
- s->image_width = widths[x][dcs_frame[5] & (DISBIT2 | DISBIT1)];
-
- /* Check which compression the far end has decided to use. */
-#if defined(SPANDSP_SUPPORT_T42)
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
+ if (tx_start_page(s))
{
- s->line_encoding = T4_COMPRESSION_T42_T81;
+ span_log(&s->logging, SPAN_LOG_WARNING, "Something seems to be wrong in the file\n");
+ t30_set_status(s, T30_ERR_FILEERROR);
+ return -1;
}
- else
-#endif
-#if defined(SPANDSP_SUPPORT_T43)
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
+
+ s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx);
+ s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx);
+ s->image_width = t4_tx_get_image_width(&s->t4.tx);
+ /* The minimum scan time to be used can't be evaluated until we know the Y resolution, and
+ must be evaluated before the minimum scan row bits can be evaluated. */
+ if ((min_row_bits = set_min_scan_time_code(s)) < 0)
{
- s->line_encoding = T4_COMPRESSION_T43;
+ terminate_operation_in_progress(s);
+ return -1;
}
- else
-#endif
- if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE))
+ span_log(&s->logging, SPAN_LOG_FLOW, "Minimum bits per row will be %d\n", min_row_bits);
+ t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits);
+
+ if (s->error_correcting_mode)
{
- s->line_encoding = T4_COMPRESSION_T85_L0;
+ if (get_partial_ecm_page(s) == 0)
+ span_log(&s->logging, SPAN_LOG_WARNING, "No image data to send\n");
}
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE))
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int restart_sending_document(t30_state_t *s)
+{
+ t4_tx_restart_page(&s->t4.tx);
+ s->retries = 0;
+ s->ecm_block = 0;
+ send_dcs_sequence(s, TRUE);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int start_receiving_document(t30_state_t *s)
+{
+ if (s->rx_file[0] == '\0')
{
- s->line_encoding = T4_COMPRESSION_T85;
+ /* There is nothing to receive to */
+ span_log(&s->logging, SPAN_LOG_FLOW, "No document to receive\n");
+ return -1;
}
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE))
+ span_log(&s->logging, SPAN_LOG_FLOW, "Start receiving document\n");
+ queue_phase(s, T30_PHASE_B_TX);
+ s->ecm_block = 0;
+ send_dis_or_dtc_sequence(s, TRUE);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void unexpected_non_final_frame(t30_state_t *s, const uint8_t *msg, int len)
+{
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]);
+ if (s->current_status == T30_ERR_OK)
+ t30_set_status(s, T30_ERR_UNEXPECTED);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void unexpected_final_frame(t30_state_t *s, const uint8_t *msg, int len)
+{
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]);
+ if (s->current_status == T30_ERR_OK)
+ t30_set_status(s, T30_ERR_UNEXPECTED);
+ send_dcn(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void unexpected_frame_length(t30_state_t *s, const uint8_t *msg, int len)
+{
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len);
+ if (s->current_status == T30_ERR_OK)
+ t30_set_status(s, T30_ERR_UNEXPECTED);
+ send_dcn(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
+{
+ int new_status;
+
+ queue_phase(s, T30_PHASE_B_TX);
+ if (analyze_rx_dis_dtc(s, msg, len) < 0)
{
+ send_dcn(s);
+ return -1;
+ }
+
+ /* Choose a compression scheme from amongst those mutually available */
+ if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85_L0))
+ s->line_encoding = T4_COMPRESSION_T85_L0;
+ else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85))
+ s->line_encoding = T4_COMPRESSION_T85;
+ else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T6))
s->line_encoding = T4_COMPRESSION_T6;
+ else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T4_2D))
+ s->line_encoding = T4_COMPRESSION_T4_2D;
+ else
+ s->line_encoding = T4_COMPRESSION_T4_1D;
+
+ span_log(&s->logging, SPAN_LOG_FLOW, "Choose compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
+
+ if (s->phase_b_handler)
+ {
+ new_status = s->phase_b_handler(s, s->phase_b_user_data, msg[2]);
+ if (new_status != T30_ERR_OK)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Application rejected DIS/DTC - '%s'\n", t30_completion_code_to_str(new_status));
+ t30_set_status(s, new_status);
+ /* TODO: If FNV is allowed, process it here */
+ send_dcn(s);
+ return -1;
+ }
}
- else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE))
+ /* Try to send something */
+ if (s->tx_file[0])
{
- s->line_encoding = T4_COMPRESSION_T4_2D;
+ span_log(&s->logging, SPAN_LOG_FLOW, "Trying to send file '%s'\n", s->tx_file);
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot receive\n", t30_frametype(msg[2]));
+ t30_set_status(s, T30_ERR_RX_INCAPABLE);
+ send_dcn(s);
+ return -1;
+ }
+ if (start_sending_document(s))
+ {
+ send_dcn(s);
+ return -1;
+ }
+ if (build_dcs(s))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "The far end is incompatible\n", s->tx_file);
+ send_dcn(s);
+ return -1;
+ }
+ s->retries = 0;
+ send_dcs_sequence(s, TRUE);
+ return 0;
}
- else
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to send\n", t30_frametype(msg[2]));
+ /* ... then try to receive something */
+ if (s->rx_file[0])
{
- s->line_encoding = T4_COMPRESSION_T4_1D;
+ span_log(&s->logging, SPAN_LOG_FLOW, "Trying to receive file '%s'\n", s->rx_file);
+ if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot transmit\n", t30_frametype(msg[2]));
+ t30_set_status(s, T30_ERR_TX_INCAPABLE);
+ send_dcn(s);
+ return -1;
+ }
+ if (start_receiving_document(s))
+ {
+ send_dcn(s);
+ return -1;
+ }
+ if (set_dis_or_dtc(s))
+ {
+ t30_set_status(s, T30_ERR_INCOMPATIBLE);
+ send_dcn(s);
+ return -1;
+ }
+ s->retries = 0;
+ send_dis_or_dtc_sequence(s, TRUE);
+ return 0;
}
- span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
- if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT))
- span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n");
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to receive\n", t30_frametype(msg[2]));
+ /* There is nothing to do, or nothing we are able to do. */
+ send_dcn(s);
+ return -1;
+}
+/*- End of function --------------------------------------------------------*/
- if ((s->current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0)
+static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
+{
+ int new_status;
+
+ if (analyze_rx_dcs(s, msg, len) < 0)
{
- span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n");
+ send_dcn(s);
return -1;
}
- s->error_correcting_mode = (test_ctrl_bit(dcs_frame, T30_DCS_BIT_ECM_MODE) != 0);
if (s->phase_b_handler)
{
s->ppr_count = 0;
s->ecm_progress = 0;
s->receiver_not_ready_count = 0;
- s->far_dis_dtc_len = 0;
memset(&s->far_dis_dtc_frame, 0, sizeof(s->far_dis_dtc_frame));
t30_build_dis_or_dtc(s);
memset(&s->rx_info, 0, sizeof(s->rx_info));
int ptr;
int row;
int bit_mask;
-} t85_packer_t;
+} packer_t;
typedef struct
{
}
/*- End of function --------------------------------------------------------*/
-static int t85_row_write_handler(void *user_data, const uint8_t buf[], size_t len)
+static int packing_row_write_handler(void *user_data, const uint8_t buf[], size_t len)
{
- t85_packer_t *s;
+ packer_t *s;
- s = (t85_packer_t *) user_data;
+ s = (packer_t *) user_data;
memcpy(&s->buf[s->ptr], buf, len);
s->ptr += len;
s->row++;
}
/*- End of function --------------------------------------------------------*/
-static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len)
+static int embedded_comment_handler(void *user_data, const uint8_t buf[], size_t len)
{
t4_tx_state_t *s;
}
/*- End of function --------------------------------------------------------*/
-static int read_tiff_image(t4_tx_state_t *s)
+static int read_tiff_t85_image(t4_tx_state_t *s)
{
+ int biggest;
+ int num_strips;
int total_len;
int len;
- int biggest;
int i;
- int num_strips;
int result;
uint8_t *t;
uint8_t *raw_data;
t85_decode_state_t t85;
- t85_packer_t t85_pack;
+ packer_t pack;
+
+ /* Size up and allocate the buffer for the raw data */
+ num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
+ biggest = TIFFRawStripSize(s->tiff.tiff_file, 0);
+ for (i = 1; i < num_strips; i++)
+ {
+ len = TIFFRawStripSize(s->tiff.tiff_file, i);
+ if (len > biggest)
+ biggest = len;
+ }
+ if ((raw_data = malloc(biggest)) == NULL)
+ return -1;
+
+ s->tiff.image_size = s->image_length*((s->image_width + 7)/8);
+ if (s->tiff.image_size >= s->tiff.image_buffer_size)
+ {
+ if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ return -1;
+ s->tiff.image_buffer_size = s->tiff.image_size;
+ s->tiff.image_buffer = t;
+ }
+
+ pack.buf = s->tiff.image_buffer;
+ pack.ptr = 0;
+ pack.row = 0;
+ t85_decode_init(&t85, packing_row_write_handler, &pack);
+ t85_decode_set_comment_handler(&t85, 1000, embedded_comment_handler, s);
+
+ total_len = 0;
+ result = -1;
+ for (i = 0; i < num_strips; i++, total_len += len)
+ {
+ len = TIFFRawStripSize(s->tiff.tiff_file, i);
+ if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, raw_data, len)) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_WARNING, "%s: ReadRaw error.\n", s->tiff.file);
+ return -1;
+ }
+ result = t85_decode_put(&t85, raw_data, len);
+ if (result != T4_DECODE_MORE_DATA)
+ break;
+ }
+ if (result == T4_DECODE_MORE_DATA)
+ result = t85_decode_put(&t85, NULL, 0);
+
+ len = t85_decode_get_compressed_image_size(&t85);
+ span_log(&s->logging, SPAN_LOG_WARNING, "Compressed image is %d bytes, %d rows\n", len/8, s->image_length);
+ t85_decode_release(&t85);
+ free(raw_data);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+#if defined(SPANDSP_SUPPORT_T43)
+static int read_tiff_t43_image(t4_tx_state_t *s, uint8_t **buf)
+{
+ int num_strips;
+ int total_len;
+ int len;
+ int i;
+ int total_image_len;
+ int image_size;
+ logging_state_t *logging;
+ uint8_t *raw_data;
+ t43_decode_state_t t43;
+ packer_t pack;
+
+ num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
+ total_image_len = 0;
+ for (i = 0; i < num_strips; i++)
+ total_image_len += TIFFRawStripSize(s->tiff.tiff_file, i);
+ if ((raw_data = malloc(total_image_len)) == NULL)
+ return -1;
+
+ total_len = 0;
+ for (i = 0; i < num_strips; i++, total_len += len)
+ {
+ if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, &raw_data[total_len], total_image_len - total_len)) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "TIFF read error.\n");
+ return -1;
+ }
+ }
+
+ t43_decode_init(&t43, packing_row_write_handler, &pack);
+ t43_decode_set_comment_handler(&t43, 1000, embedded_comment_handler, NULL);
+ logging = t43_decode_get_logging_state(&t43);
+ span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+
+ image_size = 3*s->image_length*s->image_width;
+ if ((*buf = malloc(image_size)) == NULL)
+ return -1;
+
+ pack.buf = *buf;
+ pack.ptr = 0;
+ pack.row = 0;
+ t43_decode_put(&t43, raw_data, total_len);
+ t43_decode_release(&t43);
+ free(raw_data);
+ return image_size;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+#if 0
+static int read_tiff_t42_t81_image(t4_tx_state_t *s, uint8_t **buf)
+{
+ int total_len;
+ int len;
+ int i;
+ int num_strips;
+ int total_image_len;
+ int image_size;
+ uint8_t *raw_data;
+ uint8_t *jpeg_table;
+ uint32_t jpeg_table_len;
+ uint32_t w;
+ uint32_t h;
+ tsize_t off;
+
+ num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
+ total_image_len = 0;
+ jpeg_table_len = 0;
+ if (TIFFGetField(s->tiff.tiff_file, TIFFTAG_JPEGTABLES, &jpeg_table_len, &jpeg_table))
+ {
+ total_image_len += (jpeg_table_len - 4);
+ span_log(&s->logging, SPAN_LOG_FLOW, "JPEG tables %u\n", jpeg_table_len);
+ }
+
+ for (i = 0; i < num_strips; i++)
+ total_image_len += TIFFRawStripSize(s->tiff.tiff_file, i);
+ if ((raw_data = malloc(total_image_len)) == NULL)
+ return -1;
+
+ total_len = 0;
+ if (jpeg_table_len > 0)
+ total_len += jpeg_table_len - 4;
+ for (i = 0; i < num_strips; i++, total_len += len)
+ {
+ if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, &raw_data[total_len], total_image_len - total_len)) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "TIFF read error.\n");
+ return -1;
+ }
+ }
+ if (jpeg_table_len > 0)
+ memcpy(raw_data, jpeg_table, jpeg_table_len - 2);
+
+ if (total_len != total_image_len)
+ span_log(&s->logging, SPAN_LOG_FLOW, "Size mismatch %d %d\n", (int) total_len, (int) total_image_len);
+
+ image_size = 3*s->image_length*s->image_width;
+ if ((*buf = malloc(image_size)) == NULL)
+ return -1;
+
+ off = 0;
+ if (!t42_itulab_to_srgb(&s->logging, &s->lab_params, *buf, &off, raw_data, total_image_len, &w, &h))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n");
+ return -1;
+ }
+ free(raw_data);
+ return image_size;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+static int read_tiff_decompressed_image(t4_tx_state_t *s)
+{
+ int total_len;
+ int len;
+ int num_strips;
+ int i;
+ uint8_t *t;
+
+ /* Decode the whole image into a buffer */
+ /* Let libtiff handle the decompression */
+ s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
+ if (s->tiff.image_size >= s->tiff.image_buffer_size)
+ {
+ if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ return -1;
+ s->tiff.image_buffer_size = s->tiff.image_size;
+ s->tiff.image_buffer = t;
+ }
+
+ /* Allow for the image being stored in multiple strips, although it is rare to find
+ a stripped image in a T.4 or T.6 encoded file. */
+ num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
+ for (i = 0, total_len = 0; i < num_strips; i++, total_len += len)
+ {
+ if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
+ return -1;
+ }
+ }
+ /* We might need to flip all the bits, so 1 = black and 0 = white. */
+ if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file);
+ for (i = 0; i < s->tiff.image_size; i++)
+ s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i];
+ s->tiff.photo_metric = PHOTOMETRIC_MINISWHITE;
+ }
+ /* We might need to bit reverse each of the bytes of the image. */
+ if (s->tiff.fill_order != FILLORDER_LSB2MSB)
+ bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size);
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int read_tiff_image(t4_tx_state_t *s)
+{
+ int total_len;
+ int i;
+ uint8_t *t;
image_translate_state_t *translator;
if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL)
case COMPRESSION_T85:
/* Decode the whole image into a buffer */
/* libtiff probably cannot decompress T.85, so we must handle it ourselves */
- /* Size up and allocate the buffer for the raw data */
- num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
- biggest = TIFFRawStripSize(s->tiff.tiff_file, 0);
- for (i = 1; i < num_strips; i++)
- {
- len = TIFFRawStripSize(s->tiff.tiff_file, i);
- if (len > biggest)
- biggest = len;
- }
- if ((raw_data = malloc(biggest)) == NULL)
+ /* Decode the whole image into a buffer */
+ if (read_tiff_t85_image(s) < 0)
return -1;
-
- s->tiff.image_size = s->image_length*((s->image_width + 7)/8);
- if (s->tiff.image_size >= s->tiff.image_buffer_size)
- {
- if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
- return -1;
- s->tiff.image_buffer_size = s->tiff.image_size;
- s->tiff.image_buffer = t;
- }
-
- t85_pack.buf = s->tiff.image_buffer;
- t85_pack.ptr = 0;
- t85_pack.row = 0;
- t85_decode_init(&t85, t85_row_write_handler, &t85_pack);
- t85_decode_set_comment_handler(&t85, 1000, t85_comment_handler, s);
-
- total_len = 0;
- result = -1;
- for (i = 0; i < num_strips; i++, total_len += len)
- {
- len = TIFFRawStripSize(s->tiff.tiff_file, i);
- if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, raw_data, len)) < 0)
- {
- span_log(&s->logging, SPAN_LOG_WARNING, "%s: ReadRaw error.\n", s->tiff.file);
- return -1;
- }
- result = t85_decode_put(&t85, raw_data, len);
- if (result != T4_DECODE_MORE_DATA)
- break;
- }
- if (result == T4_DECODE_MORE_DATA)
- result = t85_decode_put(&t85, NULL, 0);
-
- len = t85_decode_get_compressed_image_size(&t85);
- span_log(&s->logging, SPAN_LOG_WARNING, "Compressed image is %d bytes, %d rows\n", len/8, s->image_length);
- t85_decode_release(&t85);
- free(raw_data);
break;
default:
/* Decode the whole image into a buffer */
/* Let libtiff handle the decompression */
- s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
- if (s->tiff.image_size >= s->tiff.image_buffer_size)
- {
- if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
- return -1;
- s->tiff.image_buffer_size = s->tiff.image_size;
- s->tiff.image_buffer = t;
- }
-
- /* Allow for the image being stored in multiple strips, although it is rare to find
- a stripped image in a T.4 or T.6 encoded file. */
- num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
- for (i = 0, total_len = 0; i < num_strips; i++, total_len += len)
- {
- if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
- {
- span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
- return -1;
- }
- }
- /* We might need to flip all the bits, so 1 = black and 0 = white. */
- if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file);
- for (i = 0; i < s->tiff.image_size; i++)
- s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i];
- s->tiff.photo_metric = PHOTOMETRIC_MINISWHITE;
- }
- /* We might need to bit reverse each of the bytes of the image. */
- if (s->tiff.fill_order != FILLORDER_LSB2MSB)
- bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size);
+ if (read_tiff_decompressed_image(s) < 0)
+ return -1;
break;
}
}
case T4_COMPRESSION_T85:
case T4_COMPRESSION_T85_L0:
return t85_encode_set_row_read_handler(&s->encoder.t85, handler, user_data);
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
return t42_encode_set_row_read_handler(&s->encoder.t42, handler, user_data);
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
return t43_encode_set_row_read_handler(&s->encoder.t43, handler, user_data);
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
return -1;
}
s->line_encoding = encoding;
return s->line_encoding;
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ switch (s->line_encoding)
+ {
+ case T4_COMPRESSION_T88:
+ break;
+ default:
+ break;
+ }
+ s->line_encoding = encoding;
+ return s->line_encoding;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
switch (s->line_encoding)
{
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
break;
default:
t42_encode_init(&s->encoder.t42, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
}
s->line_encoding = encoding;
return s->line_encoding;
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ switch (s->line_encoding)
+ {
+ case T4_COMPRESSION_T45:
+ break;
+ default:
+ break;
+ }
+ s->line_encoding = encoding;
+ return s->line_encoding;
#endif
}
}
case T4_COMPRESSION_T85_L0:
t85_encode_set_image_width(&s->encoder.t85, image_width);
break;
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
t42_encode_set_image_width(&s->encoder.t42, image_width);
break;
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
t43_encode_set_image_width(&s->encoder.t43, image_width);
break;
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
}
case T4_COMPRESSION_T85_L0:
t85_encode_set_image_length(&s->encoder.t85, image_length);
break;
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
t42_encode_set_image_length(&s->encoder.t42, image_length);
break;
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
t43_encode_set_image_length(&s->encoder.t43, image_length);
break;
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
}
t->length = t85_encode_get_image_length(&s->encoder.t85)/s->row_squashing_ratio;
t->line_image_size = t85_encode_get_compressed_image_size(&s->encoder.t85)/8;
break;
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
t->type = 0;
t->width = t42_encode_get_image_width(&s->encoder.t42);
t->length = t42_encode_get_image_length(&s->encoder.t42)/s->row_squashing_ratio;
t->length = t43_encode_get_image_length(&s->encoder.t43)/s->row_squashing_ratio;
t->line_image_size = t43_encode_get_compressed_image_size(&s->encoder.t43)/8;
break;
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
}
case T4_COMPRESSION_T85:
case T4_COMPRESSION_T85_L0:
return t85_encode_image_complete(&s->encoder.t85);
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
return t42_encode_image_complete(&s->encoder.t42);
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
return t43_encode_image_complete(&s->encoder.t43);
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
return SIG_STATUS_END_OF_DATA;
case T4_COMPRESSION_T85:
case T4_COMPRESSION_T85_L0:
return t85_encode_get(&s->encoder.t85, buf, max_len);
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
return t42_encode_get(&s->encoder.t42, buf, max_len);
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
return t43_encode_get(&s->encoder.t43, buf, max_len);
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
return 0;
case T4_COMPRESSION_T85_L0:
t85_encode_restart(&s->encoder.t85, s->image_width, s->image_length);
break;
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
t42_encode_restart(&s->encoder.t42, s->image_width, s->image_length);
break;
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
t43_encode_restart(&s->encoder.t43, s->image_width, s->image_length);
break;
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
/* If there is a page header, create that first */
case T4_COMPRESSION_T85:
case T4_COMPRESSION_T85_L0:
return t85_encode_release(&s->encoder.t85);
+#if defined(SPANDSP_SUPPORT_T88)
+ case T4_COMPRESSION_T88:
+ break;
+#endif
case T4_COMPRESSION_T42_T81:
+ case T4_COMPRESSION_SYCC_T81:
return t42_encode_release(&s->encoder.t42);
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
return t43_encode_release(&s->encoder.t43);
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+ case T4_COMPRESSION_T45:
+ break;
#endif
}
return -1;