From: Steve Underwood Date: Wed, 17 Apr 2013 15:43:41 +0000 (+0800) Subject: More movement towards colour FAX X-Git-Tag: v1.5.1~226 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e5b85e61454bf4f28d47bf6434e5a1e11d80e1b;p=thirdparty%2Ffreeswitch.git More movement towards colour FAX --- diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index c28feafed2..851c9b9501 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -159,8 +159,6 @@ struct t30_state_s int local_dis_dtc_len; /*! \brief The last DIS or DTC message received form the far end. */ uint8_t far_dis_dtc_frame[T30_MAX_DIS_DTC_DCS_LEN]; - /*! \brief The length of the last DIS or DTC message received form the far end. */ - int far_dis_dtc_len; /*! \brief TRUE if a valid DIS has been received from the far end. */ int dis_received; diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 32900c5e1a..56d0ab4bda 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -453,6 +453,22 @@ static void timer_t2_t4_stop(t30_state_t *s); /*! 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 @@ -1125,48 +1141,6 @@ static int send_pps_frame(t30_state_t *s) } /*- 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; @@ -1179,7 +1153,7 @@ int t30_build_dis_or_dtc(t30_state_t *s) 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 @@ -1219,7 +1193,7 @@ int t30_build_dis_or_dtc(t30_state_t *s) 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); @@ -1383,11 +1357,52 @@ int t30_build_dis_or_dtc(t30_state_t *s) 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; @@ -1408,28 +1423,48 @@ static int build_dcs(t30_state_t *s) 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) @@ -1438,7 +1473,7 @@ static int build_dcs(t30_state_t *s) // 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) @@ -1450,37 +1485,18 @@ static int build_dcs(t30_state_t *s) // 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) @@ -1747,7 +1763,6 @@ static int build_dcs(t30_state_t *s) 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 --------------------------------------------------------*/ @@ -1757,7 +1772,7 @@ static int prune_dcs(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--) + 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); @@ -1775,1017 +1790,1027 @@ static int prune_dcs(t30_state_t *s) } /*- 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) { @@ -6657,7 +6682,6 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s) 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)); diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index f2a2929fd1..2c5d6971ad 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -218,8 +218,14 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_T85_L0: output_compression = COMPRESSION_T85; break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + output_compression = COMPRESSION_T88; + break; +#endif #if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: output_compression = COMPRESSION_JPEG; bits_per_sample = 8; samples_per_pixel = 3; @@ -233,6 +239,14 @@ static int set_tiff_directory_info(t4_rx_state_t *s) samples_per_pixel = 3; photometric = PHOTOMETRIC_ITULAB; break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + output_compression = COMPRESSION_T45; + bits_per_sample = 8; + samples_per_pixel = 3; + photometric = PHOTOMETRIC_ITULAB; + break; #endif } @@ -347,6 +361,10 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_T85_L0: s->image_length = t85_decode_get_image_length(&s->decoder.t85); break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: s->image_length = t42_decode_get_image_length(&s->decoder.t42); break; @@ -354,6 +372,10 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_T43: s->image_length = t43_decode_get_image_length(&s->decoder.t43); break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, s->image_length); @@ -392,19 +414,101 @@ static int row_read_handler(void *user_data, uint8_t row[], size_t len) } /*- End of function --------------------------------------------------------*/ -static int write_tiff_image(t4_rx_state_t *s) +static int write_tiff_t85_image(t4_rx_state_t *s) { - t4_rx_tiff_state_t *t; uint8_t *buf; uint8_t *buf2; int buf_len; int len; - int len2; + int image_len; t85_encode_state_t t85; + packer_t packer; + + /* We need to perform this compression here, as libtiff does not understand it. */ + packer.buf = s->tiff.image_buffer; + packer.ptr = 0; + if (t85_encode_init(&t85, s->image_width, s->image_length, row_read_handler, &packer) == NULL) + return -1; + //if (t->output_encoding == T4_COMPRESSION_T85_L0) + // t85_encode_set_options(&t85, 256, -1, -1); + buf = NULL; + buf_len = 0; + image_len = 0; + do + { + if (buf_len < image_len + 65536) + { + buf_len += 65536; + if ((buf2 = realloc(buf, buf_len)) == NULL) + { + if (buf) + free(buf); + return -1; + } + buf = buf2; + } + len = t85_encode_get(&t85, &buf[image_len], buf_len - image_len); + image_len += len; + } + while (len > 0); + if (TIFFWriteRawStrip(s->tiff.tiff_file, 0, buf, image_len) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + return -1; + } + t85_encode_release(&t85); + free(buf); + return 0; +} +/*- End of function --------------------------------------------------------*/ + #if defined(SPANDSP_SUPPORT_T43) +static int write_tiff_t43_image(t4_rx_state_t *s) +{ + uint8_t *buf; + uint8_t *buf2; + int buf_len; + int len; + int image_len; t43_encode_state_t t43; -#endif packer_t packer; + + packer.buf = s->tiff.image_buffer; + packer.ptr = 0; + if (t43_encode_init(&t43, s->image_width, s->image_length, row_read_handler, &packer) == NULL) + return -1; + buf = NULL; + buf_len = 0; + image_len = 0; + do + { + if (buf_len < image_len + 65536) + { + buf_len += 65536; + if ((buf2 = realloc(buf, buf_len)) == NULL) + { + if (buf) + free(buf); + return -1; + } + buf = buf2; + } + len = t43_encode_get(&t43, &buf[image_len], buf_len - image_len); + image_len += len; + } + while (len > 0); + if (TIFFWriteRawStrip(s->tiff.tiff_file, 0, buf, image_len) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + t43_encode_release(&t43); + free(buf); + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +static int write_tiff_image(t4_rx_state_t *s) +{ + t4_rx_tiff_state_t *t; #if defined(SPANDSP_SUPPORT_TIFF_FX) uint64_t offset; #endif @@ -424,68 +528,28 @@ static int write_tiff_image(t4_rx_state_t *s) case T4_COMPRESSION_T85: case T4_COMPRESSION_T85_L0: /* We need to perform this compression here, as libtiff does not understand it. */ - span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.85 compression.\n", t->file); - buf_len = 0; - buf = NULL; - packer.buf = t->image_buffer; - packer.ptr = 0; - t85_encode_init(&t85, s->image_width, s->image_length, row_read_handler, &packer); - //if (t->output_encoding == T4_COMPRESSION_T85_L0) - // t85_encode_set_options(&t85, 256, -1, -1); - len2 = 0; - do - { - if (buf_len < len2 + 50000) - { - buf_len += 50000; - if ((buf2 = realloc(buf, buf_len)) == NULL) - { - if (buf) - free(buf); - return -1; - } - buf = buf2; - } - len = t85_encode_get(&t85, &buf[len2], 50000); - len2 += len; - } - while (len > 0); - if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file); - t85_encode_release(&t85); - free(buf); + if (write_tiff_t85_image(s) < 0) + return -1; break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t88_image(s) < 0) + return -1; + break; +#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: /* We need to perform this compression here, as libtiff does not understand it. */ - span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.43 compression.\n", t->file); - buf_len = 0; - buf = NULL; - packer.buf = t->image_buffer; - packer.ptr = 0; - t43_encode_init(&t43, s->image_width, s->image_length, row_read_handler, &packer); - len2 = 0; - do - { - if (buf_len < len2 + 50000) - { - buf_len += 50000; - if ((buf2 = realloc(buf, buf_len)) == NULL) - { - if (buf) - free(buf); - return -1; - } - buf = buf2; - } - len = t43_encode_get(&t43, &buf[len2], 50000); - len2 += len; - } - while (len > 0); - if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file); - t43_encode_release(&t43); - free(buf); + if (write_tiff_t43_image(s) < 0) + return -1; + break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t45_image(s) < 0) + return -1; break; #endif default: @@ -498,6 +562,8 @@ static int write_tiff_image(t4_rx_state_t *s) if (!TIFFWriteDirectory(t->tiff_file)) span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page); #if defined(SPANDSP_SUPPORT_TIFF_FX) + /* According to the TIFF/FX spec, a global parameters IFD should only be inserted into + the first page in the file */ if (s->current_page == 0) { if (!TIFFCreateCustomDirectory(t->tiff_file, &tiff_fx_field_array)) @@ -597,11 +663,19 @@ SPAN_DECLARE(int) t4_rx_put(t4_rx_state_t *s, const uint8_t buf[], size_t len) case T4_COMPRESSION_T85: case T4_COMPRESSION_T85_L0: return t85_decode_put(&s->decoder.t85, buf, len); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: return t42_decode_put(&s->decoder.t42, buf, len); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_put(&s->decoder.t43, buf, len); +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } return T4_DECODE_OK; @@ -686,10 +760,24 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) } s->line_encoding = encoding; return 0; +#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 0; +#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_decode_init(&s->decoder.t42, s->row_handler, s->row_handler_user_data); @@ -717,6 +805,18 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) } s->line_encoding = encoding; return 0; +#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 0; #endif } return -1; @@ -742,11 +842,19 @@ SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_han case T4_COMPRESSION_T85: case T4_COMPRESSION_T85_L0: return t85_decode_set_row_write_handler(&s->decoder.t85, handler, user_data); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: return t42_decode_set_row_write_handler(&s->decoder.t42, handler, user_data); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_set_row_write_handler(&s->decoder.t43, handler, user_data); +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } return -1; @@ -789,6 +897,10 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->image_length = t->length; t->line_image_size = t85_decode_get_compressed_image_size(&s->decoder.t85)/8; break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: t->type = 0; t->width = t42_decode_get_image_width(&s->decoder.t42); @@ -808,6 +920,10 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->image_length = t->length; t->line_image_size = t43_decode_get_compressed_image_size(&s->decoder.t43)/8; break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } } @@ -828,6 +944,10 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) case T4_COMPRESSION_T85_L0: t85_decode_restart(&s->decoder.t85); break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: t42_decode_restart(&s->decoder.t42); break; @@ -835,6 +955,10 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) case T4_COMPRESSION_T43: t43_decode_restart(&s->decoder.t43); break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } s->line_image_size = 0; @@ -886,6 +1010,10 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) t85_decode_put(&s->decoder.t85, NULL, 0); length = t85_decode_get_image_length(&s->decoder.t85); break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: t42_decode_put(&s->decoder.t42, NULL, 0); length = t42_decode_get_image_length(&s->decoder.t42); @@ -895,6 +1023,10 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) t43_decode_put(&s->decoder.t43, NULL, 0); length = t43_decode_get_image_length(&s->decoder.t43); break; +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } @@ -984,11 +1116,19 @@ SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s) case T4_COMPRESSION_T85: case T4_COMPRESSION_T85_L0: return t85_decode_release(&s->decoder.t85); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif case T4_COMPRESSION_T42_T81: return t42_decode_release(&s->decoder.t42); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_release(&s->decoder.t43); +#endif +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; #endif } return -1; diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index ff5b5fd349..6ad6821b9b 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -92,7 +92,7 @@ typedef struct int ptr; int row; int bit_mask; -} t85_packer_t; +} packer_t; typedef struct { @@ -574,11 +574,11 @@ static int row_read(void *user_data, uint8_t buf[], size_t len) } /*- 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++; @@ -586,7 +586,7 @@ static int t85_row_write_handler(void *user_data, const uint8_t buf[], size_t le } /*- 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; @@ -599,18 +599,235 @@ static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len) } /*- 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) @@ -666,89 +883,15 @@ static int read_tiff_image(t4_tx_state_t *s) 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; } } @@ -788,11 +931,20 @@ static int set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, 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; @@ -971,10 +1123,24 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding) } 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); @@ -994,6 +1160,18 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding) } 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 } } @@ -1028,13 +1206,22 @@ SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width) 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 } } @@ -1049,13 +1236,22 @@ static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length) 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 } } @@ -1180,7 +1376,12 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t 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; @@ -1193,6 +1394,10 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t 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 } } @@ -1209,11 +1414,20 @@ SPAN_DECLARE(int) t4_tx_image_complete(t4_tx_state_t *s) 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; @@ -1238,11 +1452,20 @@ SPAN_DECLARE(int) t4_tx_get(t4_tx_state_t *s, uint8_t buf[], size_t max_len) 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; @@ -1278,13 +1501,22 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) 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 */ @@ -1399,11 +1631,20 @@ SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s) 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;