nsCertTree.cpp (23759B)
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/. */ 4 5 #include "nsCertTree.h" 6 7 #include "ScopedNSSTypes.h" 8 #include "mozilla/Logging.h" 9 #include "mozilla/Maybe.h" 10 #include "mozilla/intl/AppDateTimeFormat.h" 11 #include "nsArray.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" 27 #include "nsString.h" 28 #include "nsTreeColumns.h" 29 #include "mozpkix/pkixtypes.h" 30 31 using namespace mozilla; 32 33 extern LazyLogModule gPIPNSSLog; 34 35 // treeArrayElStr 36 // 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 */ 45 }; 46 47 CompareCacheHashEntryPtr::CompareCacheHashEntryPtr() { 48 entry = new CompareCacheHashEntry; 49 } 50 51 CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr() { delete entry; } 52 53 CompareCacheHashEntry::CompareCacheHashEntry() : key(nullptr), mCritInit() { 54 for (int i = 0; i < max_criterions; ++i) { 55 mCritInit[i] = false; 56 mCrit[i].SetIsVoid(true); 57 } 58 } 59 60 static bool CompareCacheMatchEntry(const PLDHashEntryHdr* hdr, 61 const void* key) { 62 const CompareCacheHashEntryPtr* entryPtr = 63 static_cast<const CompareCacheHashEntryPtr*>(hdr); 64 return entryPtr->entry->key == key; 65 } 66 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; 72 } 73 74 static void CompareCacheClearEntry(PLDHashTable* table, PLDHashEntryHdr* hdr) { 75 CompareCacheHashEntryPtr* entryPtr = 76 static_cast<CompareCacheHashEntryPtr*>(hdr); 77 entryPtr->~CompareCacheHashEntryPtr(); 78 } 79 80 static const PLDHashTableOps gMapOps = { 81 PLDHashTable::HashVoidPtrKeyStub, CompareCacheMatchEntry, 82 PLDHashTable::MoveEntryStub, CompareCacheClearEntry, CompareCacheInitEntry}; 83 84 NS_IMPL_ISUPPORTS(nsCertTreeDispInfo, nsICertTreeItem) 85 86 nsCertTreeDispInfo::~nsCertTreeDispInfo() = default; 87 88 NS_IMETHODIMP 89 nsCertTreeDispInfo::GetCert(nsIX509Cert** aCert) { 90 NS_ENSURE_ARG(aCert); 91 nsCOMPtr<nsIX509Cert> cert = mCert; 92 cert.forget(aCert); 93 return NS_OK; 94 } 95 96 NS_IMPL_ISUPPORTS(nsCertTree, nsICertTree, nsITreeView) 97 98 nsCertTree::nsCertTree() 99 : mTreeArray(nullptr), 100 mNumOrgs(0), 101 mNumRows(0), 102 mCompareCache(&gMapOps, sizeof(CompareCacheHashEntryPtr), 103 kInitialCacheLength) { 104 mCellText = nullptr; 105 } 106 107 void nsCertTree::ClearCompareHash() { 108 mCompareCache.ClearAndPrepareForLength(kInitialCacheLength); 109 } 110 111 nsCertTree::~nsCertTree() { delete[] mTreeArray; } 112 113 void nsCertTree::FreeCertArray() { mDispInfo.Clear(); } 114 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; 120 } 121 122 void nsCertTree::RemoveCacheEntry(void* key) { mCompareCache.Remove(key); } 123 124 // CountOrganizations 125 // 126 // Count the number of different organizations encountered in the cert 127 // list. 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, 139 sort_None) != 0) { 140 orgCert = nextCert; 141 orgCount++; 142 } 143 } 144 return orgCount; 145 } 146 147 // GetThreadDescAtIndex 148 // 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) { 152 int i, idx = 0; 153 if (index < 0) return nullptr; 154 for (i = 0; i < mNumOrgs; i++) { 155 if (index == idx) { 156 return &mTreeArray[i]; 157 } 158 if (mTreeArray[i].open) { 159 idx += mTreeArray[i].numChildren; 160 } 161 idx++; 162 if (idx > index) break; 163 } 164 return nullptr; 165 } 166 167 // GetCertAtIndex 168 // 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; 175 176 nsCOMPtr<nsIX509Cert> ret = certdi->mCert; 177 return ret.forget(); 178 } 179 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)); 195 if (certdi) { 196 return certdi.forget(); 197 } 198 break; 199 } 200 if (mTreeArray[i].open) idx += mTreeArray[i].numChildren; 201 cIndex += mTreeArray[i].numChildren; 202 if (idx > index) break; 203 } 204 return nullptr; 205 } 206 207 nsCertTree::nsCertCompareFunc nsCertTree::GetCompareFuncFromCertType( 208 uint32_t aType) { 209 switch (aType) { 210 case nsIX509Cert::ANY_CERT: 211 case nsIX509Cert::USER_CERT: 212 return CmpUserCert; 213 case nsIX509Cert::EMAIL_CERT: 214 return CmpEmailCert; 215 case nsIX509Cert::CA_CERT: 216 default: 217 return CmpCACert; 218 } 219 } 220 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")); 225 226 nsTHashtable<nsCStringHashKey> allHostPortOverrideKeys; 227 228 if (aWantedType == nsIX509Cert::SERVER_CERT) { 229 return NS_ERROR_INVALID_ARG; 230 } 231 232 int count = 0; 233 for (const auto& cert : aCertList) { 234 bool wantThisCert = (aWantedType == nsIX509Cert::ANY_CERT); 235 236 if (!wantThisCert) { 237 uint32_t thisCertType; 238 nsresult rv = cert->GetCertType(&thisCertType); 239 if (NS_FAILED(rv)) { 240 return rv; 241 } 242 if (thisCertType == aWantedType) { 243 wantThisCert = true; 244 } 245 } 246 247 if (wantThisCert) { 248 int InsertPosition = 0; 249 for (; InsertPosition < count; ++InsertPosition) { 250 nsCOMPtr<nsIX509Cert> otherCert = nullptr; 251 RefPtr<nsCertTreeDispInfo> elem( 252 mDispInfo.SafeElementAt(InsertPosition, nullptr)); 253 if (elem) { 254 otherCert = elem->mCert; 255 } 256 if ((*aCertCmpFn)(aCertCmpFnArg, cert, otherCert) < 0) { 257 break; 258 } 259 } 260 nsCertTreeDispInfo* certdi = new nsCertTreeDispInfo(cert); 261 mDispInfo.InsertElementAt(InsertPosition, certdi); 262 ++count; 263 ++InsertPosition; 264 } 265 } 266 267 return NS_OK; 268 } 269 270 // LoadCerts 271 // 272 // Load all of the certificates in the DB for this type. Sort them 273 // by token, organization, then common name. 274 NS_IMETHODIMP 275 nsCertTree::LoadCertsFromCache(const nsTArray<RefPtr<nsIX509Cert>>& aCache, 276 uint32_t aType) { 277 if (mTreeArray) { 278 FreeCertArray(); 279 delete[] mTreeArray; 280 mTreeArray = nullptr; 281 mNumRows = 0; 282 } 283 ClearCompareHash(); 284 285 nsresult rv = GetCertsByTypeFromCertList( 286 aCache, aType, GetCompareFuncFromCertType(aType), &mCompareCache); 287 if (NS_FAILED(rv)) { 288 return rv; 289 } 290 return UpdateUIContents(); 291 } 292 293 nsresult nsCertTree::UpdateUIContents() { 294 uint32_t count = mDispInfo.Length(); 295 mNumOrgs = CountOrganizations(); 296 mTreeArray = new treeArrayEl[mNumOrgs]; 297 298 mCellText = nsArrayBase::Create(); 299 300 if (count) { 301 uint32_t j = 0; 302 nsCOMPtr<nsIX509Cert> orgCert = mDispInfo.ElementAt(j)->mCert; 303 for (int32_t i = 0; i < mNumOrgs; i++) { 304 nsString& orgNameRef = mTreeArray[i].orgName; 305 if (!orgCert) { 306 GetPIPNSSBundleString("CertOrgUnknown", orgNameRef); 307 } else { 308 orgCert->GetIssuerOrganization(orgNameRef); 309 if (orgNameRef.IsEmpty()) orgCert->GetCommonName(orgNameRef); 310 } 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; 322 } 323 orgCert = nextCert; 324 } 325 } 326 if (mTree) { 327 mTree->BeginUpdateBatch(); 328 mTree->RowCountChanged(0, -mNumRows); 329 } 330 mNumRows = count + mNumOrgs; 331 if (mTree) mTree->EndUpdateBatch(); 332 return NS_OK; 333 } 334 335 NS_IMETHODIMP 336 nsCertTree::DeleteEntryObject(uint32_t index) { 337 if (!mTreeArray) { 338 return NS_ERROR_FAILURE; 339 } 340 341 nsCOMPtr<nsIX509CertDB> certdb = 342 do_GetService("@mozilla.org/security/x509certdb;1"); 343 if (!certdb) { 344 return NS_ERROR_FAILURE; 345 } 346 347 int i; 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; 356 357 RefPtr<nsCertTreeDispInfo> certdi( 358 mDispInfo.SafeElementAt(certIndex, nullptr)); 359 if (certdi) { 360 nsCOMPtr<nsIX509Cert> cert = certdi->mCert; 361 RemoveCacheEntry(cert); 362 certdb->DeleteCertificate(cert); 363 } 364 365 mDispInfo.RemoveElementAt(certIndex); 366 367 delete[] mTreeArray; 368 mTreeArray = nullptr; 369 return UpdateUIContents(); 370 } 371 if (mTreeArray[i].open) idx += mTreeArray[i].numChildren; 372 cIndex += mTreeArray[i].numChildren; 373 if (idx > index) break; 374 } 375 return NS_ERROR_FAILURE; 376 } 377 378 ////////////////////////////////////////////////////////////////////////////// 379 // 380 // Begin nsITreeView methods 381 // 382 ///////////////////////////////////////////////////////////////////////////// 383 384 NS_IMETHODIMP 385 nsCertTree::GetCert(uint32_t aIndex, nsIX509Cert** _cert) { 386 NS_ENSURE_ARG(_cert); 387 *_cert = GetCertAtIndex(aIndex).take(); 388 return NS_OK; 389 } 390 391 NS_IMETHODIMP 392 nsCertTree::GetTreeItem(uint32_t aIndex, nsICertTreeItem** _treeitem) { 393 NS_ENSURE_ARG(_treeitem); 394 395 RefPtr<nsCertTreeDispInfo> certdi(GetDispInfoAtIndex(aIndex)); 396 if (!certdi) return NS_ERROR_FAILURE; 397 398 *_treeitem = certdi; 399 NS_IF_ADDREF(*_treeitem); 400 return NS_OK; 401 } 402 403 NS_IMETHODIMP 404 nsCertTree::GetRowCount(int32_t* aRowCount) { 405 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 406 uint32_t count = 0; 407 for (int32_t i = 0; i < mNumOrgs; i++) { 408 if (mTreeArray[i].open) { 409 count += mTreeArray[i].numChildren; 410 } 411 count++; 412 } 413 *aRowCount = count; 414 return NS_OK; 415 } 416 417 NS_IMETHODIMP 418 nsCertTree::GetSelection(nsITreeSelection** aSelection) { 419 *aSelection = mSelection; 420 NS_IF_ADDREF(*aSelection); 421 return NS_OK; 422 } 423 424 NS_IMETHODIMP 425 nsCertTree::SetSelection(nsITreeSelection* aSelection) { 426 mSelection = aSelection; 427 return NS_OK; 428 } 429 430 NS_IMETHODIMP 431 nsCertTree::GetRowProperties(int32_t index, nsAString& aProps) { return NS_OK; } 432 433 NS_IMETHODIMP 434 nsCertTree::GetCellProperties(int32_t row, nsTreeColumn* col, 435 nsAString& aProps) { 436 return NS_OK; 437 } 438 439 NS_IMETHODIMP 440 nsCertTree::GetColumnProperties(nsTreeColumn* col, nsAString& aProps) { 441 return NS_OK; 442 } 443 NS_IMETHODIMP 444 nsCertTree::IsContainer(int32_t index, bool* _retval) { 445 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 446 treeArrayEl* el = GetThreadDescAtIndex(index); 447 if (el) { 448 *_retval = true; 449 } else { 450 *_retval = false; 451 } 452 return NS_OK; 453 } 454 455 NS_IMETHODIMP 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) { 460 *_retval = true; 461 } else { 462 *_retval = false; 463 } 464 return NS_OK; 465 } 466 467 NS_IMETHODIMP 468 nsCertTree::IsContainerEmpty(int32_t index, bool* _retval) { 469 *_retval = !mTreeArray; 470 return NS_OK; 471 } 472 473 NS_IMETHODIMP 474 nsCertTree::IsSeparator(int32_t index, bool* _retval) { 475 *_retval = false; 476 return NS_OK; 477 } 478 479 NS_IMETHODIMP 480 nsCertTree::GetParentIndex(int32_t rowIndex, int32_t* _retval) { 481 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 482 int i, idx = 0; 483 for (i = 0; i < mNumOrgs && idx < rowIndex; i++, idx++) { 484 if (mTreeArray[i].open) { 485 if (rowIndex <= idx + mTreeArray[i].numChildren) { 486 *_retval = idx; 487 return NS_OK; 488 } 489 idx += mTreeArray[i].numChildren; 490 } 491 } 492 *_retval = -1; 493 return NS_OK; 494 } 495 496 NS_IMETHODIMP 497 nsCertTree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, 498 bool* _retval) { 499 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 500 501 int i, idx = 0; 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; 507 return NS_OK; 508 } 509 } 510 } 511 *_retval = false; 512 return NS_OK; 513 } 514 515 NS_IMETHODIMP 516 nsCertTree::GetLevel(int32_t index, int32_t* _retval) { 517 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 518 treeArrayEl* el = GetThreadDescAtIndex(index); 519 if (el) { 520 *_retval = 0; 521 } else { 522 *_retval = 1; 523 } 524 return NS_OK; 525 } 526 527 NS_IMETHODIMP 528 nsCertTree::GetImageSrc(int32_t row, nsTreeColumn* col, nsAString& _retval) { 529 _retval.Truncate(); 530 return NS_OK; 531 } 532 533 NS_IMETHODIMP 534 nsCertTree::GetCellValue(int32_t row, nsTreeColumn* col, nsAString& _retval) { 535 _retval.Truncate(); 536 return NS_OK; 537 } 538 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 (void)intl::AppDateTimeFormat::Format(style, &explodedTime, result); 546 } 547 548 NS_IMETHODIMP 549 nsCertTree::GetCellText(int32_t row, nsTreeColumn* col, nsAString& _retval) { 550 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 551 552 nsresult rv = NS_OK; 553 _retval.Truncate(); 554 555 const nsAString& colID = col->GetId(); 556 557 treeArrayEl* el = GetThreadDescAtIndex(row); 558 if (el) { 559 if (u"certcol"_ns.Equals(colID)) 560 _retval.Assign(el->orgName); 561 else 562 _retval.Truncate(); 563 return NS_OK; 564 } 565 566 int32_t absoluteCertOffset; 567 RefPtr<nsCertTreeDispInfo> certdi( 568 GetDispInfoAtIndex(row, &absoluteCertOffset)); 569 if (!certdi) return NS_ERROR_FAILURE; 570 571 nsCOMPtr<nsIX509Cert> cert = certdi->mCert; 572 573 int32_t colIndex = col->Index(); 574 uint32_t arrayIndex = absoluteCertOffset + colIndex * (mNumRows - mNumOrgs); 575 uint32_t arrayLength = 0; 576 if (mCellText) { 577 mCellText->GetLength(&arrayLength); 578 } 579 if (arrayIndex < arrayLength) { 580 nsCOMPtr<nsISupportsString> myString( 581 do_QueryElementAt(mCellText, arrayIndex)); 582 if (myString) { 583 myString->GetData(_retval); 584 return NS_OK; 585 } 586 } 587 588 if (u"certcol"_ns.Equals(colID)) { 589 if (!cert) { 590 rv = GetPIPNSSBundleString("CertNotStored", _retval); 591 } else { 592 rv = cert->GetDisplayName(_retval); 593 } 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; 600 601 rv = cert->GetValidity(getter_AddRefs(validity)); 602 if (NS_SUCCEEDED(rv)) { 603 PRTime notBefore; 604 rv = validity->GetNotBefore(¬Before); 605 if (NS_SUCCEEDED(rv)) { 606 PRTimeToLocalDateString(notBefore, _retval); 607 } 608 } 609 } else if (u"expiredcol"_ns.Equals(colID) && cert) { 610 nsCOMPtr<nsIX509CertValidity> validity; 611 612 rv = cert->GetValidity(getter_AddRefs(validity)); 613 if (NS_SUCCEEDED(rv)) { 614 PRTime notAfter; 615 rv = validity->GetNotAfter(¬After); 616 if (NS_SUCCEEDED(rv)) { 617 PRTimeToLocalDateString(notAfter, _retval); 618 } 619 } 620 } else if (u"serialnumcol"_ns.Equals(colID) && cert) { 621 rv = cert->GetSerialNumber(_retval); 622 } else { 623 return NS_ERROR_FAILURE; 624 } 625 if (mCellText) { 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); 631 } 632 return rv; 633 } 634 635 NS_IMETHODIMP 636 nsCertTree::SetTree(mozilla::dom::XULTreeElement* tree) { 637 mTree = tree; 638 return NS_OK; 639 } 640 641 NS_IMETHODIMP 642 nsCertTree::ToggleOpenState(int32_t index) { 643 if (!mTreeArray) return NS_ERROR_NOT_INITIALIZED; 644 treeArrayEl* el = GetThreadDescAtIndex(index); 645 if (el) { 646 el->open = !el->open; 647 int32_t newChildren = (el->open) ? el->numChildren : -el->numChildren; 648 if (mTree) { 649 mTree->RowCountChanged(index + 1, newChildren); 650 mTree->InvalidateRow(index); 651 } 652 } 653 return NS_OK; 654 } 655 656 NS_IMETHODIMP 657 nsCertTree::CycleHeader(nsTreeColumn* col) { return NS_OK; } 658 659 NS_IMETHODIMP 660 nsCertTree::SelectionChangedXPCOM() { return NS_ERROR_NOT_IMPLEMENTED; } 661 662 NS_IMETHODIMP 663 nsCertTree::CycleCell(int32_t row, nsTreeColumn* col) { return NS_OK; } 664 665 NS_IMETHODIMP 666 nsCertTree::IsEditable(int32_t row, nsTreeColumn* col, bool* _retval) { 667 *_retval = false; 668 return NS_OK; 669 } 670 671 NS_IMETHODIMP 672 nsCertTree::SetCellValue(int32_t row, nsTreeColumn* col, 673 const nsAString& value) { 674 return NS_OK; 675 } 676 677 NS_IMETHODIMP 678 nsCertTree::SetCellText(int32_t row, nsTreeColumn* col, 679 const nsAString& value) { 680 return NS_OK; 681 } 682 683 // 684 // CanDrop 685 // 686 NS_IMETHODIMP nsCertTree::CanDrop(int32_t index, int32_t orientation, 687 mozilla::dom::DataTransfer* aDataTransfer, 688 bool* _retval) { 689 NS_ENSURE_ARG_POINTER(_retval); 690 *_retval = false; 691 692 return NS_OK; 693 } 694 695 // 696 // Drop 697 // 698 NS_IMETHODIMP nsCertTree::Drop(int32_t row, int32_t orient, 699 mozilla::dom::DataTransfer* aDataTransfer) { 700 return NS_OK; 701 } 702 703 // 704 // IsSorted 705 // 706 // ... 707 // 708 NS_IMETHODIMP nsCertTree::IsSorted(bool* _retval) { 709 *_retval = false; 710 return NS_OK; 711 } 712 713 #define RETURN_NOTHING 714 715 void nsCertTree::CmpInitCriterion(nsIX509Cert* cert, 716 CompareCacheHashEntry* entry, 717 sortCriterion crit, int32_t level) { 718 NS_ENSURE_TRUE(cert && entry, RETURN_NOTHING); 719 720 entry->mCritInit[level] = true; 721 nsString& str = entry->mCrit[level]; 722 723 switch (crit) { 724 case sort_IssuerOrg: 725 cert->GetIssuerOrganization(str); 726 if (str.IsEmpty()) cert->GetCommonName(str); 727 break; 728 case sort_Org: 729 cert->GetOrganization(str); 730 break; 731 case sort_Token: 732 cert->GetTokenName(str); 733 break; 734 case sort_CommonName: 735 cert->GetCommonName(str); 736 break; 737 case sort_IssuedDateDescending: { 738 nsresult rv; 739 nsCOMPtr<nsIX509CertValidity> validity; 740 PRTime notBefore; 741 742 rv = cert->GetValidity(getter_AddRefs(validity)); 743 if (NS_SUCCEEDED(rv)) { 744 rv = validity->GetNotBefore(¬Before); 745 } 746 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", 752 &explodedTime)) { 753 str = NS_ConvertASCIItoUTF16(nsDependentCString(datebuf)); 754 } 755 } 756 } break; 757 case sort_Email: 758 cert->GetEmailAddress(str); 759 break; 760 case sort_None: 761 default: 762 break; 763 } 764 } 765 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); 770 771 if (!ace->mCritInit[level]) { 772 CmpInitCriterion(a, ace, crit, level); 773 } 774 775 if (!bce->mCritInit[level]) { 776 CmpInitCriterion(b, bce, crit, level); 777 } 778 779 nsString& str_a = ace->mCrit[level]; 780 nsString& str_b = bce->mCrit[level]; 781 782 int32_t result; 783 if (!str_a.IsVoid() && !str_b.IsVoid()) 784 result = Compare(str_a, str_b, nsCaseInsensitiveStringComparator); 785 else 786 result = str_a.IsVoid() ? (str_b.IsVoid() ? 0 : -1) : 1; 787 788 if (sort_IssuedDateDescending == crit) result *= -1; // reverse compare order 789 790 return result; 791 } 792 793 int32_t nsCertTree::CmpBy(void* cache, nsIX509Cert* a, nsIX509Cert* b, 794 sortCriterion c0, sortCriterion c1, 795 sortCriterion c2) { 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. 802 803 if (!a && !b) return 0; 804 805 if (!a) return -1; 806 807 if (!b) return 1; 808 809 NS_ENSURE_TRUE(cache && a && b, 0); 810 811 CompareCacheHashEntry* ace = getCacheEntry(cache, a); 812 CompareCacheHashEntry* bce = getCacheEntry(cache, b); 813 814 int32_t cmp; 815 cmp = CmpByCrit(a, ace, b, bce, c0, 0); 816 if (cmp != 0) return cmp; 817 818 if (c1 != sort_None) { 819 cmp = CmpByCrit(a, ace, b, bce, c1, 1); 820 if (cmp != 0) return cmp; 821 822 if (c2 != sort_None) { 823 return CmpByCrit(a, ace, b, bce, c2, 2); 824 } 825 } 826 827 return cmp; 828 } 829 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); 833 } 834 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); 839 } 840 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); 844 }