int MimeHeaders_parse_line (const char *buffer, int32_t size, MimeHeaders *hdrs) { int status = 0; int desired_size; NS_ASSERTION(hdrs, "1.22 <*****@*****.**> 22 Aug 1999 08:48"); if (!hdrs) return -1; /* Don't try and feed me more data after having fed me a blank line... */ NS_ASSERTION(!hdrs->done_p, "1.22 <*****@*****.**> 22 Aug 1999 08:48"); if (hdrs->done_p) return -1; if (!buffer || size == 0 || *buffer == '\r' || *buffer == '\n') { /* If this is a blank line, we're done. */ hdrs->done_p = true; return MimeHeaders_build_heads_list(hdrs); } /* Tack this data on to the end of our copy. */ desired_size = hdrs->all_headers_fp + size + 1; if (desired_size >= hdrs->all_headers_size) { status = mime_GrowBuffer (desired_size, sizeof(char), 255, &hdrs->all_headers, &hdrs->all_headers_size); if (status < 0) return status; } memcpy(hdrs->all_headers+hdrs->all_headers_fp, buffer, size); hdrs->all_headers_fp += size; return 0; }
/* The opposite of mime_LineBuffer(): takes small buffers and packs them up into bigger buffers before passing them along. Pass in a desired_buffer_size 0 to tell it to flush (for example, in in the very last call to this function.) */ extern "C" int mime_ReBuffer (const char *net_buffer, PRInt32 net_buffer_size, PRUint32 desired_buffer_size, char **bufferP, PRInt32 *buffer_sizeP, PRUint32 *buffer_fpP, PRInt32 (*per_buffer_fn) (char *buffer, PRUint32 buffer_size, void *closure), void *closure) { int status = 0; if (desired_buffer_size >= (PRUint32) (*buffer_sizeP)) { status = mime_GrowBuffer (desired_buffer_size, sizeof(char), 1024, bufferP, buffer_sizeP); if (status < 0) return status; } do { PRInt32 size = *buffer_sizeP - *buffer_fpP; if (size > net_buffer_size) size = net_buffer_size; if (size > 0) { memcpy ((*bufferP) + (*buffer_fpP), net_buffer, size); (*buffer_fpP) += size; net_buffer += size; net_buffer_size -= size; } if (*buffer_fpP > 0 && *buffer_fpP >= desired_buffer_size) { status = (*per_buffer_fn) ((*bufferP), (*buffer_fpP), closure); *buffer_fpP = 0; if (status < 0) return status; } } while (net_buffer_size > 0); return 0; }
/* This function has this clunky interface because it needs to be called from outside this module (no MimeObject, etc.) */ int MimeRichtextConvert (const char *line, PRInt32 length, int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure, char **obufferP, PRInt32 *obuffer_sizeP, PRBool enriched_p) { /* RFC 1341 (the original MIME spec) defined text/richtext. RFC 1563 superceded text/richtext with text/enriched. The changes from text/richtext to text/enriched are: - CRLF semantics are different - << maps to < - These tags were added: <VERBATIM>, <NOFILL>, <PARAM>, <FLUSHBOTH> - These tags were removed: <COMMENT>, <OUTDENT>, <OUTDENTRIGHT>, <SAMEPAGE>, <SUBSCRIPT>, <SUPERSCRIPT>, <HEADING>, <FOOTING>, <PARAGRAPH>, <SIGNATURE>, <LT>, <NL>, <NP> This method implements them both. draft-resnick-text-enriched-03.txt is a proposed update to 1563. - These tags were added: <FONTFAMILY>, <COLOR>, <PARAINDENT>, <LANG>. However, all of these rely on the magic <PARAM> tag, which we don't implement, so we're ignoring all of these. Interesting fact: it's by Peter W. Resnick from Qualcomm (Eudora). And it also says "It is fully expected that other text formatting standards like HTML and SGML will supplant text/enriched in Internet mail." */ int status = 0; char *out; const char *data_end; const char *last_end; const char *this_start; const char *this_end; unsigned int desired_size; // The code below must never expand the input by more than 5x; // if it does, the desired_size multiplier (5) below must be changed too #define BGROWTH 5 if ( (PRUint32)length >= ( (PRUint32) 0xfffffffe)/BGROWTH ) return -1; desired_size = (length * BGROWTH) + 1; #undef BGROWTH if (desired_size >= (PRUint32) *obuffer_sizeP) status = mime_GrowBuffer (desired_size, sizeof(char), 1024, obufferP, obuffer_sizeP); if (status < 0) return status; if (enriched_p) { for (this_start = line; this_start < line + length; this_start++) if (!IS_SPACE (*this_start)) break; if (this_start >= line + length) /* blank line */ { PL_strncpyz (*obufferP, "<BR>", *obuffer_sizeP); return output_fn (*obufferP, strlen(*obufferP), closure); } } PRUint32 outlen = (PRUint32) *obuffer_sizeP; out = *obufferP; *out = 0; data_end = line + length; last_end = line; this_start = last_end; this_end = this_start; PRUint32 addedlen = 0; while (this_end < data_end) { /* Skip forward to next special character. */ while (this_start < data_end && *this_start != '<' && *this_start != '>' && *this_start != '&') this_start++; this_end = this_start; /* Skip to the end of the tag. */ if (this_start < data_end && *this_start == '<') { this_end++; while (this_end < data_end && !IS_SPACE(*this_end) && *this_end != '<' && *this_end != '>' && *this_end != '&') this_end++; } this_end++; /* Push out the text preceeding the tag. */ if (last_end && last_end != this_start) { memcpy (out, last_end, this_start - last_end); out += this_start - last_end; *out = 0; outlen -= (this_start - last_end); } if (this_start >= data_end) break; else if (*this_start == '&') { PL_strncpyz (out, "&", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (*this_start == '>') { PL_strncpyz (out, ">", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (enriched_p && this_start < data_end + 1 && this_start[0] == '<' && this_start[1] == '<') { PL_strncpyz (out, "<", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (this_start != this_end) { /* Push out this ID. */ const char *old = this_start + 1; const char *tag_open = 0; const char *tag_close = 0; if (*old == '/') { /* This is </tag> */ old++; } switch (*old) { case 'b': case 'B': if (!PL_strncasecmp ("BIGGER>", old, 7)) tag_open = "<FONT SIZE=\"+1\">", tag_close = "</FONT>"; else if (!PL_strncasecmp ("BLINK>", old, 5)) /* Of course, both text/richtext and text/enriched must be enhanced *somehow*... Or else what would people think. */ tag_open = "<BLINK>", tag_close = "</BLINK>"; else if (!PL_strncasecmp ("BOLD>", old, 5)) tag_open = "<B>", tag_close = "</B>"; break; case 'c': case 'C': if (!PL_strncasecmp ("CENTER>", old, 7)) tag_open = "<CENTER>", tag_close = "</CENTER>"; else if (!enriched_p && !PL_strncasecmp ("COMMENT>", old, 8)) tag_open = "<!-- ", tag_close = " -->"; break; case 'e': case 'E': if (!PL_strncasecmp ("EXCERPT>", old, 8)) tag_open = "<BLOCKQUOTE>", tag_close = "</BLOCKQUOTE>"; break; case 'f': case 'F': if (!PL_strncasecmp ("FIXED>", old, 6)) tag_open = "<TT>", tag_close = "</TT>"; else if (enriched_p && !PL_strncasecmp ("FLUSHBOTH>", old, 10)) tag_open = "<P ALIGN=LEFT>", tag_close = "</P>"; else if (!PL_strncasecmp ("FLUSHLEFT>", old, 10)) tag_open = "<P ALIGN=LEFT>", tag_close = "</P>"; else if (!PL_strncasecmp ("FLUSHRIGHT>", old, 11)) tag_open = "<P ALIGN=RIGHT>", tag_close = "</P>"; else if (!enriched_p && !PL_strncasecmp ("FOOTING>", old, 8)) tag_open = "<H6>", tag_close = "</H6>"; break; case 'h': case 'H': if (!enriched_p && !PL_strncasecmp ("HEADING>", old, 8)) tag_open = "<H6>", tag_close = "</H6>"; break; case 'i': case 'I': if (!PL_strncasecmp ("INDENT>", old, 7)) tag_open = "<UL>", tag_close = "</UL>"; else if (!PL_strncasecmp ("INDENTRIGHT>", old, 12)) tag_open = 0, tag_close = 0; /* else if (!enriched_p && !PL_strncasecmp ("ISO-8859-", old, 9)) tag_open = 0, tag_close = 0; */ else if (!PL_strncasecmp ("ITALIC>", old, 7)) tag_open = "<I>", tag_close = "</I>"; break; case 'l': case 'L': if (!enriched_p && !PL_strncasecmp ("LT>", old, 3)) tag_open = "<", tag_close = 0; break; case 'n': case 'N': if (!enriched_p && !PL_strncasecmp ("NL>", old, 3)) tag_open = "<BR>", tag_close = 0; if (enriched_p && !PL_strncasecmp ("NOFILL>", old, 7)) tag_open = "<NOBR>", tag_close = "</NOBR>"; /* else if (!enriched_p && !PL_strncasecmp ("NO-OP>", old, 6)) tag_open = 0, tag_close = 0; */ /* else if (!enriched_p && !PL_strncasecmp ("NP>", old, 3)) tag_open = 0, tag_close = 0; */ break; case 'o': case 'O': if (!enriched_p && !PL_strncasecmp ("OUTDENT>", old, 8)) tag_open = 0, tag_close = 0; else if (!enriched_p && !PL_strncasecmp ("OUTDENTRIGHT>", old, 13)) tag_open = 0, tag_close = 0; break; case 'p': case 'P': if (enriched_p && !PL_strncasecmp ("PARAM>", old, 6)) tag_open = "<!-- ", tag_close = " -->"; else if (!enriched_p && !PL_strncasecmp ("PARAGRAPH>", old, 10)) tag_open = "<P>", tag_close = 0; break; case 's': case 'S': if (!enriched_p && !PL_strncasecmp ("SAMEPAGE>", old, 9)) tag_open = 0, tag_close = 0; else if (!enriched_p && !PL_strncasecmp ("SIGNATURE>", old, 10)) tag_open = "<I><FONT SIZE=\"-1\">", tag_close = "</FONT></I>"; else if (!PL_strncasecmp ("SMALLER>", old, 8)) tag_open = "<FONT SIZE=\"-1\">", tag_close = "</FONT>"; else if (!enriched_p && !PL_strncasecmp ("SUBSCRIPT>", old, 10)) tag_open = "<SUB>", tag_close = "</SUB>"; else if (!enriched_p && !PL_strncasecmp ("SUPERSCRIPT>", old, 12)) tag_open = "<SUP>", tag_close = "</SUP>"; break; case 'u': case 'U': if (!PL_strncasecmp ("UNDERLINE>", old, 10)) tag_open = "<U>", tag_close = "</U>"; /* else if (!enriched_p && !PL_strncasecmp ("US-ASCII>", old, 10)) tag_open = 0, tag_close = 0; */ break; case 'v': case 'V': if (enriched_p && !PL_strncasecmp ("VERBATIM>", old, 9)) tag_open = "<PRE>", tag_close = "</PRE>"; break; } if (this_start[1] == '/') { if (tag_close) PL_strncpyz (out, tag_close, outlen); addedlen = strlen (out); outlen -= addedlen; out += addedlen; } else { if (tag_open) PL_strncpyz (out, tag_open, outlen); addedlen = strlen (out); outlen -= addedlen; out += addedlen; } } /* now go around again */ last_end = this_end; this_start = last_end; } *out = 0; return output_fn (*obufferP, out - *obufferP, closure); }
extern "C" int mime_LineBuffer (const char *net_buffer, PRInt32 net_buffer_size, char **bufferP, PRInt32 *buffer_sizeP, PRUint32 *buffer_fpP, bool convert_newlines_p, PRInt32 (* per_line_fn) (char *line, PRUint32 line_length, void *closure), void *closure) { int status = 0; if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == '\r' && net_buffer_size > 0 && net_buffer[0] != '\n') { /* The last buffer ended with a CR. The new buffer does not start with a LF. This old buffer should be shipped out and discarded. */ NS_ASSERTION((PRUint32) *buffer_sizeP > *buffer_fpP, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); if ((PRUint32) *buffer_sizeP <= *buffer_fpP) return -1; status = convert_and_send_buffer(*bufferP, *buffer_fpP, convert_newlines_p, per_line_fn, closure); if (status < 0) return status; *buffer_fpP = 0; } while (net_buffer_size > 0) { const char *net_buffer_end = net_buffer + net_buffer_size; const char *newline = 0; const char *s; for (s = net_buffer; s < net_buffer_end; s++) { /* Move forward in the buffer until the first newline. Stop when we see CRLF, CR, or LF, or the end of the buffer. *But*, if we see a lone CR at the *very end* of the buffer, treat this as if we had reached the end of the buffer without seeing a line terminator. This is to catch the case of the buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n". */ if (*s == '\r' || *s == '\n') { newline = s; if (newline[0] == '\r') { if (s == net_buffer_end - 1) { /* CR at end - wait for the next character. */ newline = 0; break; } else if (newline[1] == '\n') /* CRLF seen; swallow both. */ newline++; } newline++; break; } } /* Ensure room in the net_buffer and append some or all of the current chunk of data to it. */ { const char *end = (newline ? newline : net_buffer_end); PRUint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1; if (desired_size >= (PRUint32) (*buffer_sizeP)) { status = mime_GrowBuffer (desired_size, sizeof(char), 1024, bufferP, buffer_sizeP); if (status < 0) return status; } memcpy ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer)); (*buffer_fpP) += (end - net_buffer); (*bufferP)[*buffer_fpP] = '\0'; } /* Now *bufferP contains either a complete line, or as complete a line as we have read so far. If we have a line, process it, and then remove it from `*bufferP'. Then go around the loop again, until we drain the incoming data. */ if (!newline) return 0; status = convert_and_send_buffer(*bufferP, *buffer_fpP, convert_newlines_p, per_line_fn, closure); if (status < 0) return status; net_buffer_size -= (newline - net_buffer); net_buffer = newline; (*buffer_fpP) = 0; } return 0; }