Back to index

lightning-sunbird  0.9+nobinonly
mimecms.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; 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 Communicator.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corp..
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s): 
00023  *   Kai Engert <kengert@redhat.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 
00039 #include "nsICMSMessage.h"
00040 #include "nsICMSMessage2.h"
00041 #include "nsICMSMessageErrors.h"
00042 #include "nsICMSDecoder.h"
00043 #include "mimecms.h"
00044 #include "mimemsig.h"
00045 #include "nsCRT.h"
00046 #include "nspr.h"
00047 #include "nsEscape.h"
00048 #include "mimemsg.h"
00049 #include "mimemoz2.h"
00050 #include "nsIURI.h"
00051 #include "nsIMsgWindow.h"
00052 #include "nsIMsgMailNewsUrl.h"
00053 #include "nsIMimeMiscStatus.h"
00054 #include "nsIMsgSMIMEHeaderSink.h"
00055 #include "nsCOMPtr.h"
00056 #include "nsIX509Cert.h"
00057 #include "nsIMsgHeaderParser.h"
00058 #include "nsIProxyObjectManager.h"
00059 
00060 
00061 #define MIME_SUPERCLASS mimeEncryptedClass
00062 MimeDefClass(MimeEncryptedCMS, MimeEncryptedCMSClass,
00063        mimeEncryptedCMSClass, &MIME_SUPERCLASS);
00064 
00065 static void *MimeCMS_init(MimeObject *, int (*output_fn) (const char *, PRInt32, void *), void *);
00066 static int MimeCMS_write (const char *, PRInt32, void *);
00067 static int MimeCMS_eof (void *, PRBool);
00068 static char * MimeCMS_generate (void *);
00069 static void MimeCMS_free (void *);
00070 
00071 extern int SEC_ERROR_CERT_ADDR_MISMATCH;
00072 
00073 static int MimeEncryptedCMSClassInitialize(MimeEncryptedCMSClass *clazz)
00074 {
00075 #ifdef DEBUG
00076   MimeObjectClass    *oclass = (MimeObjectClass *)    clazz;
00077   NS_ASSERTION(!oclass->class_initialized, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
00078 #endif
00079 
00080   MimeEncryptedClass *eclass = (MimeEncryptedClass *) clazz;
00081   eclass->crypto_init          = MimeCMS_init;
00082   eclass->crypto_write         = MimeCMS_write;
00083   eclass->crypto_eof           = MimeCMS_eof;
00084   eclass->crypto_generate_html = MimeCMS_generate;
00085   eclass->crypto_free          = MimeCMS_free;
00086 
00087   return 0;
00088 }
00089 
00090 
00091 typedef struct MimeCMSdata
00092 {
00093   int (*output_fn) (const char *buf, PRInt32 buf_size, void *output_closure);
00094   void *output_closure;
00095   nsCOMPtr<nsICMSDecoder> decoder_context;
00096   nsCOMPtr<nsICMSMessage> content_info;
00097   PRBool ci_is_encrypted;
00098   char *sender_addr;
00099   PRBool decoding_failed;
00100   PRUint32 decoded_bytes;
00101   MimeObject *self;
00102   PRBool parent_is_encrypted_p;
00103   PRBool parent_holds_stamp_p;
00104   nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
00105   
00106   MimeCMSdata()
00107   :output_fn(nsnull),
00108   output_closure(nsnull),
00109   ci_is_encrypted(PR_FALSE),
00110   sender_addr(nsnull),
00111   decoding_failed(PR_FALSE),
00112   decoded_bytes(0),
00113   self(nsnull),
00114   parent_is_encrypted_p(PR_FALSE),
00115   parent_holds_stamp_p(PR_FALSE)
00116   {
00117   }
00118   
00119   ~MimeCMSdata()
00120   {
00121     if(sender_addr)
00122       PR_Free(sender_addr);
00123 
00124     // Do an orderly release of nsICMSDecoder and nsICMSMessage //
00125     if (decoder_context)
00126     {
00127       nsCOMPtr<nsICMSMessage> cinfo;
00128       decoder_context->Finish(getter_AddRefs(cinfo));
00129     }
00130   }
00131 } MimeCMSdata;
00132 
00133 /*   SEC_PKCS7DecoderContentCallback for SEC_PKCS7DecoderStart() */
00134 static void MimeCMS_content_callback (void *arg, const char *buf, unsigned long length)
00135 {
00136   int status;
00137   MimeCMSdata *data = (MimeCMSdata *) arg;
00138   if (!data) return;
00139 
00140   if (!data->output_fn)
00141     return;
00142 
00143   PR_SetError(0,0);
00144   status = data->output_fn (buf, length, data->output_closure);
00145   if (status < 0)
00146   {
00147     PR_SetError(status, 0);
00148     data->output_fn = 0;
00149     return;
00150   }
00151 
00152   data->decoded_bytes += length;
00153 }
00154 
00155 PRBool MimeEncryptedCMS_encrypted_p (MimeObject *obj)
00156 {
00157   PRBool encrypted;
00158 
00159   if (!obj) return PR_FALSE;
00160   if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass))
00161   {
00162     MimeEncrypted *enc = (MimeEncrypted *) obj;
00163     MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
00164     if (!data || !data->content_info) return PR_FALSE;
00165                 data->content_info->ContentIsEncrypted(&encrypted);
00166           return encrypted;
00167   }
00168   return PR_FALSE;
00169 }
00170 
00171 // extern MimeMessageClass mimeMessageClass;      /* gag */
00172 
00173 static void ParseRFC822Addresses (const char *line, nsXPIDLCString &names, nsXPIDLCString &addresses)
00174 {
00175   PRUint32 numAddresses;
00176   nsresult res;
00177   nsCOMPtr<nsIMsgHeaderParser> pHeader = do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID, &res);
00178 
00179   if (NS_SUCCEEDED(res))
00180   {
00181     pHeader->ParseHeaderAddresses(nsnull, line, getter_Copies(names), getter_Copies(addresses), &numAddresses);
00182   }
00183 }
00184 
00185 PRBool MimeCMSHeadersAndCertsMatch(nsICMSMessage *content_info, 
00186                                    nsIX509Cert *signerCert,
00187                                    const char *from_addr,
00188                                    const char *from_name,
00189                                    const char *sender_addr,
00190                                    const char *sender_name,
00191                                    PRBool *signing_cert_without_email_address)
00192 {
00193   nsXPIDLCString cert_addr;
00194   PRBool match = PR_TRUE;
00195   PRBool foundFrom = PR_FALSE;
00196   PRBool foundSender = PR_FALSE;
00197 
00198   /* Find the name and address in the cert.
00199    */
00200   if (content_info)
00201   {
00202     // Extract any address contained in the cert.
00203     // This will be used for testing, whether the cert contains no addresses at all.
00204     content_info->GetSignerEmailAddress (getter_Copies(cert_addr));
00205   }
00206 
00207   if (signing_cert_without_email_address)
00208   {
00209     *signing_cert_without_email_address = (!cert_addr);
00210   }
00211 
00212   /* Now compare them --
00213    consider it a match if the address in the cert matches either the
00214    address in the From or Sender field
00215    */
00216 
00217   /* If there is no addr in the cert at all, it can not match and we fail. */
00218   if (!cert_addr)
00219   {
00220     match = PR_FALSE;
00221   }
00222   else
00223   {
00224     if (signerCert)
00225     {
00226       if (from_addr && *from_addr)
00227       {
00228         NS_ConvertASCIItoUCS2 ucs2From(from_addr);
00229         if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2From, &foundFrom)))
00230         {
00231           foundFrom = PR_FALSE;
00232         }
00233       }
00234 
00235       if (sender_addr && *sender_addr)
00236       {
00237         NS_ConvertASCIItoUCS2 ucs2Sender(sender_addr);
00238         if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2Sender, &foundSender)))
00239         {
00240           foundSender = PR_FALSE;
00241         }
00242       }
00243     }
00244 
00245     if (!foundSender && !foundFrom)
00246     {
00247       match = PR_FALSE;
00248     }
00249   }
00250 
00251   return match;
00252 }
00253 
00254 class nsSMimeVerificationListener : public nsISMimeVerificationListener
00255 {
00256 public:
00257   NS_DECL_ISUPPORTS
00258   NS_DECL_NSISMIMEVERIFICATIONLISTENER
00259 
00260   nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName,
00261                               const char *aSenderAddr, const char *aSenderName,
00262                               nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel);
00263 
00264   virtual ~nsSMimeVerificationListener() {}
00265   
00266 protected:
00267   nsCOMPtr<nsIMsgSMIMEHeaderSink> mHeaderSink;
00268   PRInt32 mMimeNestingLevel;
00269 
00270   nsXPIDLCString mFromAddr;
00271   nsXPIDLCString mFromName;
00272   nsXPIDLCString mSenderAddr;
00273   nsXPIDLCString mSenderName;
00274 };
00275 
00276 NS_IMPL_ISUPPORTS1(nsSMimeVerificationListener, nsISMimeVerificationListener)
00277 
00278 nsSMimeVerificationListener::nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName,
00279                                                          const char *aSenderAddr, const char *aSenderName,
00280                                                          nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel)
00281 {
00282   mHeaderSink = aHeaderSink;
00283   mMimeNestingLevel = aMimeNestingLevel;
00284 
00285   mFromAddr = aFromAddr;
00286   mFromName = aFromName;
00287   mSenderAddr = aSenderAddr;
00288   mSenderName = aSenderName;
00289 }
00290 
00291 NS_IMETHODIMP nsSMimeVerificationListener::Notify(nsICMSMessage2 *aVerifiedMessage,
00292                                                   nsresult aVerificationResultCode)
00293 {
00294   // Only continue if we have a valid pointer to the UI
00295   NS_ENSURE_TRUE(mHeaderSink, NS_OK);
00296   
00297   NS_ENSURE_TRUE(aVerifiedMessage, NS_ERROR_FAILURE);
00298   
00299   nsCOMPtr<nsICMSMessage> msg = do_QueryInterface(aVerifiedMessage);
00300   NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
00301   
00302   nsCOMPtr<nsIX509Cert> signerCert;
00303   msg->GetSignerCert(getter_AddRefs(signerCert));
00304   
00305   PRInt32 signature_status = nsICMSMessageErrors::GENERAL_ERROR;
00306   
00307   if (NS_FAILED(aVerificationResultCode))
00308   {
00309     if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(aVerificationResultCode))
00310       signature_status = NS_ERROR_GET_CODE(aVerificationResultCode);
00311     else if (NS_ERROR_NOT_IMPLEMENTED == aVerificationResultCode)
00312       signature_status = nsICMSMessageErrors::VERIFY_ERROR_PROCESSING;
00313   }
00314   else
00315   {
00316     PRBool signing_cert_without_email_address;
00317 
00318     PRBool good_p = MimeCMSHeadersAndCertsMatch(msg, signerCert,
00319                                                 mFromAddr.get(), mFromName.get(),
00320                                                 mSenderAddr.get(), mSenderName.get(),
00321                                                 &signing_cert_without_email_address);
00322     if (!good_p)
00323     {
00324       if (signing_cert_without_email_address)
00325         signature_status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS;
00326       else
00327         signature_status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH;
00328     }
00329     else 
00330       signature_status = nsICMSMessageErrors::SUCCESS;
00331   }
00332 
00333 
00334   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00335   if (proxyman)
00336   {
00337     nsCOMPtr<nsIMsgSMIMEHeaderSink> proxySink;
00338     proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgSMIMEHeaderSink),
00339                                 mHeaderSink, PROXY_SYNC, getter_AddRefs(proxySink));
00340     if (proxySink)
00341       proxySink->SignedStatus(mMimeNestingLevel, signature_status, signerCert);
00342   }
00343 
00344   return NS_OK;
00345 }
00346 
00347 int MIMEGetRelativeCryptoNestLevel(MimeObject *obj)
00348 {
00349   /*
00350     the part id of any mimeobj is mime_part_address(obj)
00351     our currently displayed crypto part is obj
00352     the part shown as the toplevel object in the current window is
00353         obj->options->part_to_load
00354         possibly stored in the toplevel object only ???
00355         but hopefully all nested mimeobject point to the same displayooptions
00356 
00357     we need to find out the nesting level of our currently displayed crypto object
00358     wrt the shown part in the toplevel window
00359   */
00360 
00361   // if we are showing the toplevel message, aTopMessageNestLevel == 0
00362   int aTopMessageNestLevel = 0;
00363   MimeObject *aTopShownObject = nsnull;
00364   if (obj && obj->options->part_to_load) {
00365     PRBool aAlreadyFoundTop = PR_FALSE;
00366     for (MimeObject *walker = obj; walker; walker = walker->parent) {
00367       if (aAlreadyFoundTop) {
00368         if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
00369             && !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
00370           ++aTopMessageNestLevel;
00371         }
00372       }
00373       if (!aAlreadyFoundTop && !strcmp(mime_part_address(walker), walker->options->part_to_load)) {
00374         aAlreadyFoundTop = PR_TRUE;
00375         aTopShownObject = walker;
00376       }
00377       if (!aAlreadyFoundTop && !walker->parent) {
00378         // The mime part part_to_load is not a parent of the
00379         // the crypto mime part passed in to this function as parameter obj.
00380         // That means the crypto part belongs to another branch of the mime tree.
00381         return -1;
00382       }
00383     }
00384   }
00385 
00386   PRBool CryptoObjectIsChildOfTopShownObject = PR_FALSE;
00387   if (!aTopShownObject) {
00388     // no sub part specified, top message is displayed, and
00389     // our crypto object is definitively a child of it
00390     CryptoObjectIsChildOfTopShownObject = PR_TRUE;
00391   }
00392 
00393   // if we are the child of the topmost message, aCryptoPartNestLevel == 1
00394   int aCryptoPartNestLevel = 0;
00395   if (obj) {
00396     for (MimeObject *walker = obj; walker; walker = walker->parent) {
00397       // Crypto mime objects are transparent wrt nesting.
00398       if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
00399           && !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
00400         ++aCryptoPartNestLevel;
00401       }
00402       if (aTopShownObject && walker->parent == aTopShownObject) {
00403         CryptoObjectIsChildOfTopShownObject = PR_TRUE;
00404       }
00405     }
00406   }
00407 
00408   if (!CryptoObjectIsChildOfTopShownObject) {
00409     return -1;
00410   }
00411 
00412   return aCryptoPartNestLevel - aTopMessageNestLevel;
00413 }
00414 
00415 static void *MimeCMS_init(MimeObject *obj,
00416                           int (*output_fn) (const char *buf, PRInt32 buf_size, void *output_closure), 
00417                           void *output_closure)
00418 {
00419   MimeCMSdata *data;
00420   MimeDisplayOptions *opts;
00421   nsresult rv;
00422 
00423   if (!(obj && obj->options && output_fn)) return 0;
00424 
00425   opts = obj->options;
00426   data = new MimeCMSdata;
00427   if (!data) return 0;
00428 
00429   data->self = obj;
00430   data->output_fn = output_fn;
00431   data->output_closure = output_closure;
00432   PR_SetError(0, 0);
00433   data->decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
00434   if (NS_FAILED(rv)) return 0;
00435 
00436   rv = data->decoder_context->Start(MimeCMS_content_callback, data);
00437   if (NS_FAILED(rv)) return 0;
00438 
00439   // XXX Fix later XXX //
00440   data->parent_holds_stamp_p =
00441   (obj->parent &&
00442    (mime_crypto_stamped_p(obj->parent) ||
00443     mime_typep(obj->parent, (MimeObjectClass *) &mimeEncryptedClass)));
00444 
00445   data->parent_is_encrypted_p =
00446   (obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
00447 
00448   /* If the parent of this object is a crypto-blob, then it's the grandparent
00449    who would have written out the headers and prepared for a stamp...
00450    (This shit sucks.)
00451    */
00452   if (data->parent_is_encrypted_p &&
00453     !data->parent_holds_stamp_p &&
00454     obj->parent && obj->parent->parent)
00455   data->parent_holds_stamp_p =
00456     mime_crypto_stamped_p (obj->parent->parent);
00457 
00458   mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
00459   if (msd)
00460   {
00461     nsIChannel *channel = msd->channel;  // note the lack of ref counting...
00462     if (channel)
00463     {
00464       nsCOMPtr<nsIURI> uri;
00465       nsCOMPtr<nsIMsgWindow> msgWindow;
00466       nsCOMPtr<nsIMsgHeaderSink> headerSink;
00467       nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
00468       nsCOMPtr<nsISupports> securityInfo;
00469       channel->GetURI(getter_AddRefs(uri));
00470       if (uri)
00471       {
00472         nsCAutoString urlSpec;
00473         rv = uri->GetSpec(urlSpec);
00474 
00475         // We only want to update the UI if the current mime transaction
00476         // is intended for display.
00477         // If the current transaction is intended for background processing,
00478         // we can learn that by looking at the additional header=filter
00479         // string contained in the URI.
00480         //
00481         // If we find something, we do not set smimeHeaderSink,
00482         // which will prevent us from giving UI feedback.
00483         //
00484         // If we do not find header=filter, we assume the result of the
00485         // processing will be shown in the UI.
00486 
00487         if (!strstr(urlSpec.get(), "?header=filter") &&
00488             !strstr(urlSpec.get(), "&header=filter") &&
00489             !strstr(urlSpec.get(), "?header=attach") &&
00490             !strstr(urlSpec.get(), "&header=attach"))
00491         {
00492           msgurl = do_QueryInterface(uri);
00493           if (msgurl)
00494             msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
00495           if (msgWindow)
00496             msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
00497           if (headerSink)
00498             headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
00499           if (securityInfo)
00500             data->smimeHeaderSink = do_QueryInterface(securityInfo);
00501         }
00502       }
00503     } // if channel
00504   } // if msd
00505 
00506   return data;
00507 }
00508 
00509 static int
00510 MimeCMS_write (const char *buf, PRInt32 buf_size, void *closure)
00511 {
00512   MimeCMSdata *data = (MimeCMSdata *) closure;
00513   nsresult rv;
00514 
00515   if (!data || !data->output_fn || !data->decoder_context) return -1;
00516 
00517   PR_SetError(0, 0);
00518   rv = data->decoder_context->Update(buf, buf_size);
00519   data->decoding_failed = NS_FAILED(rv);
00520 
00521   return 0;
00522 }
00523 
00524 void MimeCMSGetFromSender(MimeObject *obj,
00525                           nsXPIDLCString &from_addr,
00526                           nsXPIDLCString &from_name,
00527                           nsXPIDLCString &sender_addr,
00528                           nsXPIDLCString &sender_name)
00529 {
00530   MimeHeaders *msg_headers = 0;
00531 
00532   /* Find the headers of the MimeMessage which is the parent (or grandparent)
00533    of this object (remember, crypto objects nest.) */
00534   MimeObject *o2 = obj;
00535   msg_headers = o2->headers;
00536   while (o2 &&
00537        o2->parent &&
00538        !mime_typep(o2->parent, (MimeObjectClass *) &mimeMessageClass))
00539     {
00540     o2 = o2->parent;
00541     msg_headers = o2->headers;
00542     }
00543 
00544   if (!msg_headers)
00545     return;
00546 
00547   /* Find the names and addresses in the From and/or Sender fields.
00548    */
00549   char *s;
00550 
00551   /* Extract the name and address of the "From:" field. */
00552   s = MimeHeaders_get(msg_headers, HEADER_FROM, PR_FALSE, PR_FALSE);
00553   if (s)
00554     {
00555     ParseRFC822Addresses(s, from_name, from_addr);
00556     PR_FREEIF(s);
00557     }
00558 
00559   /* Extract the name and address of the "Sender:" field. */
00560   s = MimeHeaders_get(msg_headers, HEADER_SENDER, PR_FALSE, PR_FALSE);
00561   if (s)
00562     {
00563     ParseRFC822Addresses(s, sender_name, sender_addr);
00564     PR_FREEIF(s);
00565     }
00566 }
00567 
00568 void MimeCMSRequestAsyncSignatureVerification(nsICMSMessage *aCMSMsg,
00569                                               const char *aFromAddr, const char *aFromName,
00570                                               const char *aSenderAddr, const char *aSenderName,
00571                                               nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel,
00572                                               unsigned char* item_data, PRUint32 item_len)
00573 {
00574   nsCOMPtr<nsICMSMessage2> msg2 = do_QueryInterface(aCMSMsg);
00575   if (!msg2)
00576     return;
00577   
00578   nsRefPtr<nsSMimeVerificationListener> listener = 
00579     new nsSMimeVerificationListener(aFromAddr, aFromName, aSenderAddr, aSenderName,
00580                                     aHeaderSink, aMimeNestingLevel);
00581   if (!listener)
00582     return;
00583   
00584   if (item_data)
00585     msg2->AsyncVerifyDetachedSignature(listener, item_data, item_len);
00586   else
00587     msg2->AsyncVerifySignature(listener);
00588 }
00589 
00590 static int
00591 MimeCMS_eof (void *crypto_closure, PRBool abort_p)
00592 {
00593   MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
00594   nsresult rv;
00595   PRInt32 status = nsICMSMessageErrors::SUCCESS;
00596 
00597   if (!data || !data->output_fn || !data->decoder_context) {
00598     return -1;
00599   }
00600 
00601   int aRelativeNestLevel = MIMEGetRelativeCryptoNestLevel(data->self);
00602 
00603   /* Hand an EOF to the crypto library.  It may call data->output_fn.
00604    (Today, the crypto library has no flushing to do, but maybe there
00605    will be someday.)
00606 
00607    We save away the value returned and will use it later to emit a
00608    blurb about whether the signature validation was cool.
00609    */
00610 
00611   PR_SetError(0, 0);
00612   rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
00613   if (NS_FAILED(rv))
00614     status = nsICMSMessageErrors::GENERAL_ERROR;
00615 
00616   data->decoder_context = 0;
00617 
00618   nsCOMPtr<nsIX509Cert> certOfInterest;
00619 
00620   if (!data->smimeHeaderSink)
00621     return 0;
00622 
00623   if (aRelativeNestLevel < 0)
00624     return 0;
00625 
00626   PRInt32 maxNestLevel = 0;
00627   data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
00628 
00629   if (aRelativeNestLevel > maxNestLevel)
00630     return 0;
00631 
00632   if (data->decoding_failed)
00633     status = nsICMSMessageErrors::GENERAL_ERROR;
00634 
00635   if (!data->content_info)
00636   {
00637     if (!data->decoded_bytes)
00638     {
00639       // We were unable to decode any data.
00640       status = nsICMSMessageErrors::GENERAL_ERROR;
00641     }
00642     else
00643     {
00644       // Some content got decoded, but we failed to decode
00645       // the final summary, probably we got truncated data.
00646       status = nsICMSMessageErrors::ENCRYPT_INCOMPLETE;
00647     }
00648 
00649     // Although a CMS message could be either encrypted or opaquely signed,
00650     // what we see is most likely encrypted, because if it were
00651     // signed only, we probably would have been able to decode it.
00652 
00653     data->ci_is_encrypted = PR_TRUE;
00654   }
00655   else
00656   {
00657     rv = data->content_info->ContentIsEncrypted(&data->ci_is_encrypted);
00658 
00659     if (NS_SUCCEEDED(rv) && data->ci_is_encrypted) {
00660       data->content_info->GetEncryptionCert(getter_AddRefs(certOfInterest));
00661     }
00662     else {
00663       // Existing logic in mimei assumes, if !ci_is_encrypted, then it is signed.
00664       // Make sure it indeed is signed.
00665 
00666       PRBool testIsSigned;
00667       rv = data->content_info->ContentIsSigned(&testIsSigned);
00668 
00669       if (NS_FAILED(rv) || !testIsSigned) {
00670         // Neither signed nor encrypted?
00671         // We are unable to understand what we got, do not try to indicate S/Mime status.
00672         return 0;
00673       }
00674 
00675       nsXPIDLCString from_addr;
00676       nsXPIDLCString from_name;
00677       nsXPIDLCString sender_addr;
00678       nsXPIDLCString sender_name;
00679 
00680       MimeCMSGetFromSender(data->self, 
00681                            from_addr, from_name,
00682                            sender_addr, sender_name);
00683 
00684       MimeCMSRequestAsyncSignatureVerification(data->content_info, 
00685                                                from_addr, from_name,
00686                                                sender_addr, sender_name,
00687                                                data->smimeHeaderSink, aRelativeNestLevel, 
00688                                                nsnull, 0);
00689     }
00690   }
00691 
00692   if (data->ci_is_encrypted)
00693   {
00694     data->smimeHeaderSink->EncryptionStatus(
00695       aRelativeNestLevel,
00696       status,
00697       certOfInterest
00698     );
00699   }
00700 
00701   return 0;
00702 }
00703 
00704 static void
00705 MimeCMS_free (void *crypto_closure)
00706 {
00707   MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
00708   if (!data) return;
00709   
00710   delete data;
00711 }
00712 
00713 static char *
00714 MimeCMS_generate (void *crypto_closure)
00715 {
00716   return nsnull;
00717 }
00718