Back to index

enigmail  1.4.3
nsEnigMimeVerify.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public
00005  * License Version 1.1 (the "MPL"); you may not use this file
00006  * except in compliance with the MPL. You may obtain a copy of
00007  * the MPL at http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the MPL is distributed on an "AS
00010  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00011  * implied. See the MPL for the specific language governing
00012  * rights and limitations under the MPL.
00013  *
00014  * The Original Code is Enigmail.
00015  *
00016  * The Initial Developer of the Original Code is Ramalingam Saravanan.
00017  * Portions created by Ramalingam Saravanan <sarava@sarava.net> are
00018  * Copyright (C) 2002 Ramalingam Saravanan. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  * Patrick Brunschwig <patrick@mozilla-enigmail.org>
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  * ***** END LICENSE BLOCK ***** */
00035 
00036 // Logging of debug output
00037 // The following define statement should occur before any include statements
00038 #define FORCE_PR_LOG       /* Allow logging even in release build */
00039 
00040 #include "enigmail.h"
00041 #include "nspr.h"
00042 #include "nsCOMPtr.h"
00043 #include "nsStringAPI.h"
00044 #include "nsNetUtil.h"
00045 #include "nsNetCID.h"
00046 #include "nsIPrompt.h"
00047 #include "nsIMsgWindow.h"
00048 #include "nsIDOMWindow.h"
00049 #include "nsIMimeMiscStatus.h"
00050 #include "nsIEnigMimeHeaderSink.h"
00051 #include "nsIThread.h"
00052 #include "nsEnigMimeVerify.h"
00053 #include "nsIPipeTransport.h"
00054 #include "nsIIPCBuffer.h"
00055 #include "nsIEnigmail.h"
00056 #include "nsIUnicharOutputStream.h"
00057 
00058 #undef MOZILLA_INTERNAL_API
00059 #ifdef PR_LOGGING
00060 PRLogModuleInfo* gEnigMimeVerifyLog = NULL;
00061 #endif
00062 
00063 #define ERROR_LOG(args)    PR_LOG(gEnigMimeVerifyLog,PR_LOG_ERROR,args)
00064 #define WARNING_LOG(args)  PR_LOG(gEnigMimeVerifyLog,PR_LOG_WARNING,args)
00065 #define DEBUG_LOG(args)    PR_LOG(gEnigMimeVerifyLog,PR_LOG_DEBUG,args)
00066 
00067 #define MAX_BUFFER_BYTES 32000
00068 #define MAX_HEADER_BYTES 16000
00069 
00070 static const PRUint32 kCharMax = 1024;
00071 
00072 // nsEnigMimeVerify implementation
00073 
00074 // nsISupports implementation
00075 NS_IMPL_THREADSAFE_ISUPPORTS3(nsEnigMimeVerify,
00076                               nsIEnigMimeVerify,
00077                               nsIRequestObserver,
00078                               nsIStreamListener)
00079 
00080 // nsEnigMimeVerify implementation
00081 nsEnigMimeVerify::nsEnigMimeVerify()
00082   : mInitialized(PR_FALSE),
00083     mPgpMime(PR_FALSE),
00084     mRequestStopped(PR_FALSE),
00085     mLastLinebreak(PR_TRUE),
00086 
00087     mStartCount(0),
00088 
00089     mContentBoundary(""),
00090     mLinebreak(""),
00091 
00092     mURISpec(""),
00093     mMsgWindow(nsnull),
00094 
00095     mOutBuffer(nsnull),
00096     mPipeTrans(nsnull),
00097 
00098     mArmorListener(nsnull),
00099     mSecondPartListener(nsnull),
00100     mFirstPartListener(nsnull),
00101     mOuterMimeListener(nsnull),
00102     mInnerMimeListener(nsnull)
00103 {
00104   nsresult rv;
00105 
00106   NS_INIT_ISUPPORTS();
00107 
00108 #ifdef PR_LOGGING
00109   if (gEnigMimeVerifyLog == nsnull) {
00110     gEnigMimeVerifyLog = PR_NewLogModule("nsEnigMimeVerify");
00111   }
00112 #endif
00113 
00114 #ifdef FORCE_PR_LOG
00115   nsCOMPtr<nsIThread> myThread;
00116   rv = ENIG_GET_THREAD(myThread);
00117   DEBUG_LOG(("nsEnigMimeVerify:: <<<<<<<<< CTOR(%p): myThread=%p\n",
00118          this, myThread.get()));
00119 #endif
00120 }
00121 
00122 
00123 nsEnigMimeVerify::~nsEnigMimeVerify()
00124 {
00125   nsresult rv;
00126 #ifdef FORCE_PR_LOG
00127   nsCOMPtr<nsIThread> myThread;
00128   rv = ENIG_GET_THREAD(myThread);
00129   DEBUG_LOG(("nsEnigMimeVerify:: >>>>>>>>> DTOR(%p): myThread=%p\n",
00130          this, myThread.get()));
00131 #endif
00132 
00133   Finalize();
00134 }
00135 
00136 
00138 // nsIEnigMimeVerify methods:
00140 
00141 NS_IMETHODIMP
00142 nsEnigMimeVerify::Init(nsIDOMWindow* window,
00143                        nsIURI* aURI,
00144                        nsIMsgWindow* msgWindow,
00145                        const nsACString& msgUriSpec,
00146                        EMBool pgpMime,
00147                        EMBool isSubPart)
00148 {
00149   nsresult rv;
00150 
00151   DEBUG_LOG(("nsEnigMimeVerify::Init: pgpMime=%d\n", (int) pgpMime));
00152 
00153   if (!aURI)
00154     return NS_ERROR_NULL_POINTER;
00155 
00156   mMsgWindow = msgWindow;
00157   mURISpec.Assign(msgUriSpec);
00158   mPgpMime = pgpMime;
00159 
00160 
00161   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
00162   if (NS_FAILED(rv)) return rv;
00163 
00164   nsCOMPtr<nsIChannel> channel;
00165   rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(channel));
00166   if (NS_FAILED(rv)) return rv;
00167 
00168   // Listener to parse PGP block armor
00169   mArmorListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00170   if (NS_FAILED(rv)) return rv;
00171 
00172   const char* pgpHeader = "-----BEGIN PGP ";
00173   const char* pgpFooter = "-----END PGP ";
00174 
00175   rv = mArmorListener->Init((nsIStreamListener*) this, nsnull,
00176                             pgpHeader, pgpFooter,
00177                             0, PR_TRUE, PR_FALSE, nsnull);
00178   if (NS_FAILED(rv)) return rv;
00179 
00180   // Inner mime listener to parse second part
00181   mInnerMimeListener = do_CreateInstance(NS_ENIGMIMELISTENER_CONTRACTID, &rv);
00182   if (NS_FAILED(rv)) return rv;
00183 
00184   rv = mInnerMimeListener->Init(mArmorListener, nsnull,
00185                                 MAX_HEADER_BYTES, PR_TRUE, PR_FALSE, PR_FALSE);
00186   if (NS_FAILED(rv)) return rv;
00187 
00188   // Create PipeFilterListener to extract second MIME part
00189   mSecondPartListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00190   if (NS_FAILED(rv)) return rv;
00191 
00192   // Create PipeFilterListener to extract first MIME part
00193   mFirstPartListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00194   if (NS_FAILED(rv)) return rv;
00195 
00196   rv = mFirstPartListener->Init((nsIStreamListener*) this,
00197                                nsnull, "", "", 0, PR_FALSE, PR_TRUE,
00198                                mSecondPartListener);
00199   if (NS_FAILED(rv)) return rv;
00200 
00201   // Outer mime listener to capture URI content
00202   mOuterMimeListener = do_CreateInstance(NS_ENIGMIMELISTENER_CONTRACTID, &rv);
00203   if (NS_FAILED(rv)) return rv;
00204 
00205   if (isSubPart)
00206     mOuterMimeListener->SetSubPartTreatment(PR_TRUE);
00207 
00208   rv = mOuterMimeListener->Init(mFirstPartListener, nsnull,
00209                                 MAX_HEADER_BYTES, PR_TRUE, PR_FALSE, PR_FALSE);
00210 
00211   if (NS_FAILED(rv)) return rv;
00212 
00213   // Initiate asynchronous loading of URI
00214   rv = channel->AsyncOpen( mOuterMimeListener, nsnull );
00215   if (NS_FAILED(rv))
00216     return rv;
00217 
00218   mInitialized = PR_TRUE;
00219 
00220   return NS_OK;
00221 }
00222 
00223 NS_IMETHODIMP
00224 nsEnigMimeVerify::InitWithChannel(nsIDOMWindow* window,
00225                        nsIChannel* aChannel,
00226                        nsIMsgWindow* msgWindow,
00227                        const nsACString& msgUriSpec,
00228                        EMBool pgpMime,
00229                        EMBool isSubPart)
00230 {
00231   nsresult rv;
00232 
00233   DEBUG_LOG(("nsEnigMimeVerify::Init: pgpMime=%d\n", (int) pgpMime));
00234 
00235   mMsgWindow = msgWindow;
00236   mURISpec = msgUriSpec;
00237   mPgpMime = pgpMime;
00238 
00239   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
00240   if (NS_FAILED(rv)) return rv;
00241 
00242   // Listener to parse PGP block armor
00243   mArmorListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00244   if (NS_FAILED(rv)) return rv;
00245 
00246   const char* pgpHeader = "-----BEGIN PGP ";
00247   const char* pgpFooter = "-----END PGP ";
00248 
00249   rv = mArmorListener->Init((nsIStreamListener*) this, nsnull,
00250                             pgpHeader, pgpFooter,
00251                             0, PR_TRUE, PR_FALSE, nsnull);
00252   if (NS_FAILED(rv)) return rv;
00253 
00254   // Inner mime listener to parse second part
00255   mInnerMimeListener = do_CreateInstance(NS_ENIGMIMELISTENER_CONTRACTID, &rv);
00256   if (NS_FAILED(rv)) return rv;
00257 
00258   rv = mInnerMimeListener->Init(mArmorListener, nsnull,
00259                                 MAX_HEADER_BYTES, PR_TRUE, PR_FALSE, PR_FALSE);
00260   if (NS_FAILED(rv)) return rv;
00261 
00262   // Create PipeFilterListener to extract second MIME part
00263   mSecondPartListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00264   if (NS_FAILED(rv)) return rv;
00265 
00266   // Create PipeFilterListener to extract first MIME part
00267   mFirstPartListener = do_CreateInstance(NS_PIPEFILTERLISTENER_CONTRACTID, &rv);
00268   if (NS_FAILED(rv)) return rv;
00269 
00270   rv = mFirstPartListener->Init((nsIStreamListener*) this,
00271                                nsnull, "", "", 0, PR_FALSE, PR_TRUE,
00272                                mSecondPartListener);
00273   if (NS_FAILED(rv)) return rv;
00274 
00275   // Outer mime listener to capture URI content
00276   mOuterMimeListener = do_CreateInstance(NS_ENIGMIMELISTENER_CONTRACTID, &rv);
00277   if (NS_FAILED(rv)) return rv;
00278 
00279   if (isSubPart)
00280     mOuterMimeListener->SetSubPartTreatment(PR_TRUE);
00281 
00282   rv = mOuterMimeListener->Init(mFirstPartListener, nsnull,
00283                                 MAX_HEADER_BYTES, PR_TRUE, PR_FALSE, PR_FALSE);
00284 
00285   if (NS_FAILED(rv)) return rv;
00286 
00287   // Initiate asynchronous loading of URI
00288   rv = aChannel->AsyncOpen( mOuterMimeListener, nsnull );
00289   if (NS_FAILED(rv))
00290     return rv;
00291 
00292   mInitialized = PR_TRUE;
00293 
00294   return NS_OK;
00295 }
00296 
00297 nsresult
00298 nsEnigMimeVerify::Finalize()
00299 {
00300   DEBUG_LOG(("nsEnigMimeVerify::Finalize:\n"));
00301 
00302   if (mPipeTrans) {
00303     mPipeTrans->Terminate();
00304     mPipeTrans = nsnull;
00305   }
00306 
00307   if (mOutBuffer) {
00308     mOutBuffer->Shutdown();
00309     mOutBuffer = nsnull;
00310   }
00311 
00312   mMsgWindow = nsnull;
00313 
00314   mArmorListener = nsnull;
00315   mFirstPartListener = nsnull;
00316   mSecondPartListener = nsnull;
00317   mOuterMimeListener = nsnull;
00318   mInnerMimeListener = nsnull;
00319 
00320   return NS_OK;
00321 }
00322 
00323 NS_IMETHODIMP
00324 nsEnigMimeVerify::Finish()
00325 {
00326   // Enigmail stuff
00327   nsresult rv;
00328 
00329   if (!mInitialized || !mPipeTrans)
00330     return NS_ERROR_NOT_INITIALIZED;
00331 
00332   if (!mRequestStopped)
00333     return NS_ERROR_FAILURE;
00334 
00335   // Wait for STDOUT to close
00336   rv = mPipeTrans->Join();
00337   if (NS_FAILED(rv)) return rv;
00338 
00339   // Count of STDOUT bytes
00340   PRUint32 outputLen;
00341   rv = mOutBuffer->GetTotalBytes(&outputLen);
00342   if (NS_FAILED(rv)) return rv;
00343 
00344   // Shutdown STDOUT console
00345   mOutBuffer->Shutdown();
00346 
00347   // Check input data consistency
00348   if (mStartCount < 2) {
00349     ERROR_LOG(("nsEnigMimeVerify::Finish: ERROR mStartCount=%d\n", mStartCount));
00350     return NS_ERROR_FAILURE;
00351   }
00352 
00353   nsCAutoString armorTail;
00354   rv = mArmorListener->GetEndLine(armorTail);
00355   if (NS_FAILED(rv)) return rv;
00356 
00357   if (armorTail.IsEmpty()) {
00358     ERROR_LOG(("nsEnigMimeVerify::Finish: ERROR No armor tail found\n"));
00359     return NS_ERROR_FAILURE;
00360   }
00361 
00362   nsCAutoString endBoundary;
00363   rv = mSecondPartListener->GetEndLine(endBoundary);
00364   if (NS_FAILED(rv)) return rv;
00365 
00366   // Trim leading/trailing whitespace
00367   endBoundary.Trim(" \t\r\n", PR_TRUE, PR_TRUE);
00368 
00369   nsCAutoString temBoundary("--");
00370   temBoundary += mContentBoundary;
00371   temBoundary += "--";
00372 
00373   if (!endBoundary.Equals(temBoundary)) {
00374     ERROR_LOG(("nsEnigMimeVerify::Finish: ERROR endBoundary=%s\n", endBoundary.get()));
00375     return NS_ERROR_FAILURE;
00376   }
00377 
00378   PRInt32 exitCode;
00379   PRUint32 statusFlags;
00380 
00381   nsString keyId;
00382   nsString userId;
00383   nsString sigDate;
00384   nsString errorMsg;
00385   nsString blockSeparation;
00386 
00387   nsCOMPtr<nsIEnigmail> enigmailSvc = do_GetService(NS_ENIGMAIL_CONTRACTID, &rv);
00388   if (NS_FAILED(rv)) return rv;
00389 
00390   PRUint32 uiFlags = nsIEnigmail::UI_PGP_MIME;
00391   EMBool verifyOnly = PR_TRUE;
00392   EMBool noOutput = PR_TRUE;
00393 
00394   rv = enigmailSvc->DecryptMessageEnd(uiFlags,
00395                                       outputLen,
00396                                       mPipeTrans,
00397                                       verifyOnly,
00398                                       noOutput,
00399                                       &statusFlags,
00400                                       getter_Copies(keyId),
00401                                       getter_Copies(userId),
00402                                       getter_Copies(sigDate),
00403                                       getter_Copies(errorMsg),
00404                                       getter_Copies(blockSeparation),
00405                                       &exitCode);
00406   if (NS_FAILED(rv)) return rv;
00407 
00408   nsCOMPtr<nsISupports> securityInfo;
00409   if (mMsgWindow) {
00410     nsCOMPtr<nsIMsgHeaderSink> headerSink;
00411     mMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
00412     if (headerSink)
00413         headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
00414   }
00415 
00416   DEBUG_LOG(("nsEnigMimeVerify::Finish: securityInfo=%p\n", securityInfo.get()));
00417 
00418   if (securityInfo) {
00419     nsCOMPtr<nsIEnigMimeHeaderSink> enigHeaderSink = do_QueryInterface(securityInfo);
00420     if (enigHeaderSink) {
00421       rv = enigHeaderSink->UpdateSecurityStatus(mURISpec, exitCode, statusFlags, keyId.get(), userId.get(), sigDate.get(), errorMsg.get(), blockSeparation.get(), NULL);
00422     }
00423   }
00424 
00425   if (exitCode != 0) {
00426     DEBUG_LOG(("nsEnigMimeVerify::Finish: ERROR EXIT %d\n", exitCode));
00427     return NS_ERROR_FAILURE;
00428   }
00429 
00430   return NS_OK;
00431 }
00432 
00433 
00435 // nsIRequestObserver methods
00437 
00438 NS_IMETHODIMP
00439 nsEnigMimeVerify::OnStartRequest(nsIRequest *aRequest,
00440                                    nsISupports *aContext)
00441 {
00442   nsresult rv;
00443 
00444   mStartCount++;
00445 
00446   DEBUG_LOG(("nsEnigMimeVerify::OnStartRequest: %d\n", mStartCount));
00447 
00448   if (!mInitialized)
00449     return NS_ERROR_NOT_INITIALIZED;
00450 
00451   if (mStartCount > 2)
00452     return NS_ERROR_FAILURE;
00453 
00454   if (mStartCount == 2) {
00455     // Second start request
00456     nsCAutoString innerContentType;
00457     rv = mInnerMimeListener->GetContentType(innerContentType);
00458     if (NS_FAILED(rv)) return rv;
00459 
00460     if (!innerContentType.Equals("application/pgp-signature", CaseInsensitiveCompare)) {
00461       DEBUG_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR innerContentType=%s\n", innerContentType.get()));
00462       return NS_ERROR_FAILURE;
00463     }
00464 
00465     // Output Linebreak after signed content (IMPORTANT)
00466     rv = mInnerMimeListener->GetLinebreak(mLinebreak);
00467     if (NS_FAILED(rv)) return rv;
00468 
00469     if (mLinebreak.IsEmpty())
00470       return NS_ERROR_FAILURE;
00471 
00472     mPipeTrans->Write(mLinebreak.get(), mLinebreak.Length());
00473 
00474     return NS_OK;
00475   }
00476 
00477   // First start request
00478   nsCAutoString contentType;
00479   rv = mOuterMimeListener->GetContentType(contentType);
00480   if (NS_FAILED(rv)) return rv;
00481 
00482   if (!contentType.Equals("multipart/signed", CaseInsensitiveCompare)) {
00483     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR contentType=%s\n", contentType.get()));
00484     return NS_ERROR_FAILURE;
00485   }
00486 
00487   nsCAutoString contentProtocol;
00488   rv = mOuterMimeListener->GetContentProtocol(contentProtocol);
00489   if (NS_FAILED(rv)) return rv;
00490 
00491   if (!contentProtocol.Equals("application/pgp-signature", CaseInsensitiveCompare)) {
00492     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR contentProtocol=%s\n", contentProtocol.get()));
00493     return NS_ERROR_FAILURE;
00494   }
00495 
00496   nsCAutoString contentMicalg;
00497   rv = mOuterMimeListener->GetContentMicalg(contentMicalg);
00498   if (NS_FAILED(rv)) return rv;
00499 
00500   nsCAutoString hashSymbol;
00501   if (contentMicalg.Equals("pgp-md5", CaseInsensitiveCompare)) {
00502     hashSymbol = "MD5";
00503 
00504   } else if (contentMicalg.Equals("pgp-sha1", CaseInsensitiveCompare)) {
00505     hashSymbol = "SHA1";
00506 
00507   } else if (contentMicalg.Equals("pgp-ripemd160", CaseInsensitiveCompare)) {
00508     hashSymbol = "RIPEMD160";
00509 
00510   } else if (contentMicalg.Equals("pgp-sha224", CaseInsensitiveCompare)) {
00511     hashSymbol = "SHA224";
00512 
00513   } else if (contentMicalg.Equals("pgp-sha256", CaseInsensitiveCompare)) {
00514     hashSymbol = "SHA256";
00515 
00516   } else if (contentMicalg.Equals("pgp-sha384", CaseInsensitiveCompare)) {
00517     hashSymbol = "SHA384";
00518 
00519   } else if (contentMicalg.Equals("pgp-sha512", CaseInsensitiveCompare)) {
00520     hashSymbol = "SHA512";
00521 
00522   } else {
00523     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR contentMicalg='%s'\n", contentMicalg.get()));
00524     return NS_ERROR_FAILURE;
00525   }
00526 
00527   nsCAutoString linebreak;
00528   rv = mOuterMimeListener->GetLinebreak(linebreak);
00529   if (NS_FAILED(rv)) return rv;
00530 
00531   rv = mOuterMimeListener->GetContentBoundary(mContentBoundary);
00532   if (NS_FAILED(rv)) return rv;
00533 
00534   if (mContentBoundary.IsEmpty()) {
00535     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR no content boundary\n"));
00536     return NS_ERROR_FAILURE;
00537   }
00538 
00539   nsCAutoString mimeSeparator("--");
00540   mimeSeparator += mContentBoundary;
00541 
00542   nsCAutoString startDelimiter;
00543   rv = mFirstPartListener->GetStartDelimiter(startDelimiter);
00544   if (NS_FAILED(rv)) return rv;
00545 
00546   if (!startDelimiter.Equals(mimeSeparator)) {
00547     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR startDelimiter=%s\n", startDelimiter.get()));
00548     return NS_ERROR_FAILURE;
00549   }
00550 
00551   nsCAutoString endBoundary;
00552   rv = mFirstPartListener->GetEndDelimiter(endBoundary);
00553   if (NS_FAILED(rv)) return rv;
00554 
00555   endBoundary.Trim(" \t\r\n", PR_TRUE, PR_TRUE);
00556 
00557   if (!endBoundary.Equals(mimeSeparator)) {
00558     ERROR_LOG(("nsEnigMimeVerify::OnStartRequest: ERROR endBoundary=%s\n", endBoundary.get()));
00559     return NS_ERROR_FAILURE;
00560   }
00561 
00562   // Initialize second part listener with content boundary
00563   rv = mSecondPartListener->Init(mInnerMimeListener,
00564                                  nsnull, "", mimeSeparator.get(),
00565                                  0, PR_FALSE, PR_FALSE, nsnull);
00566   if (NS_FAILED(rv)) return rv;
00567 
00568 
00569   // Create null buffer to capture verification output
00570   mOutBuffer = do_CreateInstance(NS_IPCBUFFER_CONTRACTID, &rv);
00571   if (NS_FAILED(rv)) return rv;
00572 
00573   rv = mOutBuffer->Open(0, PR_FALSE);
00574   if (NS_FAILED(rv)) return rv;
00575 
00576   nsCOMPtr<nsIPrompt> prompter;
00577   if (mMsgWindow) {
00578     mMsgWindow->GetPromptDialog(getter_AddRefs(prompter));
00579   }
00580 
00581   DEBUG_LOG(("nsEnigMimeVerify::OnStartRequest: prompter=%p\n", prompter.get()));
00582 
00583   nsCOMPtr<nsIEnigmail> enigmailSvc = do_GetService(NS_ENIGMAIL_CONTRACTID, &rv);
00584   if (NS_FAILED(rv)) return rv;
00585 
00586   nsString errorMsg;
00587   EMBool verifyOnly = PR_TRUE;
00588   EMBool noOutput = PR_TRUE;
00589   PRUint32 statusFlags;
00590   rv = enigmailSvc->DecryptMessageStart(nsnull,
00591                                         prompter,
00592                                         verifyOnly,
00593                                         noOutput,
00594                                         mOutBuffer,
00595                                         &statusFlags,
00596                                         getter_Copies(errorMsg),
00597                                         getter_AddRefs(mPipeTrans) );
00598   if (NS_FAILED(rv)) return rv;
00599 
00600   if (!mPipeTrans) {
00601     nsCOMPtr<nsISupports> securityInfo;
00602     if (mMsgWindow) {
00603       nsCOMPtr<nsIMsgHeaderSink> headerSink;
00604       mMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
00605       if (headerSink)
00606           headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
00607     }
00608 
00609     if (securityInfo) {
00610       nsCOMPtr<nsIEnigMimeHeaderSink> enigHeaderSink = do_QueryInterface(securityInfo);
00611       if (enigHeaderSink) {
00612         NS_NAMED_LITERAL_STRING(nullString, "");
00613         rv = enigHeaderSink->UpdateSecurityStatus(mURISpec, -1, statusFlags, nullString.get(), nullString.get(), nullString.get(), errorMsg.get(), nullString.get(), NULL);
00614       }
00615     }
00616 
00617     return NS_ERROR_FAILURE;
00618   }
00619 
00620   // Write clearsigned message header
00621   const char* clearsignHeader = "-----BEGIN PGP SIGNED MESSAGE-----";
00622 
00623   rv = mPipeTrans->Write(clearsignHeader, strlen(clearsignHeader));
00624   if (NS_FAILED(rv)) return rv;
00625 
00626   rv = mPipeTrans->Write(linebreak.get(), linebreak.Length());
00627   if (NS_FAILED(rv)) return rv;
00628 
00629   // Write out hash symbol
00630   const char* hashHeader = "Hash: ";
00631 
00632   rv = mPipeTrans->Write(hashHeader, strlen(hashHeader));
00633   if (NS_FAILED(rv)) return rv;
00634 
00635   rv = mPipeTrans->Write(hashSymbol.get(), hashSymbol.Length());
00636   if (NS_FAILED(rv)) return rv;
00637 
00638   rv = mPipeTrans->Write(linebreak.get(), linebreak.Length());
00639   if (NS_FAILED(rv)) return rv;
00640 
00641   rv = mPipeTrans->Write(linebreak.get(), linebreak.Length());
00642   if (NS_FAILED(rv)) return rv;
00643 
00644   // Initialize for dash-escaping
00645   mLastLinebreak = PR_TRUE;
00646 
00647   return NS_OK;
00648 }
00649 
00650 NS_IMETHODIMP
00651 nsEnigMimeVerify::OnStopRequest(nsIRequest* aRequest,
00652                                 nsISupports* aContext,
00653                                 nsresult aStatus)
00654 {
00655   nsresult rv;
00656   DEBUG_LOG(("nsEnigMimeVerify::OnStopRequest:\n"));
00657 
00658   if (mRequestStopped)
00659     return NS_OK;
00660 
00661   if (!mInitialized || !mPipeTrans)
00662     return NS_ERROR_NOT_INITIALIZED;
00663 
00664   mRequestStopped = PR_TRUE;
00665 
00666   rv = mPipeTrans->CloseStdin();
00667   if (NS_FAILED(rv)) {
00668     Finalize();
00669     return rv;
00670   }
00671 
00672   rv = Finish();
00673   if (NS_FAILED(rv)) {
00674     Finalize();
00675     return rv;
00676   }
00677 
00678   return NS_OK;
00679 }
00680 
00682 // nsIStreamListener method
00684 
00685 NS_IMETHODIMP
00686 nsEnigMimeVerify::OnDataAvailable(nsIRequest* aRequest,
00687                                   nsISupports* aContext,
00688                                   nsIInputStream *aInputStream,
00689                                   PRUint32 aSourceOffset,
00690                                   PRUint32 aLength)
00691 {
00692   nsresult rv = NS_OK;
00693 
00694   DEBUG_LOG(("nsEnigMimeVerify::OnDataAvailable: %d\n", aLength));
00695 
00696   if (!mInitialized || !mPipeTrans)
00697     return NS_ERROR_NOT_INITIALIZED;
00698 
00699   const char* dashEscape = " -";
00700   char buf[kCharMax];
00701   PRUint32 readCount, readMax;
00702 
00703   while (aLength > 0) {
00704     readMax = (aLength < kCharMax) ? aLength : kCharMax;
00705     rv = aInputStream->Read((char *) buf, readMax, &readCount);
00706     if (NS_FAILED(rv)){
00707       DEBUG_LOG(("nsEnigMimeVerify::OnDataAvailable: Error in reading from input stream, %p\n", rv));
00708       return rv;
00709     }
00710 
00711     if (readCount <= 0) return NS_OK;
00712 
00713     if (mStartCount == 1) {
00714       // Dash escaping for first part only (RFC 2440)
00715 
00716       PRUint32 offset = 0;
00717       for (PRUint32 j=0; j < readCount; j++) {
00718         char ch = buf[j];
00719         if ((ch == '-') && mLastLinebreak) {
00720           rv = mPipeTrans->Write(buf+offset, j-offset+1);
00721           if (NS_FAILED(rv)) return rv;
00722           offset = j+1;
00723 
00724           rv = mPipeTrans->Write(dashEscape, strlen(dashEscape));
00725           if (NS_FAILED(rv)) return rv;
00726 
00727           DEBUG_LOG(("nsEnigMimeVerify::OnDataAvailable: DASH ESCAPED\n"));
00728         }
00729 
00730         mLastLinebreak = (ch == '\r') || (ch == '\n');
00731       }
00732 
00733       if (offset < readCount) {
00734         rv = mPipeTrans->Write(buf+offset, readCount-offset);
00735         if (NS_FAILED(rv)) return rv;
00736       }
00737 
00738     } else {
00739       // No dash escaping
00740       rv = mPipeTrans->Write(buf, readCount);
00741       if (NS_FAILED(rv)) return rv;
00742     }
00743 
00744     aLength -= readCount;
00745   }
00746 
00747   return NS_OK;
00748 }