Back to index

lightning-sunbird  0.9+nobinonly
mimemsig.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "modmimee.h"
00039 #include "mimemsig.h"
00040 #include "nspr.h"
00041 
00042 #include "prmem.h"
00043 #include "plstr.h"
00044 #include "prerror.h"
00045 #include "nsMimeTypes.h"
00046 #include "msgCore.h"
00047 #include "nsMimeStringResources.h"
00048 #include "mimemoz2.h"
00049 
00050 
00051 #define MIME_SUPERCLASS mimeMultipartClass
00052 MimeDefClass(MimeMultipartSigned, MimeMultipartSignedClass,
00053                       mimeMultipartSignedClass, &MIME_SUPERCLASS);
00054 
00055 static int MimeMultipartSigned_initialize (MimeObject *);
00056 static int MimeMultipartSigned_create_child (MimeObject *);
00057 static int MimeMultipartSigned_close_child(MimeObject *);
00058 static int MimeMultipartSigned_parse_line (char *, PRInt32, MimeObject *);
00059 static int MimeMultipartSigned_parse_child_line (MimeObject *, char *, PRInt32,
00060                                                                                      PRBool);
00061 static int MimeMultipartSigned_parse_eof (MimeObject *, PRBool);
00062 static void MimeMultipartSigned_finalize (MimeObject *);
00063 
00064 static int MimeMultipartSigned_emit_child (MimeObject *obj);
00065 
00066 static int
00067 MimeMultipartSignedClassInitialize(MimeMultipartSignedClass *clazz)
00068 {
00069   MimeObjectClass    *oclass = (MimeObjectClass *)    clazz;
00070   MimeMultipartClass *mclass = (MimeMultipartClass *) clazz;
00071 
00072   oclass->initialize       = MimeMultipartSigned_initialize;
00073   oclass->parse_line       = MimeMultipartSigned_parse_line;
00074   oclass->parse_eof        = MimeMultipartSigned_parse_eof;
00075   oclass->finalize         = MimeMultipartSigned_finalize;
00076   mclass->create_child     = MimeMultipartSigned_create_child;
00077   mclass->parse_child_line = MimeMultipartSigned_parse_child_line;
00078   mclass->close_child      = MimeMultipartSigned_close_child;
00079 
00080   PR_ASSERT(!oclass->class_initialized);
00081   return 0;
00082 }
00083 
00084 static int
00085 MimeMultipartSigned_initialize (MimeObject *object)
00086 {
00087   MimeMultipartSigned *sig = (MimeMultipartSigned *) object;
00088 
00089   /* This is an abstract class; it shouldn't be directly instantiated. */
00090   PR_ASSERT(object->clazz != (MimeObjectClass *) &mimeMultipartSignedClass);
00091 
00092   sig->state = MimeMultipartSignedPreamble;
00093 
00094   return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
00095 }
00096 
00097 static void
00098 MimeMultipartSigned_cleanup (MimeObject *obj, PRBool finalizing_p)
00099 {
00100   MimeMultipart *mult = (MimeMultipart *) obj; /* #58075.  Fix suggested by jwz */
00101   MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
00102   if (sig->part_buffer)
00103        {
00104          MimePartBufferDestroy(sig->part_buffer);
00105          sig->part_buffer = 0;
00106        }
00107   if (sig->body_hdrs)
00108        {
00109          MimeHeaders_free (sig->body_hdrs);
00110          sig->body_hdrs = 0;
00111        }
00112   if (sig->sig_hdrs)
00113        {
00114          MimeHeaders_free (sig->sig_hdrs);
00115          sig->sig_hdrs = 0;
00116        }
00117 
00118   mult->state = MimeMultipartEpilogue;  /* #58075.  Fix suggested by jwz */
00119   sig->state = MimeMultipartSignedEpilogue;
00120 
00121   if (finalizing_p && sig->crypto_closure) {
00122     /* Don't free these until this object is really going away -- keep them
00123        around for the lifetime of the MIME object, so that we can get at the
00124        security info of sub-parts of the currently-displayed message. */
00125     ((MimeMultipartSignedClass *) obj->clazz)->crypto_free (sig->crypto_closure);
00126      sig->crypto_closure = 0;
00127   }
00128 
00129   if (sig->sig_decoder_data)
00130        {
00131          MimeDecoderDestroy(sig->sig_decoder_data, PR_TRUE);
00132          sig->sig_decoder_data = 0;
00133        }
00134 }
00135 
00136 static int
00137 MimeMultipartSigned_parse_eof (MimeObject *obj, PRBool abort_p)
00138 {
00139   MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
00140   int status = 0;
00141 
00142   if (obj->closed_p) return 0;
00143 
00144   /* Close off the signature, if we've gotten that far.
00145    */
00146   if (sig->state == MimeMultipartSignedSignatureHeaders ||
00147          sig->state == MimeMultipartSignedSignatureFirstLine ||
00148          sig->state == MimeMultipartSignedSignatureLine ||
00149          sig->state == MimeMultipartSignedEpilogue)
00150        {
00151     status = (((MimeMultipartSignedClass *) obj->clazz)->crypto_signature_eof) (sig->crypto_closure, abort_p);
00152     if (status < 0) return status;
00153        }
00154 
00155   if (!abort_p)
00156        {
00157          /* Now that we've read both the signed object and the signature (and
00158                have presumably verified the signature) write out a blurb, and then
00159                the signed object.
00160           */
00161          status = MimeMultipartSigned_emit_child(obj);
00162          if (status < 0) return status;
00163        }
00164 
00165   MimeMultipartSigned_cleanup(obj, PR_FALSE);
00166   return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
00167 }
00168 
00169 
00170 static void
00171 MimeMultipartSigned_finalize (MimeObject *obj)
00172 {
00173   MimeMultipartSigned_cleanup(obj, PR_TRUE);
00174   ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(obj);
00175 }
00176 
00177 
00178 static int
00179 MimeMultipartSigned_parse_line (char *line, PRInt32 length, MimeObject *obj)
00180 {
00181   MimeMultipart *mult = (MimeMultipart *) obj;
00182   MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
00183   MimeMultipartParseState old_state = mult->state;
00184   PRBool hash_line_p = PR_TRUE;
00185   PRBool no_headers_p = PR_FALSE;
00186   int status = 0;
00187 
00188   /* First do the parsing for normal multipart/ objects by handing it off to
00189         the superclass method.  This includes calling the create_child and
00190         close_child methods.
00191    */
00192   status = (((MimeObjectClass *)(&MIME_SUPERCLASS))
00193                      ->parse_line (line, length, obj));
00194   if (status < 0) return status;
00195 
00196   /* The instance variable MimeMultipartClass->state tracks motion through
00197         the various stages of multipart/ parsing.  The instance variable
00198         MimeMultipartSigned->state tracks the difference between the first
00199         part (the body) and the second part (the signature.)  This second,
00200         more specific state variable is updated by noticing the transitions
00201         of the first, more general state variable.
00202    */
00203   if (old_state != mult->state)  /* there has been a state change */
00204        {
00205          switch (mult->state)
00206               {
00207               case MimeMultipartPreamble:
00208                 PR_ASSERT(0);  /* can't move *in* to preamble state. */
00209                 sig->state = MimeMultipartSignedPreamble;
00210                 break;
00211 
00212               case MimeMultipartHeaders:
00213                 /* If we're moving in to the Headers state, then that means
00214                       that this line is the preceeding boundary string (and we
00215                       should ignore it.)
00216                  */
00217                 hash_line_p = PR_FALSE;
00218 
00219                 if (sig->state == MimeMultipartSignedPreamble)
00220                      sig->state = MimeMultipartSignedBodyFirstHeader;
00221                 else if (sig->state == MimeMultipartSignedBodyFirstLine ||
00222                                sig->state == MimeMultipartSignedBodyLine)
00223                      sig->state = MimeMultipartSignedSignatureHeaders;
00224                 else if (sig->state == MimeMultipartSignedSignatureFirstLine ||
00225                                sig->state == MimeMultipartSignedSignatureLine)
00226                      sig->state = MimeMultipartSignedEpilogue;
00227                 break;
00228 
00229               case MimeMultipartPartFirstLine:
00230                 if (sig->state == MimeMultipartSignedBodyFirstHeader)
00231                      {                    
00232                        sig->state = MimeMultipartSignedBodyFirstLine;
00233                        no_headers_p = PR_TRUE;
00234                      }
00235                 else if (sig->state == MimeMultipartSignedBodyHeaders)
00236                      sig->state = MimeMultipartSignedBodyFirstLine;
00237                 else if (sig->state == MimeMultipartSignedSignatureHeaders)
00238                      sig->state = MimeMultipartSignedSignatureFirstLine;
00239                 else
00240                      sig->state = MimeMultipartSignedEpilogue;
00241                 break;
00242 
00243               case MimeMultipartPartLine:
00244 
00245                 PR_ASSERT(sig->state == MimeMultipartSignedBodyFirstLine ||
00246                                    sig->state == MimeMultipartSignedBodyLine ||
00247                                    sig->state == MimeMultipartSignedSignatureFirstLine ||
00248                                    sig->state == MimeMultipartSignedSignatureLine);
00249 
00250                 if (sig->state == MimeMultipartSignedBodyFirstLine)
00251                      sig->state = MimeMultipartSignedBodyLine;
00252                 else if (sig->state == MimeMultipartSignedSignatureFirstLine)
00253                      sig->state = MimeMultipartSignedSignatureLine;
00254                 break;
00255 
00256               case MimeMultipartEpilogue:
00257                 sig->state = MimeMultipartSignedEpilogue;
00258                 break;
00259 
00260               default:  /* bad state */
00261                 PR_ASSERT(0);
00262                 return -1;
00263                 break;
00264               }
00265        }
00266 
00267 
00268   /* Perform multipart/signed-related actions on this line based on the state
00269         of the parser.
00270    */
00271   switch (sig->state)
00272        {
00273        case MimeMultipartSignedPreamble:
00274          /* Do nothing. */
00275          break;
00276 
00277        case MimeMultipartSignedBodyFirstLine:
00278          /* We have just moved out of the MimeMultipartSignedBodyHeaders
00279                state, so cache away the headers that apply only to the body part.
00280           */
00281          PR_ASSERT(mult->hdrs);
00282          PR_ASSERT(!sig->body_hdrs);
00283          sig->body_hdrs = mult->hdrs;
00284          mult->hdrs = 0;
00285 
00286          /* fall through. */
00287 
00288        case MimeMultipartSignedBodyFirstHeader:
00289        case MimeMultipartSignedBodyHeaders:
00290        case MimeMultipartSignedBodyLine:
00291 
00292          if (!sig->crypto_closure)
00293               {
00294                 /* Set error change */
00295                 PR_SetError(0, 0);
00296                 /* Initialize the signature verification library. */
00297                 sig->crypto_closure = (((MimeMultipartSignedClass *) obj->clazz)
00298                                                          ->crypto_init) (obj);
00299                 if (!sig->crypto_closure)
00300                      {
00301                        status = PR_GetError();
00302                        PR_ASSERT(status < 0);
00303                        if (status >= 0) status = -1;
00304                        return status;
00305                      }
00306               }
00307 
00308          if (hash_line_p)
00309               {
00310                 /* this is the first hashed line if this is the first header
00311                       (that is, if it's the first line in the header state after
00312                       a state change.)
00313                  */
00314                 PRBool first_line_p
00315                      = (no_headers_p ||
00316                         sig->state == MimeMultipartSignedBodyFirstHeader);
00317 
00318                 if (sig->state == MimeMultipartSignedBodyFirstHeader)
00319                      sig->state = MimeMultipartSignedBodyHeaders;
00320 
00321                 /* The newline issues here are tricky, since both the newlines
00322                       before and after the boundary string are to be considered part
00323                       of the boundary: this is so that a part can be specified such
00324                       that it does not end in a trailing newline.
00325 
00326                       To implement this, we send a newline *before* each line instead
00327                       of after, except for the first line, which is not preceeded by a
00328                       newline.
00329 
00330                       For purposes of cryptographic hashing, we always hash line
00331                       breaks as CRLF -- the canonical, on-the-wire linebreaks, since
00332                       we have no idea of knowing what line breaks were used on the
00333                       originating system (SMTP rightly destroys that information.)
00334                  */
00335 
00336                 /* Remove the trailing newline... */
00337                 if (length > 0 && line[length-1] == nsCRT::LF) length--;
00338                 if (length > 0 && line[length-1] == nsCRT::CR) length--;
00339 
00340                 PR_ASSERT(sig->crypto_closure);
00341 
00342                 if (!first_line_p)
00343                      {
00344                        /* Push out a preceeding newline... */
00345                        char nl[] = CRLF;
00346                        status = (((MimeMultipartSignedClass *) obj->clazz)
00347                                           ->crypto_data_hash (nl, 2, sig->crypto_closure));
00348                        if (status < 0) return status;
00349                      }
00350 
00351                 /* Now push out the line sans trailing newline. */
00352                 if (length > 0)
00353                      status = (((MimeMultipartSignedClass *) obj->clazz)
00354                                      ->crypto_data_hash (line,length, sig->crypto_closure));
00355                 if (status < 0) return status;
00356               }
00357          break;
00358 
00359        case MimeMultipartSignedSignatureHeaders:
00360 
00361          if (sig->crypto_closure &&
00362                 old_state != mult->state)
00363               {
00364                 /* We have just moved out of the MimeMultipartSignedBodyLine
00365                       state, so tell the signature verification library that we've
00366                       reached the end of the signed data.
00367                  */
00368                 status = (((MimeMultipartSignedClass *) obj->clazz)
00369                                    ->crypto_data_eof) (sig->crypto_closure, PR_FALSE);
00370                 if (status < 0) return status;
00371               }
00372          break;
00373 
00374        case MimeMultipartSignedSignatureFirstLine:
00375          /* We have just moved out of the MimeMultipartSignedSignatureHeaders
00376                state, so cache away the headers that apply only to the sig part.
00377           */
00378          PR_ASSERT(mult->hdrs);
00379          PR_ASSERT(!sig->sig_hdrs);
00380          sig->sig_hdrs = mult->hdrs;
00381          mult->hdrs = 0;
00382 
00383 
00384          /* If the signature block has an encoding, set up a decoder for it.
00385                (Similar logic is in MimeLeafClass->parse_begin.)
00386           */
00387          {
00388               MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32,void*), void*) = 0;
00389     nsXPIDLCString encoding;
00390     encoding.Adopt(MimeHeaders_get (sig->sig_hdrs,
00391                    HEADER_CONTENT_TRANSFER_ENCODING,
00392                    PR_TRUE, PR_FALSE));
00393     if (encoding.IsEmpty())
00394       ;
00395     else if (!nsCRT::strcasecmp(encoding.get(), ENCODING_BASE64))
00396       fn = &MimeB64DecoderInit;
00397     else if (!nsCRT::strcasecmp(encoding.get(), ENCODING_QUOTED_PRINTABLE))
00398     {
00399       sig->sig_decoder_data =
00400        MimeQPDecoderInit (((nsresult (*) (const char *, PRInt32, void *))
00401                (((MimeMultipartSignedClass *) obj->clazz)
00402                     ->crypto_signature_hash)),
00403               sig->crypto_closure);
00404       if (!sig->sig_decoder_data)
00405        return MIME_OUT_OF_MEMORY;
00406     }
00407     else if (!nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE) ||
00408              !nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE2) ||
00409              !nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE3) ||
00410              !nsCRT::strcasecmp(encoding.get(), ENCODING_UUENCODE4))
00411       fn = &MimeUUDecoderInit;
00412     else if (!nsCRT::strcasecmp(encoding.get(), ENCODING_YENCODE))
00413       fn = &MimeYDecoderInit;
00414               if (fn)
00415                 {
00416                      sig->sig_decoder_data =
00417                        fn (((nsresult (*) (const char *, PRInt32, void *))
00418                                (((MimeMultipartSignedClass *) obj->clazz)
00419                                    ->crypto_signature_hash)),
00420                               sig->crypto_closure);
00421                      if (!sig->sig_decoder_data)
00422                        return MIME_OUT_OF_MEMORY;
00423                 }
00424          }
00425 
00426          /* Show these headers to the crypto module. */
00427          if (hash_line_p)
00428               {
00429                 status = (((MimeMultipartSignedClass *) obj->clazz)
00430                                    ->crypto_signature_init) (sig->crypto_closure,
00431                                                                                obj, sig->sig_hdrs);
00432                 if (status < 0) return status;
00433               }
00434 
00435          /* fall through. */
00436 
00437        case MimeMultipartSignedSignatureLine:
00438          if (hash_line_p)
00439               {
00440                 /* Feed this line into the signature verification routines. */
00441 
00442                 if (sig->sig_decoder_data)
00443                      status = MimeDecoderWrite (sig->sig_decoder_data, line, length);
00444                 else
00445                      status = (((MimeMultipartSignedClass *) obj->clazz)
00446                                      ->crypto_signature_hash (line, length,
00447                                                                                 sig->crypto_closure));
00448                 if (status < 0) return status;
00449               }
00450          break;
00451 
00452        case MimeMultipartSignedEpilogue:
00453          /* Nothing special to do here. */
00454          break;
00455 
00456        default:  /* bad state */
00457          PR_ASSERT(0);
00458          return -1;
00459        }
00460 
00461   return status;
00462 }
00463 
00464 
00465 static int
00466 MimeMultipartSigned_create_child (MimeObject *parent)
00467 {
00468   /* Don't actually create a child -- we call the superclass create_child
00469         method later, after we've fully parsed everything.  (And we only call
00470         it once, for part #1, and never for part #2 (the signature.))
00471    */
00472   MimeMultipart *mult = (MimeMultipart *) parent;
00473   mult->state = MimeMultipartPartFirstLine;
00474   return 0;
00475 }
00476 
00477 
00478 static int
00479 MimeMultipartSigned_close_child (MimeObject *obj)
00480 {
00481   /* The close_child method on MimeMultipartSigned doesn't actually do
00482         anything to the children list, since the create_child method also
00483         doesn't do anything.
00484    */
00485   MimeMultipart *mult = (MimeMultipart *) obj;
00486   MimeContainer *cont = (MimeContainer *) obj;
00487   MimeMultipartSigned *msig = (MimeMultipartSigned *) obj;
00488 
00489   if (msig->part_buffer)
00490        /* Closes the tmp file, if there is one: doesn't free the part_buffer. */
00491        MimePartBufferClose(msig->part_buffer);
00492 
00493   if (mult->hdrs)    /* duplicated from MimeMultipart_close_child, ugh. */
00494        {
00495          MimeHeaders_free(mult->hdrs);
00496          mult->hdrs = 0;
00497        }
00498 
00499   /* Should be no kids yet. */
00500   PR_ASSERT(cont->nchildren == 0);
00501   if (cont->nchildren != 0) return -1;
00502 
00503   return 0;
00504 }
00505 
00506 
00507 static int
00508 MimeMultipartSigned_parse_child_line (MimeObject *obj,
00509                                                                  char *line, PRInt32 length,
00510                                                                  PRBool first_line_p)
00511 {
00512   MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
00513   MimeContainer *cont = (MimeContainer *) obj;
00514   int status = 0;
00515 
00516   /* Shouldn't have made any sub-parts yet. */
00517   PR_ASSERT(cont->nchildren == 0);
00518   if (cont->nchildren != 0) return -1;
00519 
00520   switch (sig->state)
00521        {
00522        case MimeMultipartSignedPreamble:
00523        case MimeMultipartSignedBodyFirstHeader:
00524        case MimeMultipartSignedBodyHeaders:
00525          PR_ASSERT(0);  /* How'd we get here?  Oh well, fall through. */
00526 
00527        case MimeMultipartSignedBodyFirstLine:
00528          PR_ASSERT(first_line_p);
00529          if (!sig->part_buffer)
00530               {
00531                 sig->part_buffer = MimePartBufferCreate();
00532                 if (!sig->part_buffer)
00533                      return MIME_OUT_OF_MEMORY;
00534               }
00535          /* fall through */
00536 
00537        case MimeMultipartSignedBodyLine:
00538          {
00539               /* This is the first part; we are buffering it, and will emit it all
00540                  at the end (so that we know whether the signature matches before
00541                  showing anything to the user.)
00542                */
00543 
00544               /* The newline issues here are tricky, since both the newlines
00545                  before and after the boundary string are to be considered part
00546                  of the boundary: this is so that a part can be specified such
00547                  that it does not end in a trailing newline.
00548 
00549                  To implement this, we send a newline *before* each line instead
00550                  of after, except for the first line, which is not preceeded by a
00551                  newline.
00552                */
00553 
00554               /* Remove the trailing newline... */
00555               if (length > 0 && line[length-1] == nsCRT::LF) length--;
00556               if (length > 0 && line[length-1] == nsCRT::CR) length--;
00557 
00558               PR_ASSERT(sig->part_buffer);
00559               PR_ASSERT(first_line_p ==
00560                               (sig->state == MimeMultipartSignedBodyFirstLine));
00561 
00562               if (!first_line_p)
00563                 {
00564                      /* Push out a preceeding newline... */
00565                      char nl[] = MSG_LINEBREAK;
00566                      status = MimePartBufferWrite (sig->part_buffer, nl, MSG_LINEBREAK_LEN);
00567                      if (status < 0) return status;
00568                 }
00569 
00570               /* Now push out the line sans trailing newline. */
00571               if (length > 0)
00572                      status = MimePartBufferWrite (sig->part_buffer, line, length);
00573               if (status < 0) return status;
00574          }
00575        break;
00576 
00577        case MimeMultipartSignedSignatureHeaders:
00578          PR_ASSERT(0);  /* How'd we get here?  Oh well, fall through. */
00579 
00580        case MimeMultipartSignedSignatureFirstLine:
00581        case MimeMultipartSignedSignatureLine:
00582          /* Nothing to do here -- hashing of the signature part is handled up
00583                in MimeMultipartSigned_parse_line().
00584           */
00585          break;
00586 
00587        case MimeMultipartSignedEpilogue:
00588          /* Too many kids?  MimeMultipartSigned_create_child() should have
00589                prevented us from getting here. */
00590          PR_ASSERT(0);
00591          return -1;
00592          break;
00593 
00594        default: /* bad state */
00595          PR_ASSERT(0);
00596          return -1;
00597          break;
00598        }
00599 
00600   return status;
00601 }
00602 
00603 
00604 static int
00605 MimeMultipartSigned_emit_child (MimeObject *obj)
00606 {
00607   MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
00608   MimeMultipart *mult = (MimeMultipart *) obj;
00609   MimeContainer *cont = (MimeContainer *) obj;
00610   int status = 0;
00611   MimeObject *body;
00612 
00613   NS_ASSERTION(sig->crypto_closure, "no crypto closure");
00614 
00615   /* Emit some HTML saying whether the signature was cool.
00616         But don't emit anything if in FO_QUOTE_MESSAGE mode.
00617    */
00618   if (obj->options &&
00619          obj->options->headers != MimeHeadersCitation &&
00620          obj->options->write_html_p &&
00621          obj->options->output_fn &&
00622          obj->options->headers != MimeHeadersCitation &&
00623          sig->crypto_closure)
00624        {
00625          char *html = (((MimeMultipartSignedClass *) obj->clazz)
00626                                    ->crypto_generate_html (sig->crypto_closure));
00627 #if 0 // XXX For the moment, no HTML output. Fix this XXX //
00628          if (!html) return -1; /* MIME_OUT_OF_MEMORY? */
00629 
00630          status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE);
00631          PR_Free(html);
00632          if (status < 0) return status;
00633 #endif
00634 
00635          /* Now that we have written out the crypto stamp, the outermost header
00636                block is well and truly closed.  If this is in fact the outermost
00637                message, then run the post_header_html_fn now.
00638           */
00639          if (obj->options &&
00640                 obj->options->state &&
00641                 obj->options->generate_post_header_html_fn &&
00642                 !obj->options->state->post_header_html_run_p)
00643               {
00644                 MimeHeaders *outer_headers=nsnull;
00645                 MimeObject *p;
00646                 for (p = obj; p->parent; p = p->parent)
00647                      outer_headers = p->headers;
00648                 PR_ASSERT(obj->options->state->first_data_written_p);
00649                 html = obj->options->generate_post_header_html_fn(NULL,
00650                                                                                            obj->options->html_closure,
00651                                                                                                          outer_headers);
00652                 obj->options->state->post_header_html_run_p = PR_TRUE;
00653                 if (html)
00654                      {
00655                        status = MimeObject_write(obj, html, strlen(html), PR_FALSE);
00656                        PR_Free(html);
00657                        if (status < 0) return status;
00658                      }
00659               }
00660        }
00661 
00662 
00663   /* Oh, this is fairly nasty.  We're skipping over our "create child" method
00664         and using the one our superclass defines.  Perhaps instead we should add
00665         a new method on this class, and initialize that method to be the
00666         create_child method of the superclass.  Whatever.
00667    */
00668 
00669 
00670   /* The superclass method expects to find the headers for the part that it's
00671         to create in mult->hdrs, so ensure that they're there. */
00672   PR_ASSERT(!mult->hdrs);
00673   if (mult->hdrs) MimeHeaders_free(mult->hdrs);
00674   mult->hdrs = sig->body_hdrs;
00675   sig->body_hdrs = 0;
00676 
00677   /* Run the superclass create_child method.
00678    */
00679   status = (((MimeMultipartClass *)(&MIME_SUPERCLASS))->create_child(obj));
00680   if (status < 0) return status;
00681 
00682   // Notify the charset of the first part.
00683   if (obj->options && !(obj->options->override_charset)) {
00684     MimeObject *firstChild = ((MimeContainer*) obj)->children[0];
00685     char *disposition = MimeHeaders_get (firstChild->headers,
00686                                          HEADER_CONTENT_DISPOSITION, 
00687                                          PR_TRUE,
00688                                          PR_FALSE);
00689     // check if need to show as inline
00690     if (!disposition)
00691     {
00692       const char *content_type = firstChild->content_type;
00693       if (!nsCRT::strcasecmp (content_type, TEXT_PLAIN) ||
00694           !nsCRT::strcasecmp (content_type, TEXT_HTML) ||
00695           !nsCRT::strcasecmp (content_type, TEXT_MDL) ||
00696           !nsCRT::strcasecmp (content_type, MULTIPART_ALTERNATIVE) ||
00697           !nsCRT::strcasecmp (content_type, MULTIPART_RELATED) ||
00698           !nsCRT::strcasecmp (content_type, MESSAGE_NEWS) ||
00699           !nsCRT::strcasecmp (content_type, MESSAGE_RFC822)) {
00700         char *ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
00701         if (ct) {
00702           char *cset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL);
00703           if (cset) {
00704             mimeEmitterUpdateCharacterSet(obj->options, cset);
00705             SetMailCharacterSetToMsgWindow(obj, cset);
00706             PR_Free(cset);
00707           }
00708           PR_Free(ct);
00709         }
00710       }
00711     }
00712   }
00713 
00714   /* Retrieve the child that it created.
00715    */
00716   PR_ASSERT(cont->nchildren == 1);
00717   if (cont->nchildren != 1) return -1;
00718   body = cont->children[0];
00719   PR_ASSERT(body);
00720   if (!body) return -1;
00721 
00722 #ifdef MIME_DRAFTS
00723   if (body->options->decompose_file_p) {
00724          body->options->signed_p = PR_TRUE;
00725          if (!mime_typep(body, (MimeObjectClass*)&mimeMultipartClass) &&
00726               body->options->decompose_file_init_fn)
00727               body->options->decompose_file_init_fn ( body->options->stream_closure, body->headers );
00728   }
00729 #endif /* MIME_DRAFTS */
00730 
00731   /* If there's no part_buffer, this is a zero-length signed message? */
00732   if (sig->part_buffer)
00733        {
00734 #ifdef MIME_DRAFTS
00735          if (body->options->decompose_file_p &&
00736                 !mime_typep(body, (MimeObjectClass*)&mimeMultipartClass)  &&
00737                 body->options->decompose_file_output_fn)
00738                 status = MimePartBufferRead (sig->part_buffer,
00739                                                     /* The (nsresult (*) ...) cast is to turn the
00740                                                           `void' argument into `MimeObject'. */
00741                                                     ((nsresult (*) (const char *, PRInt32, void *))
00742                                                     body->options->decompose_file_output_fn),
00743                                                     body->options->stream_closure);
00744          else
00745 #endif /* MIME_DRAFTS */
00746 
00747          status = MimePartBufferRead (sig->part_buffer,
00748                                                     /* The (nsresult (*) ...) cast is to turn the
00749                                                           `void' argument into `MimeObject'. */
00750                                                     ((nsresult (*) (const char *, PRInt32, void *))
00751                                                         body->clazz->parse_buffer),
00752                                                         body);
00753          if (status < 0) return status;
00754        }
00755 
00756   MimeMultipartSigned_cleanup(obj, PR_FALSE);
00757 
00758   /* Done parsing. */
00759   status = body->clazz->parse_eof(body, PR_FALSE);
00760   if (status < 0) return status;
00761   status = body->clazz->parse_end(body, PR_FALSE);
00762   if (status < 0) return status;
00763 
00764 #ifdef MIME_DRAFTS
00765   if (body->options->decompose_file_p &&
00766          !mime_typep(body, (MimeObjectClass*)&mimeMultipartClass)  &&
00767          body->options->decompose_file_close_fn)
00768          body->options->decompose_file_close_fn(body->options->stream_closure);
00769 #endif /* MIME_DRAFTS */
00770 
00771   /* Put out a separator after every multipart/signed object. */
00772   status = MimeObject_write_separator(obj);
00773   if (status < 0) return status;
00774 
00775   return 0;
00776 }