Back to index

lightning-sunbird  0.9+nobinonly
nsCertTree.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 the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Ian McGreer <mcgreer@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * 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 "nsNSSComponent.h" // for PIPNSS string bundle calls.
00039 #include "nsCertTree.h"
00040 #include "nsITreeColumns.h"
00041 #include "nsIX509Cert.h"
00042 #include "nsIX509CertValidity.h"
00043 #include "nsIX509CertDB.h"
00044 #include "nsXPIDLString.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsNSSCertificate.h"
00047 #include "nsNSSCertHelper.h"
00048 #include "nsINSSCertCache.h"
00049 
00050 #include "prlog.h"
00051 #ifdef PR_LOGGING
00052 extern PRLogModuleInfo* gPIPNSSLog;
00053 #endif
00054 
00055 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00056 
00057 // treeArrayElStr
00058 //
00059 // structure used to hold map of tree.  Each thread (an organization
00060 // field from a cert) has an element in the array.  The numChildren field
00061 // stores the number of certs corresponding to that thread.
00062 struct treeArrayElStr {
00063   nsString   orgName;     /* heading for thread                   */
00064   PRBool     open;        /* toggle open state for thread         */
00065   PRInt32    certIndex;   /* index into cert array for 1st cert   */
00066   PRInt32    numChildren; /* number of chidren (certs) for thread */
00067 };
00068 
00069 CompareCacheHashEntryPtr::CompareCacheHashEntryPtr()
00070 {
00071   entry = new CompareCacheHashEntry;
00072 }
00073 
00074 CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr()
00075 {
00076   if (entry) {
00077     delete entry;
00078   }
00079 }
00080 
00081 CompareCacheHashEntry::CompareCacheHashEntry()
00082 :key(nsnull)
00083 {
00084   for (int i = 0; i < max_criterions; ++i) {
00085     mCritInit[i] = PR_FALSE;
00086   }
00087 }
00088 
00089 PR_STATIC_CALLBACK(const void *)
00090 CompareCacheGetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00091 {
00092   CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
00093   return entryPtr->entry->key;
00094 }
00095 
00096 PR_STATIC_CALLBACK(PRBool)
00097 CompareCacheMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00098                          const void *key)
00099 {
00100   const CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(const CompareCacheHashEntryPtr*, hdr);
00101   return entryPtr->entry->key == key;
00102 }
00103 
00104 PR_STATIC_CALLBACK(PRBool)
00105 CompareCacheInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
00106                      const void *key)
00107 {
00108   new (hdr) CompareCacheHashEntryPtr();
00109   CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
00110   if (!entryPtr->entry) {
00111     return PR_FALSE;
00112   }
00113   entryPtr->entry->key = (void*)key;
00114   return PR_TRUE;
00115 }
00116 
00117 PR_STATIC_CALLBACK(void)
00118 CompareCacheClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
00119 {
00120   CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
00121   entryPtr->~CompareCacheHashEntryPtr();
00122 }
00123 
00124 static PLDHashTableOps gMapOps = {
00125   PL_DHashAllocTable,
00126   PL_DHashFreeTable,
00127   CompareCacheGetKey,
00128   PL_DHashVoidPtrKeyStub,
00129   CompareCacheMatchEntry,
00130   PL_DHashMoveEntryStub,
00131   CompareCacheClearEntry,
00132   PL_DHashFinalizeStub,
00133   CompareCacheInitEntry
00134 };
00135 
00136 
00137 
00138 NS_IMPL_ISUPPORTS2(nsCertTree, nsICertTree, nsITreeView)
00139 
00140 nsCertTree::nsCertTree() : mTreeArray(NULL)
00141 {
00142   mCompareCache.ops = nsnull;
00143   mNSSComponent = do_GetService(kNSSComponentCID);
00144 }
00145 
00146 void nsCertTree::ClearCompareHash()
00147 {
00148   if (mCompareCache.ops) {
00149     PL_DHashTableFinish(&mCompareCache);
00150     mCompareCache.ops = nsnull;
00151   }
00152 }
00153 
00154 nsresult nsCertTree::InitCompareHash()
00155 {
00156   ClearCompareHash();
00157   if (!PL_DHashTableInit(&mCompareCache, &gMapOps, nsnull,
00158                          sizeof(CompareCacheHashEntryPtr), 128)) {
00159     mCompareCache.ops = nsnull;
00160     return NS_ERROR_OUT_OF_MEMORY;
00161   }
00162   return NS_OK;
00163 }
00164 
00165 nsCertTree::~nsCertTree()
00166 {
00167   ClearCompareHash();
00168   delete [] mTreeArray;
00169 }
00170 
00171 void
00172 nsCertTree::FreeCertArray()
00173 {
00174   if (mCertArray) {
00175     PRUint32 count;
00176     nsresult rv = mCertArray->Count(&count);
00177     if (NS_FAILED(rv))
00178     {
00179       NS_ASSERTION(0, "Count failed");
00180       return;
00181     }
00182     PRInt32 i;
00183     for (i = count - 1; i >= 0; i--)
00184     {
00185       mCertArray->RemoveElementAt(i);
00186     }
00187   }
00188 }
00189 
00190 CompareCacheHashEntry *
00191 nsCertTree::getCacheEntry(void *cache, void *aCert)
00192 {
00193   PLDHashTable &aCompareCache = *NS_REINTERPRET_CAST(PLDHashTable*, cache);
00194   CompareCacheHashEntryPtr *entryPtr = 
00195     NS_STATIC_CAST(CompareCacheHashEntryPtr*,
00196                    PL_DHashTableOperate(&aCompareCache, aCert, PL_DHASH_ADD));
00197   return entryPtr ? entryPtr->entry : NULL;
00198 }
00199 
00200 void nsCertTree::RemoveCacheEntry(void *key)
00201 {
00202   PL_DHashTableOperate(&mCompareCache, key, PL_DHASH_REMOVE);
00203 }
00204 
00205 // CountOrganizations
00206 //
00207 // Count the number of different organizations encountered in the cert
00208 // list.
00209 PRInt32
00210 nsCertTree::CountOrganizations()
00211 {
00212   PRUint32 i, certCount;
00213   nsresult rv = mCertArray->Count(&certCount);
00214   if (NS_FAILED(rv)) return -1;
00215   if (certCount == 0) return 0;
00216   nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(0));
00217   nsCOMPtr<nsIX509Cert> orgCert = do_QueryInterface(isupport);
00218   nsCOMPtr<nsIX509Cert> nextCert = nsnull;
00219   PRInt32 orgCount = 1;
00220   for (i=1; i<certCount; i++) {
00221     isupport = dont_AddRef(mCertArray->ElementAt(i));
00222     nextCert = do_QueryInterface(isupport);
00223     // XXX we assume issuer org is always criterion 1
00224     if (CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None) != 0) {
00225       orgCert = nextCert;
00226       orgCount++;
00227     }
00228   }
00229   return orgCount;
00230 }
00231 
00232 // GetThreadDescAtIndex
00233 //
00234 // If the row at index is an organization thread, return the collection
00235 // associated with that thread.  Otherwise, return null.
00236 treeArrayEl *
00237 nsCertTree::GetThreadDescAtIndex(PRInt32 index)
00238 {
00239   int i, idx=0;
00240   if (index < 0) return nsnull;
00241   for (i=0; i<mNumOrgs; i++) {
00242     if (index == idx) {
00243       return &mTreeArray[i];
00244     }
00245     if (mTreeArray[i].open) {
00246       idx += mTreeArray[i].numChildren;
00247     }
00248     idx++;
00249     if (idx > index) break;
00250   }
00251   return nsnull;
00252 }
00253 
00254 //  GetCertAtIndex
00255 //
00256 //  If the row at index is a cert, return that cert.  Otherwise, return null.
00257 nsIX509Cert *
00258 nsCertTree::GetCertAtIndex(PRInt32 index)
00259 {
00260   int i, idx = 0, cIndex = 0, nc;
00261   nsIX509Cert *rawPtr = nsnull;
00262   if (index < 0) return nsnull;
00263   // Loop over the threads
00264   for (i=0; i<mNumOrgs; i++) {
00265     if (index == idx) return nsnull; // index is for thread
00266     idx++; // get past the thread
00267     nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
00268     if (index < idx + nc) { // cert is within range of this thread
00269       PRInt32 certIndex = cIndex + index - idx;
00270       nsCOMPtr<nsISupports> isupport = 
00271                              dont_AddRef(mCertArray->ElementAt(certIndex));
00272       nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(isupport);
00273       rawPtr = cert;
00274       NS_IF_ADDREF(rawPtr);
00275       break;
00276     }
00277     if (mTreeArray[i].open)
00278       idx += mTreeArray[i].numChildren;
00279     cIndex += mTreeArray[i].numChildren;
00280     if (idx > index) break;
00281   }
00282   return rawPtr;
00283 }
00284 
00285 nsCertTree::nsCertCompareFunc
00286 nsCertTree::GetCompareFuncFromCertType(PRUint32 aType)
00287 {
00288   switch (aType) {
00289     case nsIX509Cert::USER_CERT:
00290       return CmpUserCert;
00291     case nsIX509Cert::CA_CERT:
00292       return CmpCACert;
00293     case nsIX509Cert::EMAIL_CERT:
00294       return CmpEmailCert;
00295     case nsIX509Cert::SERVER_CERT:
00296     default:
00297       return CmpWebSiteCert;
00298   }
00299 }
00300 
00301 PRBool
00302 nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
00303                                        PRUint32 aType,
00304                                        nsCertCompareFunc  aCertCmpFn,
00305                                        void *aCertCmpFnArg,
00306                                        nsISupportsArray **_certs)
00307 {
00308   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByTypeFromCertList"));
00309   if (!aCertList)
00310     return PR_FALSE;
00311   nsCOMPtr<nsISupportsArray> certarray;
00312   nsresult rv = NS_NewISupportsArray(getter_AddRefs(certarray));
00313   if (NS_FAILED(rv)) return PR_FALSE;
00314   CERTCertListNode *node;
00315   int count = 0;
00316   for (node = CERT_LIST_HEAD(aCertList);
00317        !CERT_LIST_END(node, aCertList);
00318        node = CERT_LIST_NEXT(node)) {
00319     if (getCertType(node->cert) == aType) {
00320       nsCOMPtr<nsIX509Cert> pipCert = new nsNSSCertificate(node->cert);
00321       if (pipCert) {
00322         int i;
00323         for (i = 0; i < count; ++i) {
00324           nsCOMPtr<nsIX509Cert> cert = do_QueryElementAt(certarray, i);
00325           if ((*aCertCmpFn)(aCertCmpFnArg, pipCert, cert) < 0) {
00326             break;
00327           }
00328         }
00329         certarray->InsertElementAt(pipCert, i);
00330         ++count;
00331       }
00332     }
00333   }
00334   *_certs = certarray;
00335   NS_ADDREF(*_certs);
00336   return PR_TRUE;
00337 }
00338 
00339 PRBool 
00340 nsCertTree::GetCertsByType(PRUint32           aType,
00341                            nsCertCompareFunc  aCertCmpFn,
00342                            void              *aCertCmpFnArg,
00343                            nsISupportsArray **_certs)
00344 {
00345   nsNSSShutDownPreventionLock locker;
00346   CERTCertList *certList = NULL;
00347   nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
00348   certList = PK11_ListCerts(PK11CertListUnique, cxt);
00349   PRBool rv = GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg, _certs);
00350   if (certList)
00351     CERT_DestroyCertList(certList);
00352   return rv;
00353 }
00354 
00355 PRBool 
00356 nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache   *aCache,
00357                                     PRUint32           aType,
00358                                     nsCertCompareFunc  aCertCmpFn,
00359                                     void              *aCertCmpFnArg,
00360                                     nsISupportsArray **_certs)
00361 {
00362   NS_ENSURE_ARG_POINTER(aCache);
00363   CERTCertList *certList = NS_REINTERPRET_CAST(CERTCertList*, aCache->GetCachedCerts());
00364   if (!certList)
00365     return NS_ERROR_FAILURE;
00366   return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg, _certs);
00367 }
00368 
00369 // LoadCerts
00370 //
00371 // Load all of the certificates in the DB for this type.  Sort them
00372 // by token, organization, then common name.
00373 NS_IMETHODIMP 
00374 nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, PRUint32 aType)
00375 {
00376   if (mTreeArray) {
00377     FreeCertArray();
00378     delete [] mTreeArray;
00379     mTreeArray = nsnull;
00380     mNumRows = 0;
00381   }
00382   nsresult rv = InitCompareHash();
00383   if (NS_FAILED(rv)) return rv;
00384 
00385   rv = GetCertsByTypeFromCache(aCache, aType, 
00386                                GetCompareFuncFromCertType(aType), &mCompareCache,
00387                                getter_AddRefs(mCertArray));
00388   if (NS_FAILED(rv)) return rv;
00389   return UpdateUIContents();
00390 }
00391 
00392 NS_IMETHODIMP 
00393 nsCertTree::LoadCerts(PRUint32 aType)
00394 {
00395   if (mTreeArray) {
00396     FreeCertArray();
00397     delete [] mTreeArray;
00398     mTreeArray = nsnull;
00399     mNumRows = 0;
00400   }
00401   nsresult rv = InitCompareHash();
00402   if (NS_FAILED(rv)) return rv;
00403 
00404   rv = GetCertsByType(aType, 
00405                       GetCompareFuncFromCertType(aType), &mCompareCache,
00406                       getter_AddRefs(mCertArray));
00407   if (NS_FAILED(rv)) return rv;
00408   return UpdateUIContents();
00409 }
00410 
00411 nsresult
00412 nsCertTree::UpdateUIContents()
00413 {
00414   PRUint32 count;
00415   nsresult rv = mCertArray->Count(&count);
00416   if (NS_FAILED(rv)) return rv;
00417   mNumOrgs = CountOrganizations();
00418   mTreeArray = new treeArrayEl[mNumOrgs];
00419   if (!mTreeArray)
00420     return NS_ERROR_OUT_OF_MEMORY;
00421 
00422   PRUint32 j = 0;
00423   nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(j));
00424   nsCOMPtr<nsIX509Cert> orgCert = do_QueryInterface(isupport);
00425   for (PRInt32 i=0; i<mNumOrgs; i++) {
00426     orgCert->GetIssuerOrganization(mTreeArray[i].orgName);
00427     mTreeArray[i].open = PR_TRUE;
00428     mTreeArray[i].certIndex = j;
00429     mTreeArray[i].numChildren = 1;
00430     if (++j >= count) break;
00431     isupport = dont_AddRef(mCertArray->ElementAt(j));
00432     nsCOMPtr<nsIX509Cert> nextCert = do_QueryInterface(isupport);
00433     while (0 == CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None)) {
00434       mTreeArray[i].numChildren++;
00435       if (++j >= count) break;
00436       isupport = dont_AddRef(mCertArray->ElementAt(j));
00437       nextCert = do_QueryInterface(isupport);
00438     }
00439     orgCert = nextCert;
00440   }
00441   if (mTree) {
00442     mTree->BeginUpdateBatch();
00443     mTree->RowCountChanged(0, -mNumRows);
00444   }
00445   mNumRows = count + mNumOrgs;
00446   if (mTree)
00447     mTree->EndUpdateBatch();
00448   return NS_OK;
00449 }
00450 
00451 NS_IMETHODIMP 
00452 nsCertTree::RemoveCert(PRUint32 index)
00453 {
00454   if (!mCertArray || !mTreeArray || index < 0) {
00455     return NS_ERROR_FAILURE;
00456   }
00457 
00458   int i;
00459   PRUint32 idx = 0, cIndex = 0, nc;
00460   // Loop over the threads
00461   for (i=0; i<mNumOrgs; i++) {
00462     if (index == idx)
00463       return NS_OK; // index is for thread
00464     idx++; // get past the thread
00465     nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
00466     if (index < idx + nc) { // cert is within range of this thread
00467       PRInt32 certIndex = cIndex + index - idx;
00468       nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(certIndex));
00469       RemoveCacheEntry(isupport);
00470       mCertArray->RemoveElementAt(certIndex);
00471       delete [] mTreeArray;
00472       mTreeArray = nsnull;
00473       return UpdateUIContents();
00474     }
00475     if (mTreeArray[i].open)
00476       idx += mTreeArray[i].numChildren;
00477     cIndex += mTreeArray[i].numChildren;
00478     if (idx > index)
00479       break;
00480   }
00481   return NS_ERROR_FAILURE;
00482 }
00483 
00485 //
00486 //  Begin nsITreeView methods
00487 //
00489 
00490 /* nsIX509Cert getCert(in unsigned long index); */
00491 NS_IMETHODIMP
00492 nsCertTree::GetCert(PRUint32 aIndex, nsIX509Cert **_cert)
00493 {
00494   NS_ENSURE_ARG(_cert);
00495   *_cert = GetCertAtIndex(aIndex);
00496   //nsCOMPtr<nsIX509Cert> cert = GetCertAtIndex(aIndex);
00497   //if (cert) {
00498     //*_cert = cert;
00499     //NS_ADDREF(*_cert);
00500   //}
00501   return NS_OK;
00502 }
00503 
00504 /* readonly attribute long rowCount; */
00505 NS_IMETHODIMP 
00506 nsCertTree::GetRowCount(PRInt32 *aRowCount)
00507 {
00508   if (!mTreeArray)
00509     return NS_ERROR_NOT_INITIALIZED;
00510   PRUint32 count = 0;
00511   for (PRInt32 i=0; i<mNumOrgs; i++) {
00512     if (mTreeArray[i].open) {
00513       count += mTreeArray[i].numChildren;
00514     }
00515     count++;
00516   }
00517   *aRowCount = count;
00518   return NS_OK;
00519 }
00520 
00521 /* attribute nsITreeSelection selection; */
00522 NS_IMETHODIMP 
00523 nsCertTree::GetSelection(nsITreeSelection * *aSelection)
00524 {
00525   *aSelection = mSelection;
00526   NS_IF_ADDREF(*aSelection);
00527   return NS_OK;
00528 }
00529 
00530 NS_IMETHODIMP 
00531 nsCertTree::SetSelection(nsITreeSelection * aSelection)
00532 {
00533   mSelection = aSelection;
00534   return NS_OK;
00535 }
00536 
00537 /* void getRowProperties (in long index, in nsISupportsArray properties); */
00538 NS_IMETHODIMP 
00539 nsCertTree::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
00540 {
00541   return NS_OK;
00542 }
00543 
00544 /* void getCellProperties (in long row, in nsITreeColumn col, 
00545  *                         in nsISupportsArray properties); 
00546  */
00547 NS_IMETHODIMP 
00548 nsCertTree::GetCellProperties(PRInt32 row, nsITreeColumn* col, 
00549                               nsISupportsArray* properties)
00550 {
00551   return NS_OK;
00552 }
00553 
00554 /* void getColumnProperties (in nsITreeColumn col, 
00555  *                           in nsISupportsArray properties); 
00556  */
00557 NS_IMETHODIMP 
00558 nsCertTree::GetColumnProperties(nsITreeColumn* col, 
00559                                 nsISupportsArray* properties)
00560 {
00561   return NS_OK;
00562 }
00563 
00564 /* boolean isContainer (in long index); */
00565 NS_IMETHODIMP 
00566 nsCertTree::IsContainer(PRInt32 index, PRBool *_retval)
00567 {
00568   if (!mTreeArray)
00569     return NS_ERROR_NOT_INITIALIZED;
00570   treeArrayEl *el = GetThreadDescAtIndex(index);
00571   if (el) {
00572     *_retval = PR_TRUE;
00573   } else {
00574     *_retval = PR_FALSE;
00575   }
00576   return NS_OK;
00577 }
00578 
00579 /* boolean isContainerOpen (in long index); */
00580 NS_IMETHODIMP 
00581 nsCertTree::IsContainerOpen(PRInt32 index, PRBool *_retval)
00582 {
00583   if (!mTreeArray)
00584     return NS_ERROR_NOT_INITIALIZED;
00585   treeArrayEl *el = GetThreadDescAtIndex(index);
00586   if (el && el->open) {
00587     *_retval = PR_TRUE;
00588   } else {
00589     *_retval = PR_FALSE;
00590   }
00591   return NS_OK;
00592 }
00593 
00594 /* boolean isContainerEmpty (in long index); */
00595 NS_IMETHODIMP 
00596 nsCertTree::IsContainerEmpty(PRInt32 index, PRBool *_retval)
00597 {
00598   *_retval = !mTreeArray;
00599   return NS_OK;
00600 }
00601 
00602 /* boolean isSeparator (in long index); */
00603 NS_IMETHODIMP 
00604 nsCertTree::IsSeparator(PRInt32 index, PRBool *_retval)
00605 {
00606   *_retval = PR_FALSE;
00607   return NS_OK;
00608 }
00609 
00610 /* long getParentIndex (in long rowIndex); */
00611 NS_IMETHODIMP 
00612 nsCertTree::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
00613 {
00614   if (!mTreeArray)
00615     return NS_ERROR_NOT_INITIALIZED;
00616   int i, idx = 0;
00617   for (i = 0; i < mNumOrgs && idx < rowIndex; i++, idx++) {
00618     if (mTreeArray[i].open) {
00619       if (rowIndex <= idx + mTreeArray[i].numChildren) {
00620         *_retval = idx;
00621         return NS_OK;
00622       }
00623       idx += mTreeArray[i].numChildren;
00624     }
00625   }
00626   *_retval = -1;
00627   return NS_OK;
00628 }
00629 
00630 /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */
00631 NS_IMETHODIMP 
00632 nsCertTree::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, 
00633                                PRBool *_retval)
00634 {
00635   if (!mTreeArray)
00636     return NS_ERROR_NOT_INITIALIZED;
00637 
00638   int i, idx = 0;
00639   for (i = 0; i < mNumOrgs && idx <= rowIndex; i++, idx++) {
00640     if (mTreeArray[i].open) {
00641       idx += mTreeArray[i].numChildren;
00642       if (afterIndex <= idx) {
00643         *_retval = afterIndex < idx;
00644         return NS_OK;
00645       }
00646     }
00647   }
00648   *_retval = PR_FALSE;
00649   return NS_OK;
00650 }
00651 
00652 /* long getLevel (in long index); */
00653 NS_IMETHODIMP 
00654 nsCertTree::GetLevel(PRInt32 index, PRInt32 *_retval)
00655 {
00656   if (!mTreeArray)
00657     return NS_ERROR_NOT_INITIALIZED;
00658   treeArrayEl *el = GetThreadDescAtIndex(index);
00659   if (el) {
00660     *_retval = 0;
00661   } else {
00662     *_retval = 1;
00663   }
00664   return NS_OK;
00665 }
00666 
00667 /* Astring getImageSrc (in long row, in nsITreeColumn col); */
00668 NS_IMETHODIMP 
00669 nsCertTree::GetImageSrc(PRInt32 row, nsITreeColumn* col, 
00670                         nsAString& _retval)
00671 {
00672   _retval.Truncate();
00673   return NS_OK;
00674 }
00675 
00676 /* long getProgressMode (in long row, in nsITreeColumn col); */
00677 NS_IMETHODIMP
00678 nsCertTree::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval)
00679 {
00680   return NS_OK;
00681 }
00682 
00683 /* Astring getCellValue (in long row, in nsITreeColumn col); */
00684 NS_IMETHODIMP 
00685 nsCertTree::GetCellValue(PRInt32 row, nsITreeColumn* col, 
00686                          nsAString& _retval)
00687 {
00688   _retval.Truncate();
00689   return NS_OK;
00690 }
00691 
00692 /* Astring getCellText (in long row, in nsITreeColumn col); */
00693 NS_IMETHODIMP 
00694 nsCertTree::GetCellText(PRInt32 row, nsITreeColumn* col, 
00695                         nsAString& _retval)
00696 {
00697   if (!mTreeArray)
00698     return NS_ERROR_NOT_INITIALIZED;
00699 
00700   nsresult rv;
00701   _retval.Truncate();
00702 
00703   const PRUnichar* colID;
00704   col->GetIdConst(&colID);
00705 
00706   treeArrayEl *el = GetThreadDescAtIndex(row);
00707   if (el != nsnull) {
00708     if (NS_LITERAL_STRING("certcol").Equals(colID))
00709       _retval.Assign(el->orgName);
00710     else
00711       _retval.SetCapacity(0);
00712     return NS_OK;
00713   }
00714   nsCOMPtr<nsIX509Cert> cert = dont_AddRef(GetCertAtIndex(row));
00715   if (cert == nsnull) return NS_ERROR_FAILURE;
00716   if (NS_LITERAL_STRING("certcol").Equals(colID)) {
00717     rv = cert->GetCommonName(_retval);
00718     if (NS_FAILED(rv) || _retval.IsEmpty()) {
00719       // kaie: I didn't invent the idea to cut off anything before 
00720       //       the first colon. :-)
00721       nsAutoString nick;
00722       rv = cert->GetNickname(nick);
00723       
00724       nsAString::const_iterator start, end, end2;
00725       nick.BeginReading(start);
00726       nick.EndReading(end);
00727       end2 = end;
00728 
00729       if (FindInReadable(NS_LITERAL_STRING(":"), start, end)) {
00730         // found. end points to the first char after the colon,
00731         // that's what we want.
00732         _retval = Substring(end, end2);
00733       }
00734       else {
00735         _retval = nick;
00736       }
00737     }
00738   } else if (NS_LITERAL_STRING("tokencol").Equals(colID)) {
00739     rv = cert->GetTokenName(_retval);
00740   } else if (NS_LITERAL_STRING("emailcol").Equals(colID)) {
00741     rv = cert->GetEmailAddress(_retval);
00742   } else if (NS_LITERAL_STRING("purposecol").Equals(colID) && mNSSComponent) {
00743     PRUint32 verified;
00744 
00745     nsAutoString theUsages;
00746     rv = cert->GetUsagesString(PR_TRUE, &verified, theUsages); // ignore OCSP
00747     if (NS_FAILED(rv)) {
00748       verified = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
00749     }
00750 
00751     switch (verified) {
00752       case nsIX509Cert::VERIFIED_OK:
00753         _retval = theUsages;
00754         break;
00755 
00756       case nsIX509Cert::CERT_REVOKED:
00757         rv = mNSSComponent->GetPIPNSSBundleString("VerifyRevoked", _retval);
00758         break;
00759       case nsIX509Cert::CERT_EXPIRED:
00760         rv = mNSSComponent->GetPIPNSSBundleString("VerifyExpired", _retval);
00761         break;
00762       case nsIX509Cert::CERT_NOT_TRUSTED:
00763         rv = mNSSComponent->GetPIPNSSBundleString("VerifyNotTrusted", _retval);
00764         break;
00765       case nsIX509Cert::ISSUER_NOT_TRUSTED:
00766         rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerNotTrusted", _retval);
00767         break;
00768       case nsIX509Cert::ISSUER_UNKNOWN:
00769         rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerUnknown", _retval);
00770         break;
00771       case nsIX509Cert::INVALID_CA:
00772         rv = mNSSComponent->GetPIPNSSBundleString("VerifyInvalidCA", _retval);
00773         break;
00774       case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
00775       case nsIX509Cert::USAGE_NOT_ALLOWED:
00776       default:
00777         rv = mNSSComponent->GetPIPNSSBundleString("VerifyUnknown", _retval);
00778         break;
00779     }
00780   } else if (NS_LITERAL_STRING("issuedcol").Equals(colID)) {
00781     nsCOMPtr<nsIX509CertValidity> validity;
00782 
00783     rv = cert->GetValidity(getter_AddRefs(validity));
00784     if (NS_SUCCEEDED(rv)) {
00785       validity->GetNotBeforeLocalDay(_retval);
00786     }
00787   } else if (NS_LITERAL_STRING("expiredcol").Equals(colID)) {
00788     nsCOMPtr<nsIX509CertValidity> validity;
00789 
00790     rv = cert->GetValidity(getter_AddRefs(validity));
00791     if (NS_SUCCEEDED(rv)) {
00792       validity->GetNotAfterLocalDay(_retval);
00793     }
00794   } else if (NS_LITERAL_STRING("serialnumcol").Equals(colID)) {
00795     rv = cert->GetSerialNumber(_retval);
00796   } else {
00797     return NS_ERROR_FAILURE;
00798   }
00799   return rv;
00800 }
00801 
00802 /* void setTree (in nsITreeBoxObject tree); */
00803 NS_IMETHODIMP 
00804 nsCertTree::SetTree(nsITreeBoxObject *tree)
00805 {
00806   mTree = tree;
00807   return NS_OK;
00808 }
00809 
00810 /* void toggleOpenState (in long index); */
00811 NS_IMETHODIMP 
00812 nsCertTree::ToggleOpenState(PRInt32 index)
00813 {
00814   if (!mTreeArray)
00815     return NS_ERROR_NOT_INITIALIZED;
00816   treeArrayEl *el = GetThreadDescAtIndex(index);
00817   if (el) el->open = !el->open;
00818   PRInt32 fac = (el->open) ? 1 : -1;
00819   if (mTree) mTree->RowCountChanged(index, fac * el->numChildren);
00820   mSelection->Select(index);
00821   return NS_OK;
00822 }
00823 
00824 /* void cycleHeader (in nsITreeColumn); */
00825 NS_IMETHODIMP 
00826 nsCertTree::CycleHeader(nsITreeColumn* col)
00827 {
00828   return NS_OK;
00829 }
00830 
00831 /* void selectionChanged (); */
00832 NS_IMETHODIMP 
00833 nsCertTree::SelectionChanged()
00834 {
00835   return NS_ERROR_NOT_IMPLEMENTED;
00836 }
00837 
00838 /* void cycleCell (in long row, in nsITreeColumn col); */
00839 NS_IMETHODIMP 
00840 nsCertTree::CycleCell(PRInt32 row, nsITreeColumn* col)
00841 {
00842   return NS_OK;
00843 }
00844 
00845 /* boolean isEditable (in long row, in nsITreeColumn col); */
00846 NS_IMETHODIMP 
00847 nsCertTree::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool *_retval)
00848 {
00849   *_retval = PR_FALSE;
00850   return NS_OK;
00851 }
00852 
00853 /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */
00854 NS_IMETHODIMP 
00855 nsCertTree::SetCellValue(PRInt32 row, nsITreeColumn* col, 
00856                          const nsAString& value)
00857 {
00858   return NS_OK;
00859 }
00860 
00861 /* void setCellText (in long row, in nsITreeColumn col, in AString value); */
00862 NS_IMETHODIMP 
00863 nsCertTree::SetCellText(PRInt32 row, nsITreeColumn* col, 
00864                         const nsAString& value)
00865 {
00866   return NS_OK;
00867 }
00868 
00869 /* void performAction (in wstring action); */
00870 NS_IMETHODIMP 
00871 nsCertTree::PerformAction(const PRUnichar *action)
00872 {
00873   return NS_OK;
00874 }
00875 
00876 /* void performActionOnRow (in wstring action, in long row); */
00877 NS_IMETHODIMP 
00878 nsCertTree::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
00879 {
00880   return NS_OK;
00881 }
00882 
00883 /* void performActionOnCell (in wstring action, in long row, 
00884  *                           in wstring colID); 
00885  */
00886 NS_IMETHODIMP 
00887 nsCertTree::PerformActionOnCell(const PRUnichar *action, PRInt32 row, 
00888                                 nsITreeColumn* col)
00889 {
00890   return NS_OK;
00891 }
00892 
00893 #ifdef DEBUG_CERT_TREE
00894 void
00895 nsCertTree::dumpMap()
00896 {
00897   for (int i=0; i<mNumOrgs; i++) {
00898     nsAutoString org(mTreeArray[i].orgName);
00899     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("ORG[%s]", NS_LossyConvertUCS2toASCII(org).get()));
00900     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("OPEN[%d]", mTreeArray[i].open));
00901     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("INDEX[%d]", mTreeArray[i].certIndex));
00902     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NCHILD[%d]", mTreeArray[i].numChildren));
00903   }
00904   for (int i=0; i<mNumRows; i++) {
00905     treeArrayEl *el = GetThreadDescAtIndex(i);
00906     if (el != nsnull) {
00907       nsAutoString td(el->orgName);
00908       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("thread desc[%d]: %s", i, NS_LossyConvertUCS2toASCII(td).get()));
00909     }
00910     nsCOMPtr<nsIX509Cert> ct = dont_AddRef(GetCertAtIndex(i));
00911     if (ct != nsnull) {
00912       PRUnichar *goo;
00913       ct->GetCommonName(&goo);
00914       nsAutoString doo(goo);
00915       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert [%d]: %s", i, NS_LossyConvertUCS2toASCII(doo).get()));
00916     }
00917   }
00918 }
00919 #endif
00920 
00921 //
00922 // CanDrop
00923 //
00924 NS_IMETHODIMP nsCertTree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
00925 {
00926   NS_ENSURE_ARG_POINTER(_retval);
00927   *_retval = PR_FALSE;
00928   
00929   return NS_OK;
00930 }
00931 
00932 
00933 //
00934 // Drop
00935 //
00936 NS_IMETHODIMP nsCertTree::Drop(PRInt32 row, PRInt32 orient)
00937 {
00938   return NS_OK;
00939 }
00940 
00941 
00942 //
00943 // IsSorted
00944 //
00945 // ...
00946 //
00947 NS_IMETHODIMP nsCertTree::IsSorted(PRBool *_retval)
00948 {
00949   *_retval = PR_FALSE;
00950   return NS_OK;
00951 }
00952 
00953 #define RETURN_NOTHING
00954 
00955 void 
00956 nsCertTree::CmpInitCriterion(nsIX509Cert *cert, CompareCacheHashEntry *entry,
00957                              sortCriterion crit, PRInt32 level)
00958 {
00959   NS_ENSURE_TRUE( (cert!=0 && entry!=0), RETURN_NOTHING );
00960 
00961   entry->mCritInit[level] = PR_TRUE;
00962   nsXPIDLString &str = entry->mCrit[level];
00963   
00964   switch (crit) {
00965     case sort_IssuerOrg:
00966       cert->GetIssuerOrganization(str);
00967       break;
00968     case sort_Org:
00969       cert->GetOrganization(str);
00970       break;
00971     case sort_Token:
00972       cert->GetTokenName(str);
00973       break;
00974     case sort_CommonName:
00975       cert->GetCommonName(str);
00976       break;
00977     case sort_IssuedDateDescending:
00978       {
00979         nsresult rv;
00980         nsCOMPtr<nsIX509CertValidity> validity;
00981         PRTime notBefore;
00982 
00983         rv = cert->GetValidity(getter_AddRefs(validity));
00984         if (NS_SUCCEEDED(rv)) {
00985           rv = validity->GetNotBefore(&notBefore);
00986         }
00987 
00988         if (NS_SUCCEEDED(rv)) {
00989           PRExplodedTime explodedTime;
00990           PR_ExplodeTime(notBefore, PR_GMTParameters, &explodedTime);
00991           char datebuf[20]; // 4 + 2 + 2 + 2 + 2 + 2 + 1 = 15
00992           if (0 != PR_FormatTime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", &explodedTime)) {
00993             str = NS_ConvertASCIItoUCS2(nsDependentCString(datebuf));
00994           }
00995         }
00996       }
00997       break;
00998     case sort_Email:
00999       cert->GetEmailAddress(str);
01000       break;
01001     case sort_None:
01002     default:
01003       break;
01004   }
01005 }
01006 
01007 PRInt32
01008 nsCertTree::CmpByCrit(nsIX509Cert *a, CompareCacheHashEntry *ace, 
01009                       nsIX509Cert *b, CompareCacheHashEntry *bce, 
01010                       sortCriterion crit, PRInt32 level)
01011 {
01012   NS_ENSURE_TRUE( (a!=0 && ace!=0 && b!=0 && bce!=0), 0 );
01013 
01014   if (!ace->mCritInit[level]) {
01015     CmpInitCriterion(a, ace, crit, level);
01016   }
01017 
01018   if (!bce->mCritInit[level]) {
01019     CmpInitCriterion(b, bce, crit, level);
01020   }
01021 
01022   nsXPIDLString &str_a = ace->mCrit[level];
01023   nsXPIDLString &str_b = bce->mCrit[level];
01024 
01025   PRInt32 result;
01026   if (str_a && str_b)
01027     result = Compare(str_a, str_b);
01028   else
01029     result = !str_a ? (!str_b ? 0 : -1) : 1;
01030 
01031   if (sort_IssuedDateDescending == crit)
01032     result *= -1; // reverse compare order
01033 
01034   return result;
01035 }
01036 
01037 PRInt32
01038 nsCertTree::CmpBy(void *cache, nsIX509Cert *a, nsIX509Cert *b, 
01039                   sortCriterion c0, sortCriterion c1, sortCriterion c2)
01040 {
01041   NS_ENSURE_TRUE( (cache!=0 && a!=0 && b!=0), 0 );
01042 
01043   if (a == b)
01044     return 0;
01045 
01046   CompareCacheHashEntry *ace = getCacheEntry(cache, a);
01047   CompareCacheHashEntry *bce = getCacheEntry(cache, b);
01048 
01049   PRInt32 cmp;
01050   cmp = CmpByCrit(a, ace, b, bce, c0, 0);
01051   if (cmp != 0)
01052     return cmp;
01053 
01054   if (c1 != sort_None) {
01055     cmp = CmpByCrit(a, ace, b, bce, c1, 1);
01056     if (cmp != 0)
01057       return cmp;
01058     
01059     if (c2 != sort_None) {
01060       return CmpByCrit(a, ace, b, bce, c2, 2);
01061     }
01062   }
01063 
01064   return cmp;
01065 }
01066 
01067 PRInt32
01068 nsCertTree::CmpCACert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
01069 {
01070   // XXX we assume issuer org is always criterion 1
01071   return CmpBy(cache, a, b, sort_IssuerOrg, sort_Org, sort_Token);
01072 }
01073 
01074 PRInt32
01075 nsCertTree::CmpWebSiteCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
01076 {
01077   // XXX we assume issuer org is always criterion 1
01078   return CmpBy(cache, a, b, sort_IssuerOrg, sort_CommonName, sort_None);
01079 }
01080 
01081 PRInt32
01082 nsCertTree::CmpUserCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
01083 {
01084   // XXX we assume issuer org is always criterion 1
01085   return CmpBy(cache, a, b, sort_IssuerOrg, sort_Token, sort_IssuedDateDescending);
01086 }
01087 
01088 PRInt32
01089 nsCertTree::CmpEmailCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
01090 {
01091   // XXX we assume issuer org is always criterion 1
01092   return CmpBy(cache, a, b, sort_IssuerOrg, sort_Email, sort_CommonName);
01093 }
01094