Back to index

lightning-sunbird  0.9+nobinonly
mimebuf.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00039  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00040  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00041  *
00042  * Date             Modified by     Description of modification
00043  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00044  */
00045 /* 
00046  * mimebuf.c -  libmsg like buffer handling routines for libmime
00047  */
00048 #include "prmem.h"
00049 #include "plstr.h"
00050 #include "prlog.h"
00051 #include "nsCRT.h"
00052 #include "msgCore.h"
00053 #include "nsMimeStringResources.h"
00054 
00055 extern "C" int
00056 mime_GrowBuffer (PRUint32 desired_size, PRUint32 element_size, PRUint32 quantum,
00057                             char **buffer, PRInt32 *size)
00058 {
00059   if ((PRUint32) *size <= desired_size)
00060        {
00061          char *new_buf;
00062          PRUint32 increment = desired_size - *size;
00063          if (increment < quantum) /* always grow by a minimum of N bytes */
00064               increment = quantum;
00065 
00066          new_buf = (*buffer
00067                              ? (char *) PR_Realloc (*buffer, (*size + increment)
00068                                                                       * (element_size / sizeof(char)))
00069                              : (char *) PR_MALLOC ((*size + increment)
00070                                                                  * (element_size / sizeof(char))));
00071          if (! new_buf)
00072                 return MIME_OUT_OF_MEMORY;
00073          *buffer = new_buf;
00074          *size += increment;
00075        }
00076   return 0;
00077 }
00078 
00079 /* The opposite of mime_LineBuffer(): takes small buffers and packs them
00080    up into bigger buffers before passing them along.
00081 
00082    Pass in a desired_buffer_size 0 to tell it to flush (for example, in
00083    in the very last call to this function.)
00084  */
00085 extern "C" int
00086 mime_ReBuffer (const char *net_buffer, PRInt32 net_buffer_size,
00087                        PRUint32 desired_buffer_size,
00088                        char **bufferP, PRInt32 *buffer_sizeP, PRUint32 *buffer_fpP,
00089                        PRInt32 (*per_buffer_fn) (char *buffer, PRUint32 buffer_size,
00090                                                                  void *closure),
00091                        void *closure)
00092 {
00093   int status = 0;
00094 
00095   if (desired_buffer_size >= (PRUint32) (*buffer_sizeP))
00096        {
00097          status = mime_GrowBuffer (desired_buffer_size, sizeof(char), 1024,
00098                                                     bufferP, buffer_sizeP);
00099          if (status < 0) return status;
00100        }
00101 
00102   do
00103        {
00104          PRInt32 size = *buffer_sizeP - *buffer_fpP;
00105          if (size > net_buffer_size)
00106               size = net_buffer_size;
00107          if (size > 0)
00108               {
00109                 memcpy ((*bufferP) + (*buffer_fpP), net_buffer, size);
00110                 (*buffer_fpP) += size;
00111                 net_buffer += size;
00112                 net_buffer_size -= size;
00113               }
00114 
00115          if (*buffer_fpP > 0 &&
00116                 *buffer_fpP >= desired_buffer_size)
00117               {
00118                 status = (*per_buffer_fn) ((*bufferP), (*buffer_fpP), closure);
00119                 *buffer_fpP = 0;
00120                 if (status < 0) return status;
00121               }
00122        }
00123   while (net_buffer_size > 0);
00124 
00125   return 0;
00126 }
00127 
00128 static int
00129 convert_and_send_buffer(char* buf, int length, PRBool convert_newlines_p,
00130                                                  PRInt32 (*PR_CALLBACK per_line_fn) (char *line,
00131                                                                                       PRUint32 line_length,
00132                                                                                       void *closure),
00133                                                  void *closure)
00134 {
00135   /* Convert the line terminator to the native form.
00136    */
00137   char* newline;
00138 
00139 #if (MSG_LINEBREAK_LEN == 2)
00140   /***
00141   * This is a patch to support a mail DB corruption cause by earlier version that lead to a crash.
00142   * What happened is that the line terminator is CR+NULL+LF. Therefore, we first process a line
00143   * terminated by CR then a second line that contains only NULL+LF. We need to ignore this second
00144   * line. See bug http://bugzilla.mozilla.org/show_bug.cgi?id=61412 for more information.
00145   ***/
00146   if (length == 2 && buf[0] == 0x00 && buf[1] == nsCRT::LF)
00147     return 0;
00148 #endif
00149 
00150   NS_ASSERTION(buf && length > 0, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00151   if (!buf || length <= 0) return -1;
00152   newline = buf + length;
00153   NS_ASSERTION(newline[-1] == nsCRT::CR || newline[-1] == nsCRT::LF, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00154   if (newline[-1] != nsCRT::CR && newline[-1] != nsCRT::LF) return -1;
00155 
00156   if (!convert_newlines_p)
00157        {
00158        }
00159 #if (MSG_LINEBREAK_LEN == 1)
00160   else if ((newline - buf) >= 2 &&
00161                  newline[-2] == nsCRT::CR &&
00162                  newline[-1] == nsCRT::LF)
00163        {
00164          /* CRLF -> CR or LF */
00165          buf [length - 2] = MSG_LINEBREAK[0];
00166          length--;
00167        }
00168   else if (newline > buf + 1 &&
00169                  newline[-1] != MSG_LINEBREAK[0])
00170        {
00171          /* CR -> LF or LF -> CR */
00172          buf [length - 1] = MSG_LINEBREAK[0];
00173        }
00174 #else
00175   else if (((newline - buf) >= 2 && newline[-2] != nsCRT::CR) ||
00176                  ((newline - buf) >= 1 && newline[-1] != nsCRT::LF))
00177        {
00178          /* LF -> CRLF or CR -> CRLF */
00179          length++;
00180          buf[length - 2] = MSG_LINEBREAK[0];
00181          buf[length - 1] = MSG_LINEBREAK[1];
00182        }
00183 #endif
00184 
00185   return (*per_line_fn)(buf, length, closure);
00186 }
00187 
00188 extern "C" int
00189 mime_LineBuffer (const char *net_buffer, PRInt32 net_buffer_size,
00190                             char **bufferP, PRInt32 *buffer_sizeP, PRUint32 *buffer_fpP,
00191                             PRBool convert_newlines_p,
00192                             PRInt32 (*PR_CALLBACK per_line_fn) (char *line, PRUint32 line_length,
00193                                                                  void *closure),
00194                             void *closure)
00195 {
00196   int status = 0;
00197   if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == nsCRT::CR &&
00198          net_buffer_size > 0 && net_buffer[0] != nsCRT::LF) {
00199        /* The last buffer ended with a CR.  The new buffer does not start
00200           with a LF.  This old buffer should be shipped out and discarded. */
00201        NS_ASSERTION((PRUint32) *buffer_sizeP > *buffer_fpP, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
00202        if ((PRUint32) *buffer_sizeP <= *buffer_fpP) return -1;
00203        status = convert_and_send_buffer(*bufferP, *buffer_fpP,
00204                                                                        convert_newlines_p,
00205                                                                        per_line_fn, closure);
00206        if (status < 0) return status;
00207        *buffer_fpP = 0;
00208   }
00209   while (net_buffer_size > 0)
00210        {
00211          const char *net_buffer_end = net_buffer + net_buffer_size;
00212          const char *newline = 0;
00213          const char *s;
00214 
00215 
00216          for (s = net_buffer; s < net_buffer_end; s++)
00217               {
00218                 /* Move forward in the buffer until the first newline.
00219                       Stop when we see CRLF, CR, or LF, or the end of the buffer.
00220                       *But*, if we see a lone CR at the *very end* of the buffer,
00221                       treat this as if we had reached the end of the buffer without
00222                       seeing a line terminator.  This is to catch the case of the
00223                       buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
00224                  */
00225                 if (*s == nsCRT::CR || *s == nsCRT::LF)
00226                      {
00227                        newline = s;
00228                        if (newline[0] == nsCRT::CR)
00229                             {
00230                               if (s == net_buffer_end - 1)
00231                                    {
00232                                      /* CR at end - wait for the next character. */
00233                                      newline = 0;
00234                                      break;
00235                                    }
00236                               else if (newline[1] == nsCRT::LF)
00237                                    /* CRLF seen; swallow both. */
00238                                    newline++;
00239                             }
00240                        newline++;
00241                        break;
00242                      }
00243               }
00244 
00245          /* Ensure room in the net_buffer and append some or all of the current
00246                chunk of data to it. */
00247          {
00248               const char *end = (newline ? newline : net_buffer_end);
00249               PRUint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
00250 
00251               if (desired_size >= (PRUint32) (*buffer_sizeP))
00252                 {
00253                      status = mime_GrowBuffer (desired_size, sizeof(char), 1024,
00254                                                                 bufferP, buffer_sizeP);
00255                      if (status < 0) return status;
00256                 }
00257               memcpy ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
00258               (*buffer_fpP) += (end - net_buffer);
00259         (*bufferP)[*buffer_fpP] = '\0';
00260          }
00261 
00262          /* Now *bufferP contains either a complete line, or as complete
00263                a line as we have read so far.
00264 
00265                If we have a line, process it, and then remove it from `*bufferP'.
00266                Then go around the loop again, until we drain the incoming data.
00267           */
00268          if (!newline)
00269               return 0;
00270 
00271          status = convert_and_send_buffer(*bufferP, *buffer_fpP,
00272                                                                          convert_newlines_p,
00273                                                                          per_line_fn, closure);
00274          if (status < 0) 
00275       return status;
00276 
00277          net_buffer_size -= (newline - net_buffer);
00278          net_buffer = newline;
00279          (*buffer_fpP) = 0;
00280        }
00281   return 0;
00282 }