fix for bug #119964. implement yEnc decoding.

note, we have no plans to support yEnc encoding.
thanks to ducarroz for the patch.  r/sr=sspitzer
This commit is contained in:
sspitzer%netscape.com 2003-04-10 02:19:35 +00:00
parent 4c694bf157
commit 985e9ef0d6
13 changed files with 364 additions and 33 deletions

View File

@ -124,6 +124,8 @@ MimeEncrypted_parse_begin (MimeObject *obj)
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{
enc->decoder_data =

View File

@ -781,7 +781,7 @@ mime_insert_all_headers(char **body,
char *c2 = 0;
// Hack for BSD Mailbox delimiter.
if (i == 0 && head[0] == 'F' && !nsCRT::strncmp(head, "From ", 5))
if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
{
colon = head + 4;
contents = colon + 1;
@ -1961,6 +1961,8 @@ mime_decompose_file_init_fn ( void *stream_closure, MimeHeaders *headers )
!nsCRT::strcasecmp(newAttachment->encoding, ENCODING_UUENCODE3) ||
!nsCRT::strcasecmp(newAttachment->encoding, ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!nsCRT::strcasecmp(newAttachment->encoding, ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{

View File

@ -44,12 +44,12 @@
#include "prprf.h"
typedef enum mime_encoding {
mime_Base64, mime_QuotedPrintable, mime_uuencode
mime_Base64, mime_QuotedPrintable, mime_uuencode, mime_yencode
} mime_encoding;
typedef enum mime_uue_state {
UUE_BEGIN, UUE_BODY, UUE_END
} mime_uue_state;
typedef enum mime_decoder_state {
DS_BEGIN, DS_BODY, DS_END
} mime_decoder_state;
struct MimeDecoderData {
mime_encoding encoding; /* Which encoding to use */
@ -58,9 +58,10 @@ struct MimeDecoderData {
char token[4];
int token_size;
/* State and read-buffer used for uudecode. */
mime_uue_state uue_state;
char uue_line_buffer [128];
/* State and read-buffer used for uudecode and yencode. */
mime_decoder_state ds_state;
char *line_buffer;
int line_buffer_size;
/* Where to write the decoded data */
nsresult (*write_buffer) (const char *buf, PRInt32 size, void *closure);
@ -324,22 +325,31 @@ static int
mime_decode_uue_buffer (MimeDecoderData *data,
const char *input_buffer, PRInt32 input_length)
{
/* First, copy input_buffer into state->uue_line_buffer until we have
/* First, copy input_buffer into state->line_buffer until we have
a complete line.
Then decode that line in place (in the uue_line_buffer) and write
Then decode that line in place (in the line_buffer) and write
it out.
Then pull the next line into uue_line_buffer and continue.
Then pull the next line into line_buffer and continue.
*/
if (!data->line_buffer)
{
data->line_buffer_size = 128;
data->line_buffer = (char *)PR_MALLOC(data->line_buffer_size);
if (!data->line_buffer)
return -1;
data->line_buffer[0] = 0;
}
int status = 0;
char *line = data->uue_line_buffer;
char *line_end = data->uue_line_buffer + sizeof (data->uue_line_buffer) - 1;
char *line = data->line_buffer;
char *line_end = data->line_buffer + data->line_buffer_size - 1;
NS_ASSERTION(data->encoding == mime_uuencode, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (data->encoding != mime_uuencode) return -1;
if (data->uue_state == UUE_END)
if (data->ds_state == DS_END)
{
status = 0;
goto DONE;
@ -410,7 +420,7 @@ mime_decode_uue_buffer (MimeDecoderData *data,
*/
if (data->uue_state == UUE_BODY &&
if (data->ds_state == DS_BODY &&
line[0] == 'e' &&
line[1] == 'n' &&
line[2] == 'd' &&
@ -418,25 +428,25 @@ mime_decode_uue_buffer (MimeDecoderData *data,
line[3] == nsCRT::LF))
{
/* done! */
data->uue_state = UUE_END;
data->ds_state = DS_END;
*line = 0;
break;
}
else if (data->uue_state == UUE_BEGIN)
else if (data->ds_state == DS_BEGIN)
{
if (!nsCRT::strncmp (line, "begin ", 6))
data->uue_state = UUE_BODY;
if (!strncmp (line, "begin ", 6))
data->ds_state = DS_BODY;
*line = 0;
continue;
}
else
{
/* We're in UUE_BODY. Decode the line. */
/* We're in DS_BODY. Decode the line. */
char *in, *out;
PRInt32 i;
long lost;
NS_ASSERTION (data->uue_state == UUE_BODY, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
NS_ASSERTION (data->ds_state == DS_BODY, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
/* We map down `line', reading four bytes and writing three.
That means that `out' always stays safely behind `in'.
@ -544,6 +554,198 @@ mime_decode_uue_buffer (MimeDecoderData *data,
return status;
}
static int
mime_decode_yenc_buffer (MimeDecoderData *data,
const char *input_buffer, PRInt32 input_length)
{
/* First, copy input_buffer into state->line_buffer until we have
a complete line.
Then decode that line in place (in the line_buffer) and write
it out.
Then pull the next line into line_buffer and continue.
*/
if (!data->line_buffer)
{
data->line_buffer_size = 1000; // let make sure we have plenty of space for the header line
data->line_buffer = (char *)PR_MALLOC(data->line_buffer_size);
if (!data->line_buffer)
return -1;
data->line_buffer[0] = 0;
}
int status = 0;
char *line = data->line_buffer;
char *line_end = data->line_buffer + data->line_buffer_size - 1;
NS_ASSERTION(data->encoding == mime_yencode, "wrong decoder!");
if (data->encoding != mime_yencode) return -1;
if (data->ds_state == DS_END)
return 0;
while (input_length > 0)
{
/* Copy data from input_buffer to `line' until we have a complete line,
or until we've run out of input.
(line may have data in it already if the last time we were called,
we weren't called with a buffer that ended on a line boundary.)
*/
{
char *out = line + strlen(line);
while (input_length > 0 && out < line_end)
{
*out++ = *input_buffer++;
input_length--;
if (out[-1] == nsCRT::CR || out[-1] == nsCRT::LF)
{
/* If we just copied a CR, and an LF is waiting, grab it too. */
if (out[-1] == nsCRT::CR &&
input_length > 0 &&
*input_buffer == nsCRT::LF)
input_buffer++, input_length--;
/* We have a line. */
break;
}
}
*out = 0;
/* Ignore blank lines. */
if (*line == nsCRT::CR || *line == nsCRT::LF)
{
*line = 0;
continue;
}
/* If this line was bigger than our buffer, truncate it.
(This means the data was way corrupted, and there's basically
no chance of decoding it properly, but give it a shot anyway.)
*/
if (out == line_end)
{
out--;
out[-1] = nsCRT::CR;
out[0] = 0;
}
/* If we didn't get a complete line, simply return; we'll be called
with the rest of this line next time.
*/
if (out[-1] != nsCRT::CR && out[-1] != nsCRT::LF)
{
NS_ASSERTION (input_length == 0, "empty buffer!");
break;
}
}
/* Now we have a complete line. Deal with it.
*/
const char * endOfLine = line + strlen(line);
if (data->ds_state == DS_BEGIN)
{
int new_line_size = 0;
/* this yenc decoder does not support yenc v2 or multipart yenc.
Therefore, we are looking first for "=ybegin line="
*/
if ((endOfLine - line) >= 13 && !strncmp (line, "=ybegin line=", 13))
{
/* ...then couple digits. */
for (line += 13; line < endOfLine; line ++)
{
if (*line < '0' || *line > '9')
break;
new_line_size = (new_line_size * 10) + *line - '0';
}
/* ...next, look for <space>size= */
if ((endOfLine - line) >= 6 && !strncmp (line, " size=", 6))
{
/* ...then couple digits. */
for (line += 6; line < endOfLine; line ++)
if (*line < '0' || *line > '9')
break;
/* ...next, look for <space>name= */
if ((endOfLine - line) >= 6 && !strncmp (line, " name=", 6))
{
/* we have found the yenc header line.
Now check if we need to grow our buffer line
*/
data->ds_state = DS_BODY;
if (new_line_size > data->line_buffer_size && new_line_size <= 997) /* don't let bad value hurt us! */
{
PR_Free(data->line_buffer);
data->line_buffer_size = new_line_size + 4; //extra chars for line ending and potential escape char
data->line_buffer = (char *)PR_MALLOC(data->line_buffer_size);
if (!data->line_buffer)
return -1;
}
}
}
}
*data->line_buffer = 0;
continue;
}
if (data->ds_state == DS_BODY && line[0] == '=')
{
/* look if this this the final line */
if (!strncmp (line, "=yend size=", 11))
{
/* done! */
data->ds_state = DS_END;
*line = 0;
break;
}
}
/* We're in DS_BODY. Decode the line in place. */
{
char *src = line;
char *dest = src;
char c;
for (; src < line_end; src ++)
{
c = *src;
if (!c || c == nsCRT::CR || c == nsCRT::LF)
break;
if (c == '=')
{
src++;
c = *src;
if (c == 0)
return -1; /* last character cannot be escape char */
c -= 64;
}
c -= 42;
*dest = c;
dest ++;
}
/* Now write out what we decoded for this line. */
NS_ASSERTION(dest >= line && dest < src, "nothing to write!");
if (dest > line)
{
status = data->write_buffer (line, dest - line, data->closure);
if (status < 0) /* abort */
return status;
}
/* Reset the line so that we don't think it's partial next time. */
*line = 0;
}
}
return 1;
}
int
MimeDecoderDestroy (MimeDecoderData *data, PRBool abort_p)
@ -562,6 +764,8 @@ MimeDecoderDestroy (MimeDecoderData *data, PRBool abort_p)
data->closure);
}
if (data->line_buffer)
PR_Free(data->line_buffer);
PR_Free (data);
return status;
}
@ -578,6 +782,9 @@ mime_decoder_init (mime_encoding which,
data->encoding = which;
data->write_buffer = output_fn;
data->closure = closure;
data->line_buffer_size = 0;
data->line_buffer = nsnull;
return data;
}
@ -602,6 +809,13 @@ MimeUUDecoderInit (nsresult (*output_fn) (const char *, PRInt32, void *),
return mime_decoder_init (mime_uuencode, output_fn, closure);
}
MimeDecoderData *
MimeYDecoderInit (nsresult (*output_fn) (const char *, PRInt32, void *),
void *closure)
{
return mime_decoder_init (mime_yencode, output_fn, closure);
}
int
MimeDecoderWrite (MimeDecoderData *data, const char *buffer, PRInt32 size)
{
@ -615,6 +829,8 @@ MimeDecoderWrite (MimeDecoderData *data, const char *buffer, PRInt32 size)
return mime_decode_qp_buffer (data, buffer, size);
case mime_uuencode:
return mime_decode_uue_buffer (data, buffer, size);
case mime_yencode:
return mime_decode_yenc_buffer (data, buffer, size);
default:
NS_ASSERTION(0, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
return -1;

View File

@ -372,7 +372,7 @@ MimeHeaders_get (MimeHeaders *hdrs, const char *header_name,
if (!head) continue;
/* Quick hack to skip over BSD Mailbox delimiter. */
if (i == 0 && head[0] == 'F' && !nsCRT::strncmp(head, "From ", 5))
if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
continue;
/* Find the colon. */
@ -732,7 +732,7 @@ MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, PRBoo
hdr_value = 0;
/* Hack for BSD Mailbox delimiter. */
if (i == 0 && head[0] == 'F' && !nsCRT::strncmp(head, "From ", 5))
if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
{
/* For now, we don't really want this header to be output so
we are going to just continue */

View File

@ -128,6 +128,8 @@ MimeLeaf_parse_begin (MimeObject *obj)
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{

View File

@ -1577,8 +1577,8 @@ mime_bridge_create_display_stream(
}
if (msd->options->headers == MimeHeadersMicro &&
(msd->url_name == NULL || (nsCRT::strncmp(msd->url_name, "news:", 5) != 0 &&
nsCRT::strncmp(msd->url_name, "snews:", 6) != 0)) )
(msd->url_name == NULL || (strncmp(msd->url_name, "news:", 5) != 0 &&
strncmp(msd->url_name, "snews:", 6) != 0)) )
msd->options->headers = MimeHeadersMicroPlus;
msd->options->url = msd->url_name;

View File

@ -401,6 +401,8 @@ MimeMultipartSigned_parse_line (char *line, PRInt32 length, MimeObject *obj)
!nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE3) ||
!nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!nsCRT::strcasecmp(encoding.get(), ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{
sig->sig_decoder_data =

View File

@ -369,7 +369,7 @@ MimeMultipart_check_boundary(MimeObject *obj, const char *line, PRInt32 length)
if (term_p)
length -= 2;
if (blen == length-2 && !nsCRT::strncmp(line+2, mult->boundary, length-2))
if (blen == length-2 && !strncmp(line+2, mult->boundary, length-2))
return (term_p
? MimeMultipartBoundaryTypeTerminator
: MimeMultipartBoundaryTypeSeparator);

View File

@ -221,7 +221,7 @@ MimeObject_parse_begin (MimeObject *obj)
if (mime_typep(obj->parent, (MimeObjectClass*) &mimeMessageClass) ||
mime_typep(obj->parent, (MimeObjectClass*) &mimeMultipartAppleDoubleClass))
{
obj->output_p = !nsCRT::strncmp((const char*)id, (const char*)obj->options->part_to_load,
obj->output_p = !strncmp((const char*)id, (const char*)obj->options->part_to_load,
(unsigned int)strlen(obj->options->part_to_load));
}
}

View File

@ -67,6 +67,12 @@ static PRBool MimeUntypedText_uu_begin_line_p(const char *line, PRInt32 length,
char **name_ret);
static PRBool MimeUntypedText_uu_end_line_p(const char *line, PRInt32 length);
static PRBool MimeUntypedText_yenc_begin_line_p(const char *line, PRInt32 length,
MimeDisplayOptions *opt,
char **type_ret,
char **name_ret);
static PRBool MimeUntypedText_yenc_end_line_p(const char *line, PRInt32 length);
static PRBool MimeUntypedText_binhex_begin_line_p(const char *line,
PRInt32 length,
MimeDisplayOptions *opt);
@ -154,6 +160,21 @@ MimeUntypedText_parse_line (char *line, PRInt32 length, MimeObject *obj)
begin_line_p = PR_TRUE;
}
else if (line[0] == '=' &&
MimeUntypedText_yenc_begin_line_p(line, length, obj->options,
&type, &name))
{
/* Close the old part and open a new one. */
status = MimeUntypedText_open_subpart (obj,
MimeUntypedTextSubpartTypeYEnc,
type, ENCODING_YENCODE,
name, NULL);
PR_FREEIF(name);
PR_FREEIF(type);
if (status < 0) return status;
begin_line_p = PR_TRUE;
}
else if (line[0] == '(' && line[1] == 'T' &&
MimeUntypedText_binhex_begin_line_p(line, length, obj->options))
{
@ -202,14 +223,22 @@ MimeUntypedText_parse_line (char *line, PRInt32 length, MimeObject *obj)
{
status = MimeUntypedText_close_subpart (obj);
if (status < 0) return status;
PR_ASSERT(!uty->open_subpart);
NS_ASSERTION(!uty->open_subpart, "no open subpart");
}
else if (line[0] == '=' &&
uty->type == MimeUntypedTextSubpartTypeYEnc &&
MimeUntypedText_yenc_end_line_p(line, length))
{
status = MimeUntypedText_close_subpart (obj);
if (status < 0) return status;
NS_ASSERTION(!uty->open_subpart, "no open subpart");
}
else if (uty->type == MimeUntypedTextSubpartTypeBinhex &&
MimeUntypedText_binhex_end_line_p(line, length))
{
status = MimeUntypedText_close_subpart (obj);
if (status < 0) return status;
PR_ASSERT(!uty->open_subpart);
NS_ASSERTION(!uty->open_subpart, "no open subpart");
}
return 0;
@ -274,8 +303,8 @@ MimeUntypedText_open_subpart (MimeObject *obj,
status = MimeUntypedText_close_subpart (obj);
if (status < 0) return status;
}
PR_ASSERT(!uty->open_subpart);
PR_ASSERT(!uty->open_hdrs);
NS_ASSERTION(!uty->open_subpart, "no open subpart");
NS_ASSERTION(!uty->open_hdrs, "no open headers");
/* To make one of these implicitly-typed sub-objects, we make up a fake
header block, containing only the minimum number of MIME headers needed.
@ -400,7 +429,7 @@ MimeUntypedText_uu_begin_line_p(const char *line, PRInt32 length,
if (type_ret) *type_ret = 0;
if (name_ret) *name_ret = 0;
if (nsCRT::strncmp (line, "begin ", 6)) return PR_FALSE;
if (strncmp (line, "begin ", 6)) return PR_FALSE;
/* ...then three or four octal digits. */
s = line + 6;
if (*s < '0' || *s > '7') return PR_FALSE;
@ -482,6 +511,78 @@ MimeUntypedText_uu_end_line_p(const char *line, PRInt32 length)
#endif
}
static PRBool
MimeUntypedText_yenc_begin_line_p(const char *line, PRInt32 length,
MimeDisplayOptions *opt,
char **type_ret, char **name_ret)
{
const char *s;
const char *endofline = line + length;
char *name = 0;
char *type = 0;
if (type_ret) *type_ret = 0;
if (name_ret) *name_ret = 0;
/* we don't support yenc V2 neither multipart yencode,
therefore the second parameter should always be "line="*/
if (length < 13 || strncmp (line, "=ybegin line=", 13)) return PR_FALSE;
/* ...then couple digits. */
for (s = line + 13; s < endofline; s ++)
if (*s < '0' || *s > '9')
break;
/* ...next, look for <space>size= */
if ((endofline - s) < 6 || strncmp (s, " size=", 6)) return PR_FALSE;
/* ...then couple digits. */
for (s += 6; s < endofline; s ++)
if (*s < '0' || *s > '9')
break;
/* ...next, look for <space>name= */
if ((endofline - s) < 6 || strncmp (s, " name=", 6)) return PR_FALSE;
/* anything left is the file name */
s += 6;
name = (char *) PR_MALLOC((endofline-s) + 1);
if (!name) return PR_FALSE; /* grr... */
memcpy(name, s, endofline-s);
name[endofline-s] = 0;
/* take off newline. */
if (name[strlen(name)-1] == nsCRT::LF) name[strlen(name)-1] = 0;
if (name[strlen(name)-1] == nsCRT::CR) name[strlen(name)-1] = 0;
/* Now try and figure out a type.
*/
if (opt && opt->file_type_fn)
type = opt->file_type_fn(name, opt->stream_closure);
else
type = 0;
if (name_ret)
*name_ret = name;
else
PR_FREEIF(name);
if (type_ret)
*type_ret = type;
else
PR_FREEIF(type);
return PR_TRUE;
}
static PRBool
MimeUntypedText_yenc_end_line_p(const char *line, PRInt32 length)
{
if (length < 11 || strncmp (line, "=yend size=", 11)) return PR_FALSE;
return PR_TRUE;
}
#define BINHEX_MAGIC "(This file must be converted with BinHex 4.0)"
#define BINHEX_MAGIC_LEN 45
@ -499,7 +600,7 @@ MimeUntypedText_binhex_begin_line_p(const char *line, PRInt32 length,
if (length != BINHEX_MAGIC_LEN)
return PR_FALSE;
if (!nsCRT::strncmp(line, BINHEX_MAGIC, BINHEX_MAGIC_LEN))
if (!strncmp(line, BINHEX_MAGIC, BINHEX_MAGIC_LEN))
return PR_TRUE;
else
return PR_FALSE;

View File

@ -85,6 +85,7 @@ extern MimeUntypedTextClass mimeUntypedTextClass;
typedef enum {
MimeUntypedTextSubpartTypeText, /* text/plain */
MimeUntypedTextSubpartTypeUUE, /* uuencoded data */
MimeUntypedTextSubpartTypeYEnc, /* yencoded data */
MimeUntypedTextSubpartTypeBinhex /* Mac BinHex data */
} MimeUntypedTextSubpartType;

View File

@ -71,6 +71,10 @@ MimeDecoderData *MimeUUDecoderInit (nsresult (*output_fn) (const char *buf,
PRInt32 size,
void *closure),
void *closure);
MimeDecoderData *MimeYDecoderInit (nsresult (*output_fn) (const char *buf,
PRInt32 size,
void *closure),
void *closure);
MimeEncoderData *MimeB64EncoderInit(nsresult (*output_fn) (const char *buf,
PRInt32 size,

View File

@ -170,6 +170,7 @@
#define ENCODING_UUENCODE2 "x-uue"
#define ENCODING_UUENCODE3 "uuencode"
#define ENCODING_UUENCODE4 "uue"
#define ENCODING_YENCODE "x-yencode"
/* Some names of parameters that various MIME headers include.
*/