Back to index

lightning-sunbird  0.9+nobinonly
nsSMimeJSHelper.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 License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
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  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nspr.h"
00038 #include "nsSMimeJSHelper.h"
00039 #include "nsCOMPtr.h"
00040 #include "nsMemory.h"
00041 #include "nsReadableUtils.h"
00042 #include "nsLiteralString.h"
00043 #include "nsString.h"
00044 #include "nsIMsgHeaderParser.h"
00045 #include "nsIX509CertDB.h"
00046 #include "nsIX509CertValidity.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsPromiseFlatString.h"
00049 #include "nsCRT.h"
00050 
00051 NS_IMPL_ISUPPORTS1(nsSMimeJSHelper, nsISMimeJSHelper)
00052 
00053 nsSMimeJSHelper::nsSMimeJSHelper()
00054 {
00055 }
00056 
00057 nsSMimeJSHelper::~nsSMimeJSHelper()
00058 {
00059 }
00060 
00061 NS_IMETHODIMP nsSMimeJSHelper::GetRecipientCertsInfo(
00062     nsIMsgCompFields *compFields, 
00063     PRUint32 *count, 
00064     PRUnichar ***emailAddresses, 
00065     PRInt32 **certVerification, 
00066     PRUnichar ***certIssuedInfos, 
00067     PRUnichar ***certExpiresInfos, 
00068     nsIX509Cert ***certs,
00069     PRBool *canEncrypt)
00070 {
00071   NS_ENSURE_ARG_POINTER(count);
00072   *count = 0;
00073   
00074   NS_ENSURE_ARG_POINTER(emailAddresses);
00075   NS_ENSURE_ARG_POINTER(certVerification);
00076   NS_ENSURE_ARG_POINTER(certIssuedInfos);
00077   NS_ENSURE_ARG_POINTER(certExpiresInfos);
00078   NS_ENSURE_ARG_POINTER(certs);
00079   NS_ENSURE_ARG_POINTER(canEncrypt);
00080 
00081   NS_ENSURE_ARG_POINTER(compFields);
00082 
00083   PRUint32 mailbox_count;
00084   char *mailbox_list;
00085 
00086   nsresult rv = getMailboxList(compFields, &mailbox_count, &mailbox_list);
00087   if (NS_FAILED(rv))
00088     return rv;
00089 
00090   if (!mailbox_list)
00091     return NS_ERROR_FAILURE;
00092 
00093   nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
00094 
00095   *count = mailbox_count;
00096   *canEncrypt = PR_FALSE;
00097   rv = NS_OK;
00098 
00099   if (mailbox_count)
00100   {
00101     PRUnichar **outEA = NS_STATIC_CAST(PRUnichar **, nsMemory::Alloc(mailbox_count * sizeof(PRUnichar *)));
00102     PRInt32 *outCV = NS_STATIC_CAST(PRInt32 *, nsMemory::Alloc(mailbox_count * sizeof(PRInt32)));
00103     PRUnichar **outCII = NS_STATIC_CAST(PRUnichar **, nsMemory::Alloc(mailbox_count * sizeof(PRUnichar *)));
00104     PRUnichar **outCEI = NS_STATIC_CAST(PRUnichar **, nsMemory::Alloc(mailbox_count * sizeof(PRUnichar *)));
00105     nsIX509Cert **outCerts = NS_STATIC_CAST(nsIX509Cert **, nsMemory::Alloc(mailbox_count * sizeof(nsIX509Cert *)));
00106 
00107     if (!outEA || !outCV || !outCII || !outCEI || !outCerts)
00108     {
00109       nsMemory::Free(outEA);
00110       nsMemory::Free(outCV);
00111       nsMemory::Free(outCII);
00112       nsMemory::Free(outCEI);
00113       nsMemory::Free(outCerts);
00114       rv = NS_ERROR_OUT_OF_MEMORY;
00115     }
00116     else
00117     {
00118       PRUnichar **iEA = outEA;
00119       PRInt32 *iCV = outCV;
00120       PRUnichar **iCII = outCII;
00121       PRUnichar **iCEI = outCEI;
00122       nsIX509Cert **iCert = outCerts;
00123 
00124       PRBool found_blocker = PR_FALSE;
00125       PRBool memory_failure = PR_FALSE;
00126 
00127       const char *walk = mailbox_list;
00128 
00129       // To understand this loop, especially the "+= strlen +1", look at the documentation
00130       // of ParseHeaderAddresses. Basically, it returns a list of zero terminated strings.
00131       for (PRUint32 i = 0;
00132           i < mailbox_count;
00133           ++i, ++iEA, ++iCV, ++iCII, ++iCEI, ++iCert, walk += strlen(walk) + 1)
00134       {
00135         *iCert = nsnull;
00136         *iCV = 0;
00137         *iCII = nsnull;
00138         *iCEI = nsnull;
00139 
00140         if (memory_failure) {
00141           *iEA = nsnull;
00142           continue;
00143         }
00144 
00145         nsDependentCString email(walk);
00146         *iEA = ToNewUnicode(email);
00147         if (!*iEA) {
00148           memory_failure = PR_TRUE;
00149           continue;
00150         }
00151 
00152         nsCString email_lowercase;
00153         ToLowerCase(email, email_lowercase);
00154 
00155         nsCOMPtr<nsIX509Cert> cert;
00156         if (NS_SUCCEEDED(certdb->FindCertByEmailAddress(nsnull, email_lowercase.get(), getter_AddRefs(cert))) 
00157             && cert)
00158         {
00159           *iCert = cert;
00160           NS_ADDREF(*iCert);
00161           
00162           PRUint32 verification_result;
00163           
00164           if (NS_FAILED(
00165               cert->VerifyForUsage(nsIX509Cert::CERT_USAGE_EmailRecipient, &verification_result)))
00166           {
00167             *iCV = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
00168             found_blocker = PR_TRUE;
00169           }
00170           else
00171           {
00172             *iCV = verification_result;
00173             
00174             if (verification_result != nsIX509Cert::VERIFIED_OK)
00175             {
00176               found_blocker = PR_TRUE;
00177             }
00178           }
00179           
00180           nsCOMPtr<nsIX509CertValidity> validity;
00181           rv = cert->GetValidity(getter_AddRefs(validity));
00182 
00183           if (NS_SUCCEEDED(rv)) {
00184             nsXPIDLString id, ed;
00185 
00186             if (NS_SUCCEEDED(validity->GetNotBeforeLocalDay(id)))
00187             {
00188               *iCII = ToNewUnicode(id);
00189               if (!*iCII) {
00190                 memory_failure = PR_TRUE;
00191                 continue;
00192               }
00193             }
00194 
00195             if (NS_SUCCEEDED(validity->GetNotAfterLocalDay(ed)))
00196             {
00197               *iCEI = ToNewUnicode(ed);
00198               if (!*iCEI) {
00199                 memory_failure = PR_TRUE;
00200                 continue;
00201               }
00202             }
00203           }
00204         }
00205         else
00206         {
00207           found_blocker = PR_TRUE;
00208         }
00209       }
00210 
00211       if (memory_failure) {
00212         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mailbox_count, outEA);
00213         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mailbox_count, outCII);
00214         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mailbox_count, outCEI);
00215         NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(mailbox_count, outCerts);
00216         nsMemory::Free(outCV);
00217         rv = NS_ERROR_OUT_OF_MEMORY;
00218       }
00219       else {
00220         if (mailbox_count > 0 && !found_blocker)
00221         {
00222           *canEncrypt = PR_TRUE;
00223         }
00224 
00225         *emailAddresses = outEA;
00226         *certVerification = outCV;
00227         *certIssuedInfos = outCII;
00228         *certExpiresInfos = outCEI;
00229         *certs = outCerts;
00230       }
00231     }
00232   }
00233 
00234   if (mailbox_list) {
00235     nsMemory::Free(mailbox_list);
00236   }
00237   return rv;
00238 }
00239 
00240 NS_IMETHODIMP nsSMimeJSHelper::GetNoCertAddresses(
00241     nsIMsgCompFields *compFields, 
00242     PRUint32 *count, 
00243     PRUnichar ***emailAddresses)
00244 {
00245   NS_ENSURE_ARG_POINTER(count);
00246   *count = 0;
00247   
00248   NS_ENSURE_ARG_POINTER(emailAddresses);
00249 
00250   NS_ENSURE_ARG_POINTER(compFields);
00251 
00252   PRUint32 mailbox_count;
00253   char *mailbox_list;
00254 
00255   nsresult rv = getMailboxList(compFields, &mailbox_count, &mailbox_list);
00256   if (NS_FAILED(rv))
00257     return rv;
00258 
00259   if (!mailbox_list)
00260     return NS_ERROR_FAILURE;
00261 
00262   if (!mailbox_count)
00263   {
00264     *count = 0;
00265     *emailAddresses = nsnull;
00266     if (mailbox_list) {
00267       nsMemory::Free(mailbox_list);
00268     }
00269     return NS_OK;
00270   }
00271 
00272   nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
00273 
00274   PRUint32 missing_count = 0;
00275   PRBool *haveCert = new PRBool[mailbox_count];
00276   if (!haveCert)
00277   {
00278     if (mailbox_list) {
00279       nsMemory::Free(mailbox_list);
00280     }
00281     return NS_ERROR_OUT_OF_MEMORY;
00282   }
00283 
00284   rv = NS_OK;
00285 
00286   if (mailbox_count)
00287   {
00288     const char *walk = mailbox_list;
00289 
00290     // To understand this loop, especially the "+= strlen +1", look at the documentation
00291     // of ParseHeaderAddresses. Basically, it returns a list of zero terminated strings.
00292     for (PRUint32 i = 0;
00293         i < mailbox_count;
00294         ++i, walk += strlen(walk) + 1)
00295     {
00296       haveCert[i] = PR_FALSE;
00297 
00298       nsDependentCString email(walk);
00299       nsCString email_lowercase;
00300       ToLowerCase(email, email_lowercase);
00301 
00302       nsCOMPtr<nsIX509Cert> cert;
00303       if (NS_SUCCEEDED(certdb->FindCertByEmailAddress(nsnull, email_lowercase.get(), getter_AddRefs(cert))) 
00304           && cert)
00305       {
00306         PRUint32 verification_result;
00307 
00308         if (NS_SUCCEEDED(
00309               cert->VerifyForUsage(nsIX509Cert::CERT_USAGE_EmailRecipient, &verification_result))
00310             &&
00311             nsIX509Cert::VERIFIED_OK == verification_result)
00312         {
00313           haveCert[i] = PR_TRUE;
00314         }
00315       }
00316 
00317       if (!haveCert[i])
00318         ++missing_count;
00319     }
00320   }
00321 
00322   *count = missing_count;
00323 
00324   if (missing_count)
00325   {
00326     PRUnichar **outEA = NS_STATIC_CAST(PRUnichar **, nsMemory::Alloc(missing_count * sizeof(PRUnichar *)));
00327     if (!outEA )
00328     {
00329       rv = NS_ERROR_OUT_OF_MEMORY;
00330     }
00331     else
00332     {
00333       PRUnichar **iEA = outEA;
00334       const char *walk = mailbox_list;
00335 
00336       PRBool memory_failure = PR_FALSE;
00337 
00338       // To understand this loop, especially the "+= strlen +1", look at the documentation
00339       // of ParseHeaderAddresses. Basically, it returns a list of zero terminated strings.
00340       for (PRUint32 i = 0;
00341           i < mailbox_count;
00342           ++i, walk += strlen(walk) + 1)
00343       {
00344         if (!haveCert[i])
00345         {
00346           if (memory_failure) {
00347             *iEA = nsnull;
00348           }
00349           else {
00350             *iEA = ToNewUnicode(nsDependentCString(walk));
00351             if (!*iEA) {
00352               memory_failure = PR_TRUE;
00353             }
00354           }
00355           ++iEA;
00356         }
00357       }
00358       
00359       if (memory_failure) {
00360         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(missing_count, outEA);
00361         rv = NS_ERROR_OUT_OF_MEMORY;
00362       }
00363       else {
00364         *emailAddresses = outEA;
00365       }
00366     }
00367   }
00368   else
00369   {
00370     *emailAddresses = nsnull;
00371   }
00372 
00373   delete [] haveCert;
00374   if (mailbox_list) {
00375     nsMemory::Free(mailbox_list);
00376   }
00377   return rv;
00378 }
00379 
00380 nsresult nsSMimeJSHelper::getMailboxList(nsIMsgCompFields *compFields, PRUint32 *mailbox_count, char **mailbox_list)
00381 {
00382   NS_ENSURE_ARG(mailbox_count);
00383   NS_ENSURE_ARG(mailbox_list);
00384 
00385   if (!compFields)
00386     return NS_ERROR_INVALID_ARG;
00387 
00388   nsresult res;
00389   nsCOMPtr<nsIMsgHeaderParser> parser = do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID, &res);
00390   if (NS_FAILED(res))
00391     return res;
00392 
00393   nsXPIDLString to, cc, bcc, ng;
00394 
00395   res = compFields->GetTo(to);
00396   if (NS_FAILED(res))
00397     return res;
00398 
00399   res = compFields->GetCc(cc);
00400   if (NS_FAILED(res))
00401     return res;
00402 
00403   res = compFields->GetBcc(bcc);
00404   if (NS_FAILED(res))
00405     return res;
00406 
00407   res = compFields->GetNewsgroups(ng);
00408   if (NS_FAILED(res))
00409     return res;
00410 
00411   *mailbox_list = nsnull;
00412   *mailbox_count = 0;
00413   
00414   {
00415     nsCString all_recipients;
00416 
00417     if (!to.IsEmpty()) {
00418       AppendUTF16toUTF8(to, all_recipients);
00419       all_recipients.Append(',');
00420     }
00421 
00422     if (!cc.IsEmpty()) {
00423       AppendUTF16toUTF8(cc, all_recipients);
00424       all_recipients.Append(',');
00425     }
00426 
00427     if (!bcc.IsEmpty()) {
00428       AppendUTF16toUTF8(bcc, all_recipients);
00429       all_recipients.Append(',');
00430     }
00431 
00432     if (!ng.IsEmpty()) {
00433       AppendUTF16toUTF8(ng, all_recipients);
00434     }
00435 
00436     char *unique_mailboxes = nsnull;
00437 
00438     {
00439       char *all_mailboxes = nsnull;
00440       parser->ExtractHeaderAddressMailboxes(nsnull, all_recipients.get(), &all_mailboxes);
00441       parser->RemoveDuplicateAddresses(nsnull, all_mailboxes, 0, PR_FALSE /*removeAliasesToMe*/, &unique_mailboxes);
00442       if (all_mailboxes) {
00443         nsMemory::Free(all_mailboxes);
00444       }
00445     }
00446     if (unique_mailboxes)
00447     {
00448       parser->ParseHeaderAddresses(nsnull, unique_mailboxes, 0, mailbox_list, mailbox_count);
00449     }
00450     if (unique_mailboxes) {
00451       nsMemory::Free(unique_mailboxes);
00452     }
00453   }
00454 
00455   return NS_OK;
00456 }