1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsCertTree.h"
7 #include "ScopedNSSTypes.h"
8 #include "mozilla/Logging.h"
9 #include "mozilla/Maybe.h"
10 #include "mozilla/intl/AppDateTimeFormat.h"
12 #include "nsArrayUtils.h"
13 #include "nsHashKeys.h"
14 #include "nsISupportsPrimitives.h"
15 #include "nsIX509CertDB.h"
16 #include "nsIX509Cert.h"
17 #include "nsIX509CertValidity.h"
18 #include "nsNSSCertHelper.h"
19 #include "nsNSSCertificate.h"
20 #include "nsComponentManagerUtils.h"
21 #include "nsNSSCertificateDB.h"
22 #include "nsNSSHelper.h"
23 #include "nsReadableUtils.h"
24 #include "nsTHashtable.h"
25 #include "nsUnicharUtils.h"
26 #include "nsXPCOMCID.h"
28 #include "nsTreeColumns.h"
29 #include "mozpkix/pkixtypes.h"
31 using namespace mozilla
;
33 extern LazyLogModule gPIPNSSLog
;
37 // structure used to hold map of tree. Each thread (an organization
38 // field from a cert) has an element in the array. The numChildren field
39 // stores the number of certs corresponding to that thread.
40 struct treeArrayElStr
{
41 nsString orgName
; /* heading for thread */
42 bool open
; /* toggle open state for thread */
43 int32_t certIndex
; /* index into cert array for 1st cert */
44 int32_t numChildren
; /* number of chidren (certs) for thread */
47 CompareCacheHashEntryPtr::CompareCacheHashEntryPtr() {
48 entry
= new CompareCacheHashEntry
;
51 CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr() { delete entry
; }
53 CompareCacheHashEntry::CompareCacheHashEntry() : key(nullptr), mCritInit() {
54 for (int i
= 0; i
< max_criterions
; ++i
) {
56 mCrit
[i
].SetIsVoid(true);
60 static bool CompareCacheMatchEntry(const PLDHashEntryHdr
* hdr
,
62 const CompareCacheHashEntryPtr
* entryPtr
=
63 static_cast<const CompareCacheHashEntryPtr
*>(hdr
);
64 return entryPtr
->entry
->key
== key
;
67 static void CompareCacheInitEntry(PLDHashEntryHdr
* hdr
, const void* key
) {
68 new (hdr
) CompareCacheHashEntryPtr();
69 CompareCacheHashEntryPtr
* entryPtr
=
70 static_cast<CompareCacheHashEntryPtr
*>(hdr
);
71 entryPtr
->entry
->key
= (void*)key
;
74 static void CompareCacheClearEntry(PLDHashTable
* table
, PLDHashEntryHdr
* hdr
) {
75 CompareCacheHashEntryPtr
* entryPtr
=
76 static_cast<CompareCacheHashEntryPtr
*>(hdr
);
77 entryPtr
->~CompareCacheHashEntryPtr();
80 static const PLDHashTableOps gMapOps
= {
81 PLDHashTable::HashVoidPtrKeyStub
, CompareCacheMatchEntry
,
82 PLDHashTable::MoveEntryStub
, CompareCacheClearEntry
, CompareCacheInitEntry
};
84 NS_IMPL_ISUPPORTS(nsCertTreeDispInfo
, nsICertTreeItem
)
86 nsCertTreeDispInfo::~nsCertTreeDispInfo() = default;
89 nsCertTreeDispInfo::GetCert(nsIX509Cert
** aCert
) {
91 nsCOMPtr
<nsIX509Cert
> cert
= mCert
;
96 NS_IMPL_ISUPPORTS(nsCertTree
, nsICertTree
, nsITreeView
)
98 nsCertTree::nsCertTree()
99 : mTreeArray(nullptr),
102 mCompareCache(&gMapOps
, sizeof(CompareCacheHashEntryPtr
),
103 kInitialCacheLength
) {
107 void nsCertTree::ClearCompareHash() {
108 mCompareCache
.ClearAndPrepareForLength(kInitialCacheLength
);
111 nsCertTree::~nsCertTree() { delete[] mTreeArray
; }
113 void nsCertTree::FreeCertArray() { mDispInfo
.Clear(); }
115 CompareCacheHashEntry
* nsCertTree::getCacheEntry(void* cache
, void* aCert
) {
116 PLDHashTable
& aCompareCache
= *static_cast<PLDHashTable
*>(cache
);
117 auto entryPtr
= static_cast<CompareCacheHashEntryPtr
*>(
118 aCompareCache
.Add(aCert
, fallible
));
119 return entryPtr
? entryPtr
->entry
: nullptr;
122 void nsCertTree::RemoveCacheEntry(void* key
) { mCompareCache
.Remove(key
); }
124 // CountOrganizations
126 // Count the number of different organizations encountered in the cert
128 int32_t nsCertTree::CountOrganizations() {
129 uint32_t i
, certCount
;
130 certCount
= mDispInfo
.Length();
131 if (certCount
== 0) return 0;
132 nsCOMPtr
<nsIX509Cert
> orgCert
= mDispInfo
.ElementAt(0)->mCert
;
133 nsCOMPtr
<nsIX509Cert
> nextCert
= nullptr;
134 int32_t orgCount
= 1;
135 for (i
= 1; i
< certCount
; i
++) {
136 nextCert
= mDispInfo
.SafeElementAt(i
, nullptr)->mCert
;
137 // XXX we assume issuer org is always criterion 1
138 if (CmpBy(&mCompareCache
, orgCert
, nextCert
, sort_IssuerOrg
, sort_None
,
147 // GetThreadDescAtIndex
149 // If the row at index is an organization thread, return the collection
150 // associated with that thread. Otherwise, return null.
151 treeArrayEl
* nsCertTree::GetThreadDescAtIndex(int32_t index
) {
153 if (index
< 0) return nullptr;
154 for (i
= 0; i
< mNumOrgs
; i
++) {
156 return &mTreeArray
[i
];
158 if (mTreeArray
[i
].open
) {
159 idx
+= mTreeArray
[i
].numChildren
;
162 if (idx
> index
) break;
169 // If the row at index is a cert, return that cert. Otherwise, return null.
170 already_AddRefed
<nsIX509Cert
> nsCertTree::GetCertAtIndex(
171 int32_t index
, int32_t* outAbsoluteCertOffset
) {
172 RefPtr
<nsCertTreeDispInfo
> certdi(
173 GetDispInfoAtIndex(index
, outAbsoluteCertOffset
));
174 if (!certdi
) return nullptr;
176 nsCOMPtr
<nsIX509Cert
> ret
= certdi
->mCert
;
180 // If the row at index is a cert, return that cert. Otherwise, return null.
181 already_AddRefed
<nsCertTreeDispInfo
> nsCertTree::GetDispInfoAtIndex(
182 int32_t index
, int32_t* outAbsoluteCertOffset
) {
183 int i
, idx
= 0, cIndex
= 0, nc
;
184 if (index
< 0) return nullptr;
185 // Loop over the threads
186 for (i
= 0; i
< mNumOrgs
; i
++) {
187 if (index
== idx
) return nullptr; // index is for thread
188 idx
++; // get past the thread
189 nc
= (mTreeArray
[i
].open
) ? mTreeArray
[i
].numChildren
: 0;
190 if (index
< idx
+ nc
) { // cert is within range of this thread
191 int32_t certIndex
= cIndex
+ index
- idx
;
192 if (outAbsoluteCertOffset
) *outAbsoluteCertOffset
= certIndex
;
193 RefPtr
<nsCertTreeDispInfo
> certdi(
194 mDispInfo
.SafeElementAt(certIndex
, nullptr));
196 return certdi
.forget();
200 if (mTreeArray
[i
].open
) idx
+= mTreeArray
[i
].numChildren
;
201 cIndex
+= mTreeArray
[i
].numChildren
;
202 if (idx
> index
) break;
207 nsCertTree::nsCertCompareFunc
nsCertTree::GetCompareFuncFromCertType(
210 case nsIX509Cert::ANY_CERT
:
211 case nsIX509Cert::USER_CERT
:
213 case nsIX509Cert::EMAIL_CERT
:
215 case nsIX509Cert::CA_CERT
:
221 nsresult
nsCertTree::GetCertsByTypeFromCertList(
222 const nsTArray
<RefPtr
<nsIX509Cert
>>& aCertList
, uint32_t aWantedType
,
223 nsCertCompareFunc aCertCmpFn
, void* aCertCmpFnArg
) {
224 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("GetCertsByTypeFromCertList"));
226 nsTHashtable
<nsCStringHashKey
> allHostPortOverrideKeys
;
228 if (aWantedType
== nsIX509Cert::SERVER_CERT
) {
229 return NS_ERROR_INVALID_ARG
;
233 for (const auto& cert
: aCertList
) {
234 bool wantThisCert
= (aWantedType
== nsIX509Cert::ANY_CERT
);
237 uint32_t thisCertType
;
238 nsresult rv
= cert
->GetCertType(&thisCertType
);
242 if (thisCertType
== aWantedType
) {
248 int InsertPosition
= 0;
249 for (; InsertPosition
< count
; ++InsertPosition
) {
250 nsCOMPtr
<nsIX509Cert
> otherCert
= nullptr;
251 RefPtr
<nsCertTreeDispInfo
> elem(
252 mDispInfo
.SafeElementAt(InsertPosition
, nullptr));
254 otherCert
= elem
->mCert
;
256 if ((*aCertCmpFn
)(aCertCmpFnArg
, cert
, otherCert
) < 0) {
260 nsCertTreeDispInfo
* certdi
= new nsCertTreeDispInfo(cert
);
261 mDispInfo
.InsertElementAt(InsertPosition
, certdi
);
272 // Load all of the certificates in the DB for this type. Sort them
273 // by token, organization, then common name.
275 nsCertTree::LoadCertsFromCache(const nsTArray
<RefPtr
<nsIX509Cert
>>& aCache
,
280 mTreeArray
= nullptr;
285 nsresult rv
= GetCertsByTypeFromCertList(
286 aCache
, aType
, GetCompareFuncFromCertType(aType
), &mCompareCache
);
290 return UpdateUIContents();
293 nsresult
nsCertTree::UpdateUIContents() {
294 uint32_t count
= mDispInfo
.Length();
295 mNumOrgs
= CountOrganizations();
296 mTreeArray
= new treeArrayEl
[mNumOrgs
];
298 mCellText
= nsArrayBase::Create();
302 nsCOMPtr
<nsIX509Cert
> orgCert
= mDispInfo
.ElementAt(j
)->mCert
;
303 for (int32_t i
= 0; i
< mNumOrgs
; i
++) {
304 nsString
& orgNameRef
= mTreeArray
[i
].orgName
;
306 GetPIPNSSBundleString("CertOrgUnknown", orgNameRef
);
308 orgCert
->GetIssuerOrganization(orgNameRef
);
309 if (orgNameRef
.IsEmpty()) orgCert
->GetCommonName(orgNameRef
);
311 mTreeArray
[i
].open
= true;
312 mTreeArray
[i
].certIndex
= j
;
313 mTreeArray
[i
].numChildren
= 1;
314 if (++j
>= count
) break;
315 nsCOMPtr
<nsIX509Cert
> nextCert
=
316 mDispInfo
.SafeElementAt(j
, nullptr)->mCert
;
317 while (0 == CmpBy(&mCompareCache
, orgCert
, nextCert
, sort_IssuerOrg
,
318 sort_None
, sort_None
)) {
319 mTreeArray
[i
].numChildren
++;
320 if (++j
>= count
) break;
321 nextCert
= mDispInfo
.SafeElementAt(j
, nullptr)->mCert
;
327 mTree
->BeginUpdateBatch();
328 mTree
->RowCountChanged(0, -mNumRows
);
330 mNumRows
= count
+ mNumOrgs
;
331 if (mTree
) mTree
->EndUpdateBatch();
336 nsCertTree::DeleteEntryObject(uint32_t index
) {
338 return NS_ERROR_FAILURE
;
341 nsCOMPtr
<nsIX509CertDB
> certdb
=
342 do_GetService("@mozilla.org/security/x509certdb;1");
344 return NS_ERROR_FAILURE
;
348 uint32_t idx
= 0, cIndex
= 0, nc
;
349 // Loop over the threads
350 for (i
= 0; i
< mNumOrgs
; i
++) {
351 if (index
== idx
) return NS_OK
; // index is for thread
352 idx
++; // get past the thread
353 nc
= (mTreeArray
[i
].open
) ? mTreeArray
[i
].numChildren
: 0;
354 if (index
< idx
+ nc
) { // cert is within range of this thread
355 int32_t certIndex
= cIndex
+ index
- idx
;
357 RefPtr
<nsCertTreeDispInfo
> certdi(
358 mDispInfo
.SafeElementAt(certIndex
, nullptr));
360 nsCOMPtr
<nsIX509Cert
> cert
= certdi
->mCert
;
361 RemoveCacheEntry(cert
);
362 certdb
->DeleteCertificate(cert
);
365 mDispInfo
.RemoveElementAt(certIndex
);
368 mTreeArray
= nullptr;
369 return UpdateUIContents();
371 if (mTreeArray
[i
].open
) idx
+= mTreeArray
[i
].numChildren
;
372 cIndex
+= mTreeArray
[i
].numChildren
;
373 if (idx
> index
) break;
375 return NS_ERROR_FAILURE
;
378 //////////////////////////////////////////////////////////////////////////////
380 // Begin nsITreeView methods
382 /////////////////////////////////////////////////////////////////////////////
385 nsCertTree::GetCert(uint32_t aIndex
, nsIX509Cert
** _cert
) {
386 NS_ENSURE_ARG(_cert
);
387 *_cert
= GetCertAtIndex(aIndex
).take();
392 nsCertTree::GetTreeItem(uint32_t aIndex
, nsICertTreeItem
** _treeitem
) {
393 NS_ENSURE_ARG(_treeitem
);
395 RefPtr
<nsCertTreeDispInfo
> certdi(GetDispInfoAtIndex(aIndex
));
396 if (!certdi
) return NS_ERROR_FAILURE
;
399 NS_IF_ADDREF(*_treeitem
);
404 nsCertTree::GetRowCount(int32_t* aRowCount
) {
405 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
407 for (int32_t i
= 0; i
< mNumOrgs
; i
++) {
408 if (mTreeArray
[i
].open
) {
409 count
+= mTreeArray
[i
].numChildren
;
418 nsCertTree::GetSelection(nsITreeSelection
** aSelection
) {
419 *aSelection
= mSelection
;
420 NS_IF_ADDREF(*aSelection
);
425 nsCertTree::SetSelection(nsITreeSelection
* aSelection
) {
426 mSelection
= aSelection
;
431 nsCertTree::GetRowProperties(int32_t index
, nsAString
& aProps
) { return NS_OK
; }
434 nsCertTree::GetCellProperties(int32_t row
, nsTreeColumn
* col
,
440 nsCertTree::GetColumnProperties(nsTreeColumn
* col
, nsAString
& aProps
) {
444 nsCertTree::IsContainer(int32_t index
, bool* _retval
) {
445 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
446 treeArrayEl
* el
= GetThreadDescAtIndex(index
);
456 nsCertTree::IsContainerOpen(int32_t index
, bool* _retval
) {
457 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
458 treeArrayEl
* el
= GetThreadDescAtIndex(index
);
459 if (el
&& el
->open
) {
468 nsCertTree::IsContainerEmpty(int32_t index
, bool* _retval
) {
469 *_retval
= !mTreeArray
;
474 nsCertTree::IsSeparator(int32_t index
, bool* _retval
) {
480 nsCertTree::GetParentIndex(int32_t rowIndex
, int32_t* _retval
) {
481 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
483 for (i
= 0; i
< mNumOrgs
&& idx
< rowIndex
; i
++, idx
++) {
484 if (mTreeArray
[i
].open
) {
485 if (rowIndex
<= idx
+ mTreeArray
[i
].numChildren
) {
489 idx
+= mTreeArray
[i
].numChildren
;
497 nsCertTree::HasNextSibling(int32_t rowIndex
, int32_t afterIndex
,
499 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
502 for (i
= 0; i
< mNumOrgs
&& idx
<= rowIndex
; i
++, idx
++) {
503 if (mTreeArray
[i
].open
) {
504 idx
+= mTreeArray
[i
].numChildren
;
505 if (afterIndex
<= idx
) {
506 *_retval
= afterIndex
< idx
;
516 nsCertTree::GetLevel(int32_t index
, int32_t* _retval
) {
517 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
518 treeArrayEl
* el
= GetThreadDescAtIndex(index
);
528 nsCertTree::GetImageSrc(int32_t row
, nsTreeColumn
* col
, nsAString
& _retval
) {
534 nsCertTree::GetCellValue(int32_t row
, nsTreeColumn
* col
, nsAString
& _retval
) {
539 static void PRTimeToLocalDateString(PRTime time
, nsAString
& result
) {
540 PRExplodedTime explodedTime
;
541 PR_ExplodeTime(time
, PR_LocalTimeParameters
, &explodedTime
);
542 intl::DateTimeFormat::StyleBag style
;
543 style
.date
= Some(intl::DateTimeFormat::Style::Long
);
544 style
.time
= Nothing();
545 Unused
<< intl::AppDateTimeFormat::Format(style
, &explodedTime
, result
);
549 nsCertTree::GetCellText(int32_t row
, nsTreeColumn
* col
, nsAString
& _retval
) {
550 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
555 const nsAString
& colID
= col
->GetId();
557 treeArrayEl
* el
= GetThreadDescAtIndex(row
);
559 if (u
"certcol"_ns
.Equals(colID
))
560 _retval
.Assign(el
->orgName
);
566 int32_t absoluteCertOffset
;
567 RefPtr
<nsCertTreeDispInfo
> certdi(
568 GetDispInfoAtIndex(row
, &absoluteCertOffset
));
569 if (!certdi
) return NS_ERROR_FAILURE
;
571 nsCOMPtr
<nsIX509Cert
> cert
= certdi
->mCert
;
573 int32_t colIndex
= col
->Index();
574 uint32_t arrayIndex
= absoluteCertOffset
+ colIndex
* (mNumRows
- mNumOrgs
);
575 uint32_t arrayLength
= 0;
577 mCellText
->GetLength(&arrayLength
);
579 if (arrayIndex
< arrayLength
) {
580 nsCOMPtr
<nsISupportsString
> myString(
581 do_QueryElementAt(mCellText
, arrayIndex
));
583 myString
->GetData(_retval
);
588 if (u
"certcol"_ns
.Equals(colID
)) {
590 rv
= GetPIPNSSBundleString("CertNotStored", _retval
);
592 rv
= cert
->GetDisplayName(_retval
);
594 } else if (u
"tokencol"_ns
.Equals(colID
) && cert
) {
595 rv
= cert
->GetTokenName(_retval
);
596 } else if (u
"emailcol"_ns
.Equals(colID
) && cert
) {
597 rv
= cert
->GetEmailAddress(_retval
);
598 } else if (u
"issuedcol"_ns
.Equals(colID
) && cert
) {
599 nsCOMPtr
<nsIX509CertValidity
> validity
;
601 rv
= cert
->GetValidity(getter_AddRefs(validity
));
602 if (NS_SUCCEEDED(rv
)) {
604 rv
= validity
->GetNotBefore(¬Before
);
605 if (NS_SUCCEEDED(rv
)) {
606 PRTimeToLocalDateString(notBefore
, _retval
);
609 } else if (u
"expiredcol"_ns
.Equals(colID
) && cert
) {
610 nsCOMPtr
<nsIX509CertValidity
> validity
;
612 rv
= cert
->GetValidity(getter_AddRefs(validity
));
613 if (NS_SUCCEEDED(rv
)) {
615 rv
= validity
->GetNotAfter(¬After
);
616 if (NS_SUCCEEDED(rv
)) {
617 PRTimeToLocalDateString(notAfter
, _retval
);
620 } else if (u
"serialnumcol"_ns
.Equals(colID
) && cert
) {
621 rv
= cert
->GetSerialNumber(_retval
);
623 return NS_ERROR_FAILURE
;
626 nsCOMPtr
<nsISupportsString
> text(
627 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
));
628 NS_ENSURE_SUCCESS(rv
, rv
);
629 text
->SetData(_retval
);
630 mCellText
->ReplaceElementAt(text
, arrayIndex
);
636 nsCertTree::SetTree(mozilla::dom::XULTreeElement
* tree
) {
642 nsCertTree::ToggleOpenState(int32_t index
) {
643 if (!mTreeArray
) return NS_ERROR_NOT_INITIALIZED
;
644 treeArrayEl
* el
= GetThreadDescAtIndex(index
);
646 el
->open
= !el
->open
;
647 int32_t newChildren
= (el
->open
) ? el
->numChildren
: -el
->numChildren
;
649 mTree
->RowCountChanged(index
+ 1, newChildren
);
650 mTree
->InvalidateRow(index
);
657 nsCertTree::CycleHeader(nsTreeColumn
* col
) { return NS_OK
; }
660 nsCertTree::SelectionChangedXPCOM() { return NS_ERROR_NOT_IMPLEMENTED
; }
663 nsCertTree::CycleCell(int32_t row
, nsTreeColumn
* col
) { return NS_OK
; }
666 nsCertTree::IsEditable(int32_t row
, nsTreeColumn
* col
, bool* _retval
) {
672 nsCertTree::SetCellValue(int32_t row
, nsTreeColumn
* col
,
673 const nsAString
& value
) {
678 nsCertTree::SetCellText(int32_t row
, nsTreeColumn
* col
,
679 const nsAString
& value
) {
686 NS_IMETHODIMP
nsCertTree::CanDrop(int32_t index
, int32_t orientation
,
687 mozilla::dom::DataTransfer
* aDataTransfer
,
689 NS_ENSURE_ARG_POINTER(_retval
);
698 NS_IMETHODIMP
nsCertTree::Drop(int32_t row
, int32_t orient
,
699 mozilla::dom::DataTransfer
* aDataTransfer
) {
708 NS_IMETHODIMP
nsCertTree::IsSorted(bool* _retval
) {
713 #define RETURN_NOTHING
715 void nsCertTree::CmpInitCriterion(nsIX509Cert
* cert
,
716 CompareCacheHashEntry
* entry
,
717 sortCriterion crit
, int32_t level
) {
718 NS_ENSURE_TRUE(cert
&& entry
, RETURN_NOTHING
);
720 entry
->mCritInit
[level
] = true;
721 nsString
& str
= entry
->mCrit
[level
];
725 cert
->GetIssuerOrganization(str
);
726 if (str
.IsEmpty()) cert
->GetCommonName(str
);
729 cert
->GetOrganization(str
);
732 cert
->GetTokenName(str
);
734 case sort_CommonName
:
735 cert
->GetCommonName(str
);
737 case sort_IssuedDateDescending
: {
739 nsCOMPtr
<nsIX509CertValidity
> validity
;
742 rv
= cert
->GetValidity(getter_AddRefs(validity
));
743 if (NS_SUCCEEDED(rv
)) {
744 rv
= validity
->GetNotBefore(¬Before
);
747 if (NS_SUCCEEDED(rv
)) {
748 PRExplodedTime explodedTime
;
749 PR_ExplodeTime(notBefore
, PR_GMTParameters
, &explodedTime
);
750 char datebuf
[20]; // 4 + 2 + 2 + 2 + 2 + 2 + 1 = 15
751 if (0 != PR_FormatTime(datebuf
, sizeof(datebuf
), "%Y%m%d%H%M%S",
753 str
= NS_ConvertASCIItoUTF16(nsDependentCString(datebuf
));
758 cert
->GetEmailAddress(str
);
766 int32_t nsCertTree::CmpByCrit(nsIX509Cert
* a
, CompareCacheHashEntry
* ace
,
767 nsIX509Cert
* b
, CompareCacheHashEntry
* bce
,
768 sortCriterion crit
, int32_t level
) {
769 NS_ENSURE_TRUE(a
&& ace
&& b
&& bce
, 0);
771 if (!ace
->mCritInit
[level
]) {
772 CmpInitCriterion(a
, ace
, crit
, level
);
775 if (!bce
->mCritInit
[level
]) {
776 CmpInitCriterion(b
, bce
, crit
, level
);
779 nsString
& str_a
= ace
->mCrit
[level
];
780 nsString
& str_b
= bce
->mCrit
[level
];
783 if (!str_a
.IsVoid() && !str_b
.IsVoid())
784 result
= Compare(str_a
, str_b
, nsCaseInsensitiveStringComparator
);
786 result
= str_a
.IsVoid() ? (str_b
.IsVoid() ? 0 : -1) : 1;
788 if (sort_IssuedDateDescending
== crit
) result
*= -1; // reverse compare order
793 int32_t nsCertTree::CmpBy(void* cache
, nsIX509Cert
* a
, nsIX509Cert
* b
,
794 sortCriterion c0
, sortCriterion c1
,
796 // This will be called when comparing items for display sorting.
797 // Some items might have no cert associated, so either a or b is null.
798 // We want all those orphans show at the top of the list,
799 // so we treat a null cert as "smaller" by returning -1.
800 // We don't try to sort within the group of no-cert entries,
801 // so we treat them as equal wrt sort order.
803 if (!a
&& !b
) return 0;
809 NS_ENSURE_TRUE(cache
&& a
&& b
, 0);
811 CompareCacheHashEntry
* ace
= getCacheEntry(cache
, a
);
812 CompareCacheHashEntry
* bce
= getCacheEntry(cache
, b
);
815 cmp
= CmpByCrit(a
, ace
, b
, bce
, c0
, 0);
816 if (cmp
!= 0) return cmp
;
818 if (c1
!= sort_None
) {
819 cmp
= CmpByCrit(a
, ace
, b
, bce
, c1
, 1);
820 if (cmp
!= 0) return cmp
;
822 if (c2
!= sort_None
) {
823 return CmpByCrit(a
, ace
, b
, bce
, c2
, 2);
830 int32_t nsCertTree::CmpCACert(void* cache
, nsIX509Cert
* a
, nsIX509Cert
* b
) {
831 // XXX we assume issuer org is always criterion 1
832 return CmpBy(cache
, a
, b
, sort_IssuerOrg
, sort_Org
, sort_Token
);
835 int32_t nsCertTree::CmpUserCert(void* cache
, nsIX509Cert
* a
, nsIX509Cert
* b
) {
836 // XXX we assume issuer org is always criterion 1
837 return CmpBy(cache
, a
, b
, sort_IssuerOrg
, sort_Token
,
838 sort_IssuedDateDescending
);
841 int32_t nsCertTree::CmpEmailCert(void* cache
, nsIX509Cert
* a
, nsIX509Cert
* b
) {
842 // XXX we assume issuer org is always criterion 1
843 return CmpBy(cache
, a
, b
, sort_IssuerOrg
, sort_Email
, sort_CommonName
);