├── .gitignore ├── BestIconFinder.cs ├── CustomIconDashboarder.csproj ├── CustomIconDashboarderExt.cs ├── CustomIconDashboarder_plgx.csproj ├── DashboarderForm.Designer.cs ├── DashboarderForm.cs ├── DashboarderForm.resx ├── HOWTO_COMPILE.md ├── HtmlAgilityPack ├── EncodingFoundException.cs ├── HtmlAttribute.cs ├── HtmlAttributeCollection.cs ├── HtmlCmdLine.cs ├── HtmlCommentNode.cs ├── HtmlConsoleListener.cs ├── HtmlDocument.PathMethods.cs ├── HtmlDocument.Xpath.cs ├── HtmlDocument.cs ├── HtmlElementFlag.cs ├── HtmlEntity.cs ├── HtmlNameTable.cs ├── HtmlNode.Encapsulator.cs ├── HtmlNode.Xpath.cs ├── HtmlNode.cs ├── HtmlNodeCollection.cs ├── HtmlNodeNavigator.cs ├── HtmlNodeType.cs ├── HtmlParseError.cs ├── HtmlParseErrorCode.cs ├── HtmlTextNode.cs ├── HtmlWeb.Xpath.cs ├── HtmlWeb.cs ├── HtmlWebException.cs ├── IOLibrary.cs ├── InvalidProgramException.cs ├── Metro │ ├── HtmlWeb.cs │ └── InvalidProgramException.cs ├── MimeTypeMap.cs ├── MixedCodeDocument.cs ├── MixedCodeDocumentCodeFragment.cs ├── MixedCodeDocumentFragment.cs ├── MixedCodeDocumentFragmentList.cs ├── MixedCodeDocumentFragmentType.cs ├── MixedCodeDocumentTextFragment.cs ├── NameValuePair.cs ├── NameValuePairList.cs ├── Trace.FullFramework.cs ├── Trace.cs ├── Utilities.cs └── crc32.cs ├── IconChooser.cs ├── IconStatsHandler.cs ├── ImageInfo.cs ├── KPCIDConfig.cs ├── LICENSE.txt ├── LomsonLib ├── Collections │ └── CollectionUtil.cs ├── LomsonDebug │ ├── ListViewLayoutManager.cs │ └── LomsonDebugLib.cs ├── LomsonLib.csproj ├── Properties │ └── AssemblyInfo.cs ├── UI │ ├── CompatibilityManager.cs │ ├── RTFBuilder.cs │ ├── ScaleControlTableLayoutPanel.cs │ └── SwappableComparer.cs └── Utility │ └── LomsonUtility.cs ├── Properties └── AssemblyInfo.cs ├── README.md ├── Resource.Designer.cs ├── Resource.resx ├── WaitingForm.Designer.cs ├── WaitingForm.cs ├── WaitingForm.resx ├── _config.yml ├── cleanBinaries.cmd ├── createPlgx.cmd ├── docs └── images │ ├── screenshot-dashboard-1.png │ └── screenshot-menuitem.png └── versionInfo.txt /.gitignore: -------------------------------------------------------------------------------- 1 | obj/* 2 | bin/* 3 | /LomsonLib/bin/Debug 4 | /LomsonLib/obj/Debug 5 | -------------------------------------------------------------------------------- /BestIconFinder.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Net; 24 | using System.Drawing; 25 | using System.Text.RegularExpressions; 26 | using HtmlAgilityPack; 27 | using LomsonLib.Utility; 28 | 29 | namespace CustomIconDashboarderPlugin 30 | { 31 | 32 | /// 33 | /// Find the best icon of a web site from its url. 34 | /// 35 | public class BestIconFinder 36 | { 37 | #region Static elements 38 | 39 | /// 40 | /// STATIC Section 41 | /// 42 | 43 | 44 | public static void InitClass() { 45 | // Enable TLS 1.1 (768), TLS 1.2 (3072) and TLS 1.3 (12288) 46 | ServicePointManager.SecurityProtocol = 47 | (SecurityProtocolType)768 | 48 | (SecurityProtocolType)3072 | 49 | (SecurityProtocolType)12288; 50 | } 51 | 52 | ~BestIconFinder() { 53 | client.Dispose(); 54 | } 55 | 56 | private const string REQUEST_USER_AGENT = "Mozilla/5.0 (Windows 6.1; rv:27.0) Gecko/20100101 Firefox/27.0"; 57 | private const string REQUEST_HEADER_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 58 | private const int REQUEST_TIMEOUT = 10000; 59 | 60 | private const string alphabetUC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 61 | private const string alphabetLC = "abcdefghijklmnopqrstuvwxyz"; 62 | 63 | private static string[] xPathToTest = { 64 | "//link[translate(@rel,'" + alphabetUC + "','" + alphabetLC +"')='shortcut icon']", 65 | "//link[translate(@rel,'" + alphabetUC + "','" + alphabetLC +"')='icon']", 66 | "//link[translate(@rel,'" + alphabetUC + "','" + alphabetLC +"')='apple-touch-icon']", 67 | "//link[translate(@rel,'" + alphabetUC + "','" + alphabetLC +"')='apple-touch-icon image_src']", 68 | "//link[translate(@rel,'" + alphabetUC + "','" + alphabetLC +"')='apple-touch-icon-precomposed']" 69 | }; 70 | 71 | private static Dictionary imageCache = new Dictionary{}; 72 | private static object lckImageCache = new object(); 73 | private static Dictionary uriRequestCache = new Dictionary{}; 74 | private static object lckUriRequestCache = new object(); 75 | 76 | #endregion 77 | 78 | 79 | public Image BestImage {get; private set; } 80 | 81 | public Uri SiteUri {get; private set;} // Uri without path - eg http://www.sample.com 82 | public Uri OriginalSiteUri {get; private set;} // Original URI with all path - eg http://www.sample.com/folder/subfolder 83 | public Uri RootUriForIco {get; private set;} 84 | public FinderResult Result {get; private set; } 85 | public string Details {get;set; } 86 | public int NbRequestCacheInvoke {get; private set; } 87 | private MyWebClient client; 88 | 89 | public List ListImageInfo {get; private set;} // All image and URI 90 | public int IndexOfBestImage {get; private set; } 91 | 92 | private MyLogger myLogger; 93 | private List ListUriIcons {get; set;} 94 | 95 | public BestIconFinder(Uri siteUri) 96 | { 97 | this.OriginalSiteUri = siteUri; 98 | if ( (siteUri.Scheme.ToLower() == "http") || 99 | (siteUri.Scheme.ToLower() == "https" ) ){ 100 | this.SiteUri = new Uri(siteUri.Scheme + "://" +siteUri.DnsSafeHost); 101 | this.Result = new FinderResult(FinderResult.RESULT_NO_URL); 102 | } else { 103 | this.SiteUri = null; 104 | this.Result = new FinderResult(FinderResult.RESULT_NO_URL); 105 | } 106 | this.myLogger = new MyLogger(this); 107 | this.BestImage = null; 108 | this.IndexOfBestImage = -1; 109 | this.ListImageInfo = new List(); 110 | this.NbRequestCacheInvoke = 0; 111 | client = new MyWebClient(); 112 | } 113 | 114 | public BestIconFinder() 115 | { 116 | this.SiteUri = null; 117 | this.Result = null; 118 | this.myLogger = new MyLogger(this); 119 | this.BestImage = null; 120 | this.IndexOfBestImage = -1; 121 | this.ListImageInfo = new List(); 122 | this.NbRequestCacheInvoke = 0; 123 | client = new MyWebClient(); 124 | } 125 | 126 | #region Embeded Factory 127 | public static BestIconFinder BuildInstanceWithNoURLResult() 128 | { 129 | BestIconFinder result = new BestIconFinder 130 | { 131 | Result = new FinderResult(FinderResult.RESULT_NO_URL) 132 | }; 133 | return result; 134 | } 135 | 136 | public static BestIconFinder BuildInstanceWithMalformedURLResult() 137 | { 138 | BestIconFinder result = new BestIconFinder 139 | { 140 | Result = new FinderResult(FinderResult.RESULT_MALFORMED_URL) 141 | }; 142 | result.myLogger.LogDebug("Non managed URL format"); 143 | return result; 144 | } 145 | #endregion 146 | 147 | public void FindBestIcon() 148 | { 149 | if (this.SiteUri == null) { 150 | this.myLogger.LogWarn("No URL. Stop Find Best Icon"); 151 | return; 152 | } 153 | 154 | FindBestIconForURI( this.SiteUri); 155 | 156 | if (this.BestImage == null) { // try with www 157 | 158 | Uri testURI = this.SiteUri; 159 | if ( ! testURI.Host.StartsWith("www.") ) { 160 | FindBestIconForURI( new Uri( 161 | this.SiteUri.Scheme + "://www." + this.SiteUri.DnsSafeHost )); 162 | } 163 | } 164 | 165 | string rootDomain = URLUtility.RootDomain(this.SiteUri.AbsoluteUri); 166 | 167 | if (! string.IsNullOrEmpty(rootDomain)) { 168 | if (this.BestImage == null) { // try with root domain prefix 169 | FindBestIconForURI( new Uri( this.SiteUri.Scheme + "://" + rootDomain )); 170 | } 171 | 172 | if (this.BestImage == null) { // try with host prefix and www 173 | FindBestIconForURI( new Uri (this.SiteUri.Scheme + "://www." + rootDomain)); 174 | } 175 | } 176 | 177 | if (this.RootUriForIco != null) { 178 | if (this.BestImage == null) { // try with host prefix 179 | FindBestIconForURI( new Uri( 180 | this.RootUriForIco.Scheme + "://" + this.RootUriForIco.Host) ); 181 | } 182 | 183 | if (this.BestImage == null) { // try with host prefix and www 184 | FindBestIconForURI( new Uri ( 185 | this.RootUriForIco.Scheme + "://www." + this.RootUriForIco.Host)); 186 | } 187 | } 188 | 189 | if (this.BestImage == null) { 190 | FindBestIconForURI( this.OriginalSiteUri ); 191 | } 192 | 193 | } 194 | 195 | public void FindBestIconForURI(Uri param_uri) 196 | { 197 | // Prepare 198 | if (param_uri == null) { 199 | this.myLogger.LogWarn("No url. Stop Find Best Icon"); 200 | return; 201 | } 202 | 203 | Uri testedUri = param_uri; 204 | 205 | // Get Links 206 | GetIconLinksForURI(testedUri); 207 | 208 | if (this.Result.ResultCode != FinderResult.RESULT_OK) { 209 | this.myLogger.LogError("Error while retrieving Icon link for " + 210 | testedUri.AbsoluteUri); 211 | return; 212 | } 213 | 214 | // Test Icon URL 215 | this.myLogger.LogInfo("Test Icon URL"); 216 | this.myLogger.Indent(); 217 | this.BestImage = null; 218 | foreach ( Uri uriTested in this.ListUriIcons) { 219 | TestImageUri( uriTested); 220 | } 221 | 222 | // Test default url 223 | if ( ((this.BestImage != null) 224 | && (this.BestImage.Width + this.BestImage.Height < 64)) 225 | || (this.BestImage == null) ) { 226 | TestImageUri( new Uri(this.RootUriForIco, "favicon.ico")); 227 | } 228 | 229 | // Try better resolution (usefull for site like www dot francetvsport dot com 230 | if ( ((this.BestImage != null) 231 | && (this.BestImage.Width + this.BestImage.Height < 64)) 232 | || (this.BestImage == null) ) { 233 | TestImageUri( new Uri(this.RootUriForIco, "apple-touch-icon-precomposed.png")); 234 | TestImageUri( new Uri(this.RootUriForIco, "apple-touch-icon.png")); 235 | } 236 | 237 | this.myLogger.Unindent(); 238 | this.myLogger.LogInfo("End test Icon URI"); 239 | 240 | } 241 | 242 | /// 243 | /// Test Image URI and store in Best Image if quality is better 244 | /// 245 | public void TestImageUri (Uri uriToBeTested) 246 | { 247 | this.myLogger.LogDebug("Test " + uriToBeTested.AbsoluteUri); 248 | byte[] pictureData = null; 249 | Image downloadedImage = null; 250 | 251 | bool imageWasInCache = false; 252 | 253 | lock (lckImageCache) { 254 | if (imageCache.ContainsKey( uriToBeTested ) ) { 255 | downloadedImage = imageCache[uriToBeTested]; 256 | if (downloadedImage != null) 257 | downloadedImage = (Image)downloadedImage.Clone(); 258 | imageWasInCache = true; 259 | } 260 | } 261 | 262 | if (!imageWasInCache) { 263 | try { 264 | pictureData = client.DownloadData( uriToBeTested); 265 | pictureData = PreparedIconBytesArrayToBeParsed( pictureData ); 266 | 267 | try { 268 | downloadedImage = KeePassLib.Utility.GfxUtil.LoadImage( pictureData ); 269 | } 270 | catch (Exception e) { 271 | this.myLogger.LogError("Error while parsing image " + uriToBeTested.AbsoluteUri + System.Environment.NewLine 272 | + e.Message); 273 | } 274 | 275 | } 276 | catch (WebException) { 277 | this.myLogger.LogError( "Error while getting icon " 278 | + uriToBeTested.AbsoluteUri); 279 | } 280 | catch (NotSupportedException) { 281 | this.myLogger.LogError( "Not Supported Exception while getting icon " 282 | + uriToBeTested.AbsoluteUri); 283 | } 284 | 285 | lock (lckImageCache) { 286 | if (!imageCache.ContainsKey(uriToBeTested)) { 287 | imageCache.Add(uriToBeTested, downloadedImage); 288 | } 289 | if (downloadedImage != null) 290 | downloadedImage = (Image)downloadedImage.Clone(); 291 | 292 | } 293 | } 294 | 295 | if (downloadedImage != null) { 296 | // It is necessary to clone image to avoid concurrent access during post operation. 297 | // For example, error should occured if image is resized by several thread in the same time. 298 | this.myLogger.LogDebug( "Size " + downloadedImage.Width + " x " + downloadedImage.Height ); 299 | this.ListImageInfo.Add( new ImageInfo( downloadedImage,uriToBeTested.AbsolutePath) ); 300 | if ( (this.BestImage == null ) || 301 | (CompareImageQuality( downloadedImage, this.BestImage) == 1) ) { 302 | this.BestImage = downloadedImage; 303 | this.IndexOfBestImage = this.ListImageInfo.Count - 1; 304 | this.myLogger.LogInfo("-->stored as the best image"); 305 | } 306 | } 307 | } 308 | 309 | public void GetIconLinks() { 310 | GetIconLinksForURI(this.SiteUri); 311 | } 312 | 313 | public void GetIconLinksForURI(Uri param_Uri) 314 | { 315 | this.myLogger.LogDebug("Start findIconLinks"); 316 | this.myLogger.LogDebug("URL = " + param_Uri.AbsoluteUri); 317 | 318 | this.myLogger.Indent(); 319 | 320 | Uri testedUri = param_Uri; 321 | 322 | // Get HTML 323 | HtmlAgilityPack.HtmlDocument htmlPage = null; 324 | Uri fullUri = null; 325 | 326 | bool uriInCache = false; 327 | lock(lckUriRequestCache) { 328 | if (uriRequestCache.ContainsKey( param_Uri )) { 329 | CachedURIRequestResult curr = uriRequestCache[param_Uri]; 330 | fullUri = curr.FullUri; 331 | htmlPage = curr.Html; 332 | this.NbRequestCacheInvoke++; 333 | uriInCache = true; 334 | } 335 | } 336 | 337 | if (!uriInCache) { 338 | try { 339 | fullUri = GetURIOfSite(testedUri, out htmlPage); 340 | } 341 | catch ( WebException ) { 342 | this.Result = new FinderResult(FinderResult.RESULT_HTML_NOT_FOUND); 343 | this.myLogger.Unindent(); 344 | this.myLogger.LogDebug("End findIconLinks"); 345 | return; 346 | } 347 | catch ( Exception ) { 348 | this.Result = new FinderResult(FinderResult.RESULT_HTML_PARSING); 349 | this.myLogger.Unindent(); 350 | this.myLogger.LogDebug("End findIconLinks"); 351 | return; 352 | } 353 | lock (lckUriRequestCache) { 354 | if (!uriRequestCache.ContainsKey( param_Uri )) { 355 | var curr = new CachedURIRequestResult(fullUri, htmlPage); 356 | uriRequestCache.Add( param_Uri, curr); 357 | } 358 | } 359 | } 360 | 361 | if ( htmlPage == null) { 362 | this.Result = new FinderResult(FinderResult.RESULT_HTML_NOT_FOUND); 363 | this.myLogger.Unindent(); 364 | this.myLogger.LogDebug("End findIconLinks"); 365 | return; 366 | } 367 | this.RootUriForIco = new Uri ( fullUri.Scheme + "://" + fullUri.DnsSafeHost ); 368 | this.myLogger.LogDebug("Root Url = " + this.RootUriForIco.AbsoluteUri); 369 | 370 | // Get XPath 371 | HtmlNode hnn = htmlPage.DocumentNode; 372 | //this.myLogger.LogDebugIndented(hnn.OuterHtml); 373 | this.ListUriIcons = new List(); 374 | foreach (String currentXpath in xPathToTest) 375 | { 376 | this.myLogger.LogInfo("Testing " + currentXpath); 377 | this.myLogger.Indent(); 378 | 379 | HtmlNodeCollection hnc = hnn.SelectNodes(currentXpath); 380 | if ( (hnc == null) || (hnc.Count == 0) ) { 381 | this.myLogger.LogInfo("Node not found for xpath " + currentXpath); 382 | } 383 | 384 | else { 385 | 386 | foreach (HtmlNode hn in hnc) { 387 | string relativeUrlPicture = hn.GetAttributeValue("href", ""); 388 | if ( relativeUrlPicture.Length == 0 ) { 389 | this.myLogger.LogWarn("Zero Length URL found for xpath "); 390 | } 391 | else { 392 | var uriPicture = new Uri(this.RootUriForIco, relativeUrlPicture); 393 | 394 | if (!this.ListUriIcons.Exists((Uri myUri) => myUri == uriPicture)) { 395 | this.ListUriIcons.Add( uriPicture); 396 | } 397 | 398 | this.myLogger.LogDebug("URL = '" + uriPicture.AbsoluteUri + "'"); 399 | } 400 | } 401 | 402 | } 403 | this.myLogger.Unindent(); 404 | } 405 | 406 | this.Result = new FinderResult( FinderResult.RESULT_OK ); 407 | this.myLogger.Unindent(); 408 | this.myLogger.LogDebug("End findIconLinks"); 409 | 410 | } 411 | 412 | 413 | 414 | /// 415 | /// Compare Quality of two images. 416 | /// 417 | /// 418 | /// 419 | /// 1 = if img1 better than img2, 0 = equivalent, -1 = worse 420 | 421 | private static int CompareImageQuality(Image img1, Image img2) { 422 | if ( (img1.Width + img1.Height) > (img2.Width + img2.Height) ) { 423 | return 1; 424 | } 425 | else if ( (img1.Width + img1.Height) == (img2.Width + img2.Height) ) { 426 | return 0; 427 | } 428 | 429 | return -1; 430 | } 431 | 432 | /// 433 | /// Gets a memory stream representing an image from an explicit favicon location. 434 | /// 435 | /// The URI. 436 | /// 437 | private Uri GetURIOfSite(Uri initialURI, out HtmlDocument hdoc) 438 | { 439 | HtmlWeb hw = new HtmlWeb(); 440 | hw.UserAgent = REQUEST_USER_AGENT; 441 | 442 | hdoc = null; 443 | Uri responseURI = null; 444 | 445 | Uri nextUri = initialURI; 446 | try 447 | { 448 | int counter = 0; // Protection from cyclic redirect 449 | do 450 | { 451 | // A cookie container is needed for some sites to work 452 | hw.PreRequest += PreRequest_EventHandler; 453 | 454 | // HtmlWeb.Load will follow 301 and 302 redirects to alternate URIs 455 | hdoc = hw.Load(nextUri.AbsoluteUri); 456 | responseURI = hw.ResponseUri; 457 | 458 | // Old school meta refreshes need to parsed 459 | nextUri = GetMetaRefreshLink(responseURI, hdoc); 460 | counter++; 461 | } while (nextUri != null && counter < 16); // Sixteen redirects would be more than enough. 462 | 463 | 464 | } 465 | catch (Exception e) { 466 | this.myLogger.LogError("error while getting url " + nextUri.AbsoluteUri 467 | + " " + e.Message); 468 | } 469 | return responseURI; 470 | } 471 | 472 | private Uri GetMetaRefreshLink(Uri uri, HtmlAgilityPack.HtmlDocument hdoc) 473 | { 474 | HtmlNodeCollection metas = hdoc.DocumentNode.SelectNodes("/html/head/meta"); 475 | string redirect = null; 476 | 477 | if (metas == null) 478 | { 479 | return null; 480 | } 481 | 482 | for (int i = 0; i < metas.Count; i++) 483 | { 484 | HtmlNode node = metas[i]; 485 | try 486 | { 487 | HtmlAttribute httpeq = node.Attributes["http-equiv"]; 488 | HtmlAttribute content = node.Attributes["content"]; 489 | if (httpeq.Value.ToLower().Equals("location") || httpeq.Value.ToLower().Equals("refresh")) 490 | { 491 | if (content.Value.ToLower().Contains("url")) 492 | { 493 | Match match = Regex.Match(content.Value.ToLower(), @".*?url[\s=]*(\S+)"); 494 | if (match.Success) 495 | { 496 | redirect = match.Captures[0].ToString(); 497 | redirect = match.Groups[1].ToString(); 498 | } 499 | } 500 | 501 | } 502 | } 503 | catch (Exception) { } 504 | } 505 | 506 | if (String.IsNullOrEmpty(redirect)) 507 | { 508 | return null; 509 | } 510 | 511 | return new Uri(uri, redirect); 512 | } 513 | 514 | 515 | /// 516 | /// Prepare bytes array representing an icon to be parsed by libraries 517 | /// (provided by KP and MS) 518 | /// 519 | /// 520 | /// Pad with zero if length of array is not sufficient according to header. 521 | /// 522 | /// Byte array to be parsed 523 | /// 524 | /// Inspired by the method KeePassLib.Utility.GsfxUtil.UnpackIco of KeePass v2.30 525 | private byte[] PreparedIconBytesArrayToBeParsed(byte[] batbp) { 526 | if (batbp == null) { 527 | myLogger.LogWarn("PreparedIconBytesArrayToBeParsed: Byte array to be prepared is Null"); 528 | return batbp; 529 | } 530 | 531 | const int SizeICONDIR = 6; 532 | const int SizeICONDIRENTRY = 16; 533 | 534 | if (BitConverter.ToInt32(new byte[] { 1, 2, 3, 4 }, 535 | 0) != 0x04030201) { 536 | myLogger.LogWarn("PreparedIconBytesArrayToBeParsed: Not Little Endian detected"); 537 | } 538 | 539 | if (batbp.Length < SizeICONDIR) return null; 540 | if (BitConverter.ToUInt16(batbp, 0) != 0) return batbp; // Reserved, 0 if icon 541 | if (BitConverter.ToUInt16(batbp, 2) != 1) return batbp; // ICO type, 1 if icon 542 | 543 | int nbIcon = BitConverter.ToUInt16(batbp, 4); 544 | if (nbIcon < 0) { 545 | myLogger.LogWarn("PreparedIconBytesArrayToBeParsed: nb of Icons is not positive");; 546 | } 547 | 548 | int cbDir = SizeICONDIR + (nbIcon * SizeICONDIRENTRY); 549 | if (batbp.Length < cbDir) 550 | return null; 551 | 552 | int iOffset = SizeICONDIR; 553 | int padLength = 0; 554 | for (int i = 0; i < nbIcon; ++i) { 555 | int dataSize = BitConverter.ToInt32(batbp, iOffset + 8); 556 | int iStartImgData = BitConverter.ToInt32(batbp, iOffset + 12); 557 | 558 | if ((iStartImgData + dataSize) > batbp.Length) { 559 | padLength = iStartImgData + dataSize - batbp.Length; 560 | 561 | } 562 | 563 | iOffset += SizeICONDIRENTRY; 564 | } 565 | 566 | if (padLength == 0 ) { 567 | return batbp; 568 | } 569 | else { 570 | myLogger.LogWarn("PreparedIconBytesArrayToBeParsed: Padding file with " 571 | + padLength.ToString() + " leading zero(s)");; 572 | 573 | var padArray = new byte[padLength]; 574 | for (int ii = 0; ii < padLength; ii++) { 575 | padArray[ii] = 0; 576 | } 577 | var result = new byte[batbp.Length + padLength]; 578 | Array.Copy(batbp, 0, result, 0, batbp.Length); 579 | Array.Copy(padArray, 0, result, batbp.Length, padLength); 580 | 581 | return result; 582 | } 583 | 584 | } 585 | 586 | private bool PreRequest_EventHandler(HttpWebRequest request) 587 | { 588 | request.CookieContainer = new System.Net.CookieContainer(); 589 | request.Accept = REQUEST_HEADER_ACCEPT; 590 | request.Headers.Add(HttpRequestHeader.AcceptLanguage, "*"); 591 | request.Timeout = REQUEST_TIMEOUT; 592 | 593 | return true; 594 | } 595 | 596 | private sealed class MyLogger { 597 | 598 | private int nbIndent; 599 | private String indent; 600 | private BestIconFinder myBestIf; 601 | private int logLevel; // ERROR = 1, WARN = 2, INFO = 3, DEBUG = 4 602 | 603 | public MyLogger(BestIconFinder paramMyBestIf) { 604 | this.nbIndent = 0; 605 | indent = ""; 606 | this.myBestIf = paramMyBestIf; 607 | this.logLevel = 4; 608 | } 609 | 610 | 611 | public MyLogger(BestIconFinder paramMyBestIf, int paramLogLevel):this(paramMyBestIf) { 612 | logLevel = paramLogLevel; 613 | } 614 | 615 | public void Reset() { 616 | this.nbIndent = 0; 617 | indent = ""; 618 | } 619 | 620 | public void Indent() { 621 | nbIndent++; 622 | updateIndent(); 623 | } 624 | 625 | public void Unindent() { 626 | nbIndent--; 627 | updateIndent(); 628 | } 629 | 630 | private void updateIndent() { 631 | indent = ""; 632 | indent = indent.PadRight(nbIndent * 2, ' '); 633 | } 634 | 635 | public void LogInfo(String what) { 636 | if ( this.logLevel >= 3) 637 | myBestIf.Details += indent + what + System.Environment.NewLine; 638 | } 639 | 640 | public void LogDebug(String what) { 641 | if ( this.logLevel >= 4) 642 | myBestIf.Details += indent + what + System.Environment.NewLine; 643 | } 644 | 645 | public void LogDebugIndented(String what) { 646 | if ( this.logLevel >= 4) { 647 | what = what.Replace("\n", System.Environment.NewLine + indent); 648 | 649 | myBestIf.Details += indent + what + System.Environment.NewLine; 650 | } 651 | } 652 | 653 | public void LogWarn(String what) { 654 | if ( this.logLevel >= 2) 655 | myBestIf.Details += indent + what + System.Environment.NewLine; 656 | } 657 | 658 | public void LogError(String what) { 659 | if ( this.logLevel >= 1) 660 | myBestIf.Details += indent + "ERROR - " + what + System.Environment.NewLine; 661 | } 662 | } 663 | 664 | public void Dispose() { 665 | if (this.BestImage != null) { 666 | this.BestImage.Dispose(); 667 | } 668 | } 669 | 670 | 671 | // // Set "UnsafeHeaderParsing" flags. Usefull to retrieve information from several sites 672 | // // try www dot geni dot com 673 | // // to be used with "using System.Reflection;" in header 674 | // public static bool SetAllowUnsafeHeaderParsing(bool value) 675 | // { 676 | // //Get the assembly that contains the internal class 677 | // Assembly aNetAssembly = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection)); 678 | // if (aNetAssembly != null) 679 | // { 680 | // //Use the assembly in order to get the internal type for the internal class 681 | // Type aSettingsType = aNetAssembly.GetType("System.Net.Configuration.SettingsSectionInternal"); 682 | // if (aSettingsType != null) 683 | // { 684 | // //Use the internal static property to get an instance of the internal settings class. 685 | // //If the static instance isn't created allready the property will create it for us. 686 | // object anInstance = aSettingsType.InvokeMember("Section", 687 | // BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { }); 688 | // 689 | // if (anInstance != null) 690 | // { 691 | // //Locate the private bool field that tells the framework is unsafe header parsing should be allowed or not 692 | // FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance); 693 | // if (aUseUnsafeHeaderParsing != null) 694 | // { 695 | // aUseUnsafeHeaderParsing.SetValue(anInstance, value); 696 | // return true; 697 | // } 698 | // } 699 | // } 700 | // } 701 | // return false; 702 | // } 703 | // 704 | 705 | public class MyWebClient : WebClient 706 | { 707 | private readonly CookieContainer m_container = new CookieContainer(); 708 | 709 | protected override WebRequest GetWebRequest(Uri address) 710 | { 711 | // enhance chance to get favicon by setting some specifics parameters in request 712 | // Sample of web site and parameters 713 | // Header Accept - usefull for www dot akamai dot com 714 | WebRequest request = null; 715 | try { request = base.GetWebRequest(address); } 716 | catch (Exception) { } // address is not well formed 717 | 718 | var webRequest = request as HttpWebRequest; 719 | if (webRequest != null) { 720 | webRequest.Accept = REQUEST_HEADER_ACCEPT; 721 | webRequest.UserAgent = REQUEST_USER_AGENT; 722 | webRequest.Headers.Add(HttpRequestHeader.AcceptLanguage, "*"); 723 | webRequest.Timeout = REQUEST_TIMEOUT; 724 | webRequest.CookieContainer = m_container; 725 | } 726 | return request; 727 | } 728 | } 729 | 730 | 731 | private sealed class CachedURIRequestResult { 732 | public Uri FullUri {get; private set; } 733 | public HtmlDocument Html {get; private set; } 734 | 735 | public CachedURIRequestResult (Uri fullUri, HtmlDocument html) { 736 | this.FullUri = fullUri; 737 | this.Html = html; 738 | } 739 | 740 | } 741 | 742 | } 743 | 744 | public sealed class FinderResult { 745 | 746 | public const int RESULT_NOT_YET_SEARCH = 0; 747 | public const int RESULT_OK = 1; 748 | public const int RESULT_HTML_NOT_FOUND = 2; 749 | public const int RESULT_HTML_PARSING = 3; 750 | public const int RESULT_NO_URL = 4; 751 | public const int RESULT_MALFORMED_URL = 5; 752 | 753 | public int ResultCode {get; private set; } 754 | public FinderResult (int code) 755 | { 756 | ResultCode = code; 757 | } 758 | 759 | public override string ToString() { 760 | switch (this.ResultCode) { 761 | case FinderResult.RESULT_NOT_YET_SEARCH : return "Not Yet Search"; 762 | case RESULT_OK : return "OK"; 763 | case RESULT_HTML_NOT_FOUND : return "Html not found"; 764 | case RESULT_HTML_PARSING : return "Error Html parsing"; 765 | case RESULT_NO_URL : return "No URL"; 766 | case RESULT_MALFORMED_URL: return "Malformed URL"; 767 | default : return ""; 768 | } 769 | } 770 | } 771 | 772 | } 773 | -------------------------------------------------------------------------------- /CustomIconDashboarder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {6089EB1A-29CD-4CFF-8CF8-C9D0E2CEFAB1} 5 | Debug 6 | AnyCPU 7 | Library 8 | CustomIconDashboarderPlugin 9 | CustomIconDashboarderPlugin 10 | v4.8 11 | 12 | 13 | Properties 14 | False 15 | False 16 | False 17 | OnBuildSuccess 18 | False 19 | False 20 | False 21 | obj\$(Configuration)\ 22 | 4 23 | False 24 | C:\Users\Matthieu\AppData\Roaming\ICSharpCode/SharpDevelop4\Settings.SourceAnalysis 25 | 26 | 27 | x86 28 | 4194304 29 | False 30 | Auto 31 | 4096 32 | 33 | 34 | ..\KeePass\Build\KeePass\Debug\ 35 | True 36 | Full 37 | False 38 | False 39 | DEBUG;TRACE 40 | obj\ 41 | Project 42 | 43 | 44 | bin\Release\ 45 | False 46 | None 47 | True 48 | False 49 | TRACE 50 | 51 | 52 | x64 53 | 5 54 | false 55 | 56 | 57 | false 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Form 111 | 112 | 113 | WaitingForm.cs 114 | 115 | 116 | 117 | 118 | Form 119 | 120 | 121 | DashboarderForm.cs 122 | 123 | 124 | 125 | 126 | 127 | 128 | Resource.resx 129 | True 130 | True 131 | 132 | 133 | 134 | 135 | DashboarderForm.cs 136 | 137 | 138 | WaitingForm.cs 139 | 140 | 141 | ResXFileCodeGenerator 142 | Resource.Designer.cs 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | {10938016-dee2-4a25-9a5a-8fd3444379ca} 159 | KeePass 160 | 161 | 162 | {f61ffd35-4b4a-4a54-84ef-7ea8b3c59b44} 163 | LomsonLib 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /CustomIconDashboarderExt.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | using System; 23 | using System.Collections.Generic; 24 | 25 | using System.Windows.Forms; 26 | using KeePass.Plugins; 27 | 28 | namespace CustomIconDashboarderPlugin 29 | { 30 | /// 31 | /// Description of CustomIconCounterPlugin. 32 | /// 33 | public sealed class CustomIconDashboarderPluginExt : Plugin, IDisposable 34 | { 35 | 36 | private IPluginHost m_host; 37 | 38 | public override string UpdateUrl 39 | { 40 | get { return "https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/master/versionInfo.txt"; } 41 | } 42 | 43 | 44 | private ToolStripSeparator m_tsSeparator; 45 | private ToolStripMenuItem m_tsmiMenuItem; 46 | 47 | public override bool Initialize(IPluginHost host) 48 | { 49 | m_host = host; 50 | 51 | // Get a reference to the 'Tools' menu item container 52 | ToolStripItemCollection tsMenu = m_host.MainWindow.ToolsMenu.DropDownItems; 53 | 54 | // Add a separator at the bottom 55 | m_tsSeparator = new ToolStripSeparator(); 56 | tsMenu.Add(m_tsSeparator); 57 | 58 | // Add menu item 'Count Uses of Favicon' 59 | m_tsmiMenuItem = new ToolStripMenuItem(); 60 | m_tsmiMenuItem.Text = Resource.menu_customIcon; 61 | m_tsmiMenuItem.Click += this.OnMenuFavicon; 62 | tsMenu.Add(m_tsmiMenuItem); 63 | m_host.MainWindow.ToolsMenu.DropDownOpened += this.OnToolsMenuOpen; 64 | 65 | return true; 66 | } 67 | 68 | 69 | /// 70 | /// Terminate plugin 71 | /// 72 | public override void Terminate() 73 | { 74 | // Remove all of our menu items 75 | ToolStripItemCollection tsMenu = m_host.MainWindow.ToolsMenu.DropDownItems; 76 | m_tsmiMenuItem.Click -= this.OnMenuFavicon; 77 | m_host.MainWindow.ToolsMenu.DropDownOpened -= this.OnToolsMenuOpen; 78 | tsMenu.Remove(m_tsmiMenuItem); 79 | tsMenu.Remove(m_tsSeparator); 80 | Dispose(); 81 | 82 | } 83 | 84 | public void Dispose() 85 | { 86 | m_tsSeparator.Dispose(); 87 | m_tsmiMenuItem.Dispose(); 88 | } 89 | 90 | private void OnToolsMenuOpen(object sender, EventArgs e) 91 | { 92 | m_tsmiMenuItem.Enabled = m_host.Database.IsOpen; 93 | } 94 | 95 | 96 | private void OnMenuFavicon(object sender, EventArgs e) 97 | { 98 | DashboarderForm cilf = new DashboarderForm(m_host); 99 | 100 | cilf.ShowDialog(); 101 | } 102 | 103 | 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /CustomIconDashboarder_plgx.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {6089EB1A-29CD-4CFF-8CF8-C9D0E2CEFAB1} 5 | Debug 6 | AnyCPU 7 | Library 8 | CustomIconDashboarderPlugin 9 | CustomIconDashboarderPlugin 10 | v4.5 11 | 12 | 13 | Properties 14 | False 15 | False 16 | False 17 | OnBuildSuccess 18 | False 19 | False 20 | False 21 | obj\$(Configuration)\ 22 | 4 23 | False 24 | C:\Users\Matthieu\AppData\Roaming\ICSharpCode/SharpDevelop4\Settings.SourceAnalysis 25 | 26 | 27 | x86 28 | 4194304 29 | False 30 | Auto 31 | 4096 32 | 33 | 34 | ..\KeePass\Build\KeePass\Debug\ 35 | True 36 | Full 37 | False 38 | False 39 | DEBUG;TRACE 40 | obj\ 41 | Project 42 | 43 | 44 | bin\Release\ 45 | False 46 | None 47 | True 48 | False 49 | TRACE 50 | 51 | 52 | x64 53 | 5 54 | false 55 | 56 | 57 | false 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | Component 116 | 117 | 118 | 119 | 120 | Form 121 | 122 | 123 | WaitingForm.cs 124 | 125 | 126 | 127 | 128 | Form 129 | 130 | 131 | DashboarderForm.cs 132 | 133 | 134 | 135 | 136 | 137 | 138 | Resource.resx 139 | True 140 | True 141 | 142 | 143 | 144 | 145 | DashboarderForm.cs 146 | 147 | 148 | WaitingForm.cs 149 | 150 | 151 | ResXFileCodeGenerator 152 | Resource.Designer.cs 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | {10938016-dee2-4a25-9a5a-8fd3444379ca} 168 | KeePass 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /DashboarderForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 30 122 | 123 | -------------------------------------------------------------------------------- /HOWTO_COMPILE.md: -------------------------------------------------------------------------------- 1 | # How to compile KeePass Custom Icon Dashboarder 2 | 3 | 1. Download and uncompress the last version of Keepass source code zip 4 | 5 | 2. Download and uncompress the KPCID source code zip or clone the repository 6 | 7 | 3. Open the solution file `KeePass\keepass.sln` in Visual Studio 8 | - Remove post-build command from `KeePass` and `KeePassLib` project 9 | - Remove signature from `KeePass` and `KeePassLib` project 10 | 11 | 4. Update the solution as follow: 12 | - Add the project `KPCID\CustomIconDashboarder.csproj` 13 | - Add the project `KPCID\LomsonLib\LomsonLib.csproj` 14 | - Define KeePass as starting project 15 | 16 | 5. To ensure that CustomIconDashboarder is always compile, in Visual Studio: 17 | - Navigate to `Debug > Options` and `Settings` or `Tools > Options` 18 | - Go to `Projects and Solutions > Build and Run` and make sure that the `Only build startup projects and dependencies on Run` box is left unchecked. 19 | 20 | The solution can now be debugged by pressing `F5` -------------------------------------------------------------------------------- /HtmlAgilityPack/EncodingFoundException.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/EncodingFoundException.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlAttribute.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlAttribute.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlAttributeCollection.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlAttributeCollection.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlCmdLine.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlCmdLine.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlCommentNode.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlCommentNode.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlConsoleListener.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlConsoleListener.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlDocument.PathMethods.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if !METRO 9 | 10 | using System; 11 | using System.IO; 12 | using System.Text; 13 | 14 | namespace HtmlAgilityPack 15 | { 16 | public partial class HtmlDocument 17 | { 18 | /// 19 | /// Detects the encoding of an HTML document from a file first, and then loads the file. 20 | /// 21 | /// The complete file path to be read. 22 | public void DetectEncodingAndLoad(string path) 23 | { 24 | DetectEncodingAndLoad(path, true); 25 | } 26 | 27 | /// 28 | /// Detects the encoding of an HTML document from a file first, and then loads the file. 29 | /// 30 | /// The complete file path to be read. May not be null. 31 | /// true to detect encoding, false otherwise. 32 | public void DetectEncodingAndLoad(string path, bool detectEncoding) 33 | { 34 | if (path == null) 35 | { 36 | throw new ArgumentNullException("path"); 37 | } 38 | 39 | Encoding enc; 40 | if (detectEncoding) 41 | { 42 | enc = DetectEncoding(path); 43 | } 44 | else 45 | { 46 | enc = null; 47 | } 48 | 49 | if (enc == null) 50 | { 51 | Load(path); 52 | } 53 | else 54 | { 55 | Load(path, enc); 56 | } 57 | } 58 | 59 | /// 60 | /// Detects the encoding of an HTML file. 61 | /// 62 | /// Path for the file containing the HTML document to detect. May not be null. 63 | /// The detected encoding. 64 | public Encoding DetectEncoding(string path) 65 | { 66 | if (path == null) 67 | { 68 | throw new ArgumentNullException("path"); 69 | } 70 | 71 | #if NETSTANDARD1_3 || NETSTANDARD1_6 72 | using (StreamReader sr = new StreamReader(File.OpenRead(path), OptionDefaultStreamEncoding)) 73 | #else 74 | using (StreamReader sr = new StreamReader(path, OptionDefaultStreamEncoding)) 75 | #endif 76 | { 77 | Encoding encoding = DetectEncoding(sr); 78 | return encoding; 79 | } 80 | } 81 | 82 | /// 83 | /// Loads an HTML document from a file. 84 | /// 85 | /// The complete file path to be read. May not be null. 86 | public void Load(string path) 87 | { 88 | if (path == null) 89 | throw new ArgumentNullException("path"); 90 | 91 | #if NETSTANDARD1_3 || NETSTANDARD1_6 92 | using (StreamReader sr = new StreamReader(File.OpenRead(path), OptionDefaultStreamEncoding)) 93 | #else 94 | using (StreamReader sr = new StreamReader(path, OptionDefaultStreamEncoding)) 95 | #endif 96 | { 97 | Load(sr); 98 | } 99 | } 100 | 101 | /// 102 | /// Loads an HTML document from a file. 103 | /// 104 | /// The complete file path to be read. May not be null. 105 | /// Indicates whether to look for byte order marks at the beginning of the file. 106 | public void Load(string path, bool detectEncodingFromByteOrderMarks) 107 | { 108 | if (path == null) 109 | throw new ArgumentNullException("path"); 110 | 111 | #if NETSTANDARD1_3 || NETSTANDARD1_6 112 | using (StreamReader sr = new StreamReader(File.OpenRead(path), detectEncodingFromByteOrderMarks)) 113 | #else 114 | using (StreamReader sr = new StreamReader(path, detectEncodingFromByteOrderMarks)) 115 | #endif 116 | { 117 | Load(sr); 118 | } 119 | } 120 | 121 | /// 122 | /// Loads an HTML document from a file. 123 | /// 124 | /// The complete file path to be read. May not be null. 125 | /// The character encoding to use. May not be null. 126 | public void Load(string path, Encoding encoding) 127 | { 128 | if (path == null) 129 | throw new ArgumentNullException("path"); 130 | 131 | if (encoding == null) 132 | throw new ArgumentNullException("encoding"); 133 | 134 | #if NETSTANDARD1_3 || NETSTANDARD1_6 135 | using (StreamReader sr = new StreamReader(File.OpenRead(path), encoding)) 136 | #else 137 | using (StreamReader sr = new StreamReader(path, encoding)) 138 | #endif 139 | { 140 | Load(sr); 141 | } 142 | } 143 | 144 | /// 145 | /// Loads an HTML document from a file. 146 | /// 147 | /// The complete file path to be read. May not be null. 148 | /// The character encoding to use. May not be null. 149 | /// Indicates whether to look for byte order marks at the beginning of the file. 150 | public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks) 151 | { 152 | if (path == null) 153 | throw new ArgumentNullException("path"); 154 | 155 | if (encoding == null) 156 | throw new ArgumentNullException("encoding"); 157 | 158 | #if NETSTANDARD1_3 || NETSTANDARD1_6 159 | using (StreamReader sr = new StreamReader(File.OpenRead(path), encoding, detectEncodingFromByteOrderMarks)) 160 | #else 161 | using (StreamReader sr = new StreamReader(path, encoding, detectEncodingFromByteOrderMarks)) 162 | #endif 163 | { 164 | Load(sr); 165 | } 166 | } 167 | 168 | /// 169 | /// Loads an HTML document from a file. 170 | /// 171 | /// The complete file path to be read. May not be null. 172 | /// The character encoding to use. May not be null. 173 | /// Indicates whether to look for byte order marks at the beginning of the file. 174 | /// The minimum buffer size. 175 | public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize) 176 | { 177 | if (path == null) 178 | throw new ArgumentNullException("path"); 179 | 180 | if (encoding == null) 181 | throw new ArgumentNullException("encoding"); 182 | 183 | #if NETSTANDARD1_3 || NETSTANDARD1_6 184 | using (StreamReader sr = new StreamReader(File.OpenRead(path), encoding, detectEncodingFromByteOrderMarks, buffersize)) 185 | 186 | #else 187 | using (StreamReader sr = new StreamReader(path, encoding, detectEncodingFromByteOrderMarks, buffersize)) 188 | #endif 189 | { 190 | Load(sr); 191 | } 192 | } 193 | 194 | /// 195 | /// Saves the mixed document to the specified file. 196 | /// 197 | /// The location of the file where you want to save the document. 198 | public void Save(string filename) 199 | { 200 | #if NETSTANDARD1_3 || NETSTANDARD1_6 201 | using (StreamWriter sw = new StreamWriter(File.OpenWrite(filename), GetOutEncoding())) 202 | #else 203 | using (StreamWriter sw = new StreamWriter(filename, false, GetOutEncoding())) 204 | #endif 205 | { 206 | Save(sw); 207 | } 208 | } 209 | 210 | /// 211 | /// Saves the mixed document to the specified file. 212 | /// 213 | /// The location of the file where you want to save the document. May not be null. 214 | /// The character encoding to use. May not be null. 215 | public void Save(string filename, Encoding encoding) 216 | { 217 | if (filename == null) 218 | { 219 | throw new ArgumentNullException("filename"); 220 | } 221 | 222 | if (encoding == null) 223 | { 224 | throw new ArgumentNullException("encoding"); 225 | } 226 | #if NETSTANDARD1_3 || NETSTANDARD1_6 227 | using (StreamWriter sw = new StreamWriter(File.OpenWrite(filename), encoding)) 228 | #else 229 | using (StreamWriter sw = new StreamWriter(filename, false, encoding)) 230 | #endif 231 | { 232 | Save(sw); 233 | } 234 | } 235 | } 236 | } 237 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlDocument.Xpath.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if !METRO 9 | 10 | using System.Xml.XPath; 11 | 12 | namespace HtmlAgilityPack 13 | { 14 | public partial class HtmlDocument : IXPathNavigable 15 | { 16 | /// 17 | /// Creates a new XPathNavigator object for navigating this HTML document. 18 | /// 19 | /// An XPathNavigator object. The XPathNavigator is positioned on the root of the document. 20 | public XPathNavigator CreateNavigator() 21 | { 22 | return new HtmlNodeNavigator(this, _documentnode); 23 | } 24 | } 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlDocument.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlDocument.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlElementFlag.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlElementFlag.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlEntity.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlEntity.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlNameTable.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlNameTable.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlNode.Xpath.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if !METRO 9 | 10 | using System; 11 | using System.Xml.XPath; 12 | 13 | namespace HtmlAgilityPack 14 | { 15 | public partial class HtmlNode : IXPathNavigable 16 | { 17 | /// 18 | /// Creates a new XPathNavigator object for navigating this HTML node. 19 | /// 20 | /// An XPathNavigator object. The XPathNavigator is positioned on the node from which the method was called. It is not positioned on the root of the document. 21 | public XPathNavigator CreateNavigator() 22 | { 23 | return new HtmlNodeNavigator(OwnerDocument, this); 24 | } 25 | 26 | /// 27 | /// Creates an XPathNavigator using the root of this document. 28 | /// 29 | /// 30 | public XPathNavigator CreateRootNavigator() 31 | { 32 | return new HtmlNodeNavigator(OwnerDocument, OwnerDocument.DocumentNode); 33 | } 34 | 35 | /// 36 | /// Selects a list of nodes matching the expression. 37 | /// 38 | /// The XPath expression. 39 | /// An containing a collection of nodes matching the query, or null if no node matched the XPath expression. 40 | public HtmlNodeCollection SelectNodes(string xpath) 41 | { 42 | HtmlNodeCollection list = new HtmlNodeCollection(null); 43 | 44 | HtmlNodeNavigator nav = new HtmlNodeNavigator(OwnerDocument, this); 45 | XPathNodeIterator it = nav.Select(xpath); 46 | while (it.MoveNext()) 47 | { 48 | HtmlNodeNavigator n = (HtmlNodeNavigator) it.Current; 49 | list.Add(n.CurrentNode, false); 50 | } 51 | 52 | if (list.Count == 0 && !OwnerDocument.OptionEmptyCollection) 53 | { 54 | return null; 55 | } 56 | 57 | return list; 58 | } 59 | 60 | /// 61 | /// Selects a list of nodes matching the expression. 62 | /// 63 | /// The XPath expression. 64 | /// An containing a collection of nodes matching the query, or null if no node matched the XPath expression. 65 | public HtmlNodeCollection SelectNodes(XPathExpression xpath) 66 | { 67 | HtmlNodeCollection list = new HtmlNodeCollection(null); 68 | 69 | HtmlNodeNavigator nav = new HtmlNodeNavigator(OwnerDocument, this); 70 | XPathNodeIterator it = nav.Select(xpath); 71 | while (it.MoveNext()) 72 | { 73 | HtmlNodeNavigator n = (HtmlNodeNavigator) it.Current; 74 | list.Add(n.CurrentNode, false); 75 | } 76 | 77 | if (list.Count == 0 && !OwnerDocument.OptionEmptyCollection) 78 | { 79 | return null; 80 | } 81 | 82 | return list; 83 | } 84 | 85 | /// 86 | /// Selects the first XmlNode that matches the expression. 87 | /// 88 | /// The XPath expression. May not be null. 89 | /// The first that matches the XPath query or a null reference if no matching node was found. 90 | public HtmlNode SelectSingleNode(string xpath) 91 | { 92 | if (xpath == null) 93 | { 94 | throw new ArgumentNullException("xpath"); 95 | } 96 | 97 | HtmlNodeNavigator nav = new HtmlNodeNavigator(OwnerDocument, this); 98 | XPathNodeIterator it = nav.Select(xpath); 99 | if (!it.MoveNext()) 100 | { 101 | return null; 102 | } 103 | 104 | HtmlNodeNavigator node = (HtmlNodeNavigator) it.Current; 105 | return node.CurrentNode; 106 | } 107 | 108 | /// 109 | /// Selects the first XmlNode that matches the expression. 110 | /// 111 | /// The XPath expression. 112 | /// An containing a collection of nodes matching the query, or null if no node matched the XPath expression. 113 | public HtmlNode SelectSingleNode(XPathExpression xpath) 114 | { 115 | if (xpath == null) 116 | { 117 | throw new ArgumentNullException("xpath"); 118 | } 119 | 120 | HtmlNodeNavigator nav = new HtmlNodeNavigator(OwnerDocument, this); 121 | XPathNodeIterator it = nav.Select(xpath); 122 | if (!it.MoveNext()) 123 | { 124 | return null; 125 | } 126 | 127 | HtmlNodeNavigator node = (HtmlNodeNavigator)it.Current; 128 | return node.CurrentNode; 129 | } 130 | } 131 | } 132 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlNode.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlNode.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlNodeCollection.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlNodeCollection.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlNodeType.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlNodeType.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlParseError.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlParseError.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlParseErrorCode.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlParseErrorCode.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlTextNode.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlTextNode.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlWeb.Xpath.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if !(NETSTANDARD1_3 || NETSTANDARD1_6) && !METRO 9 | using System; 10 | using System.IO; 11 | using System.Xml; 12 | using System.Xml.Serialization; 13 | using System.Xml.Xsl; 14 | 15 | namespace HtmlAgilityPack 16 | { 17 | public partial class HtmlWeb 18 | { 19 | /// 20 | /// Creates an instance of the given type from the specified Internet resource. 21 | /// 22 | /// The requested URL, such as "http://Myserver/Mypath/Myfile.asp". 23 | /// The URL that specifies the XSLT stylesheet to load. 24 | /// An containing the namespace-qualified arguments used as input to the transform. 25 | /// The requested type. 26 | /// An newly created instance. 27 | public object CreateInstance(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, Type type) 28 | { 29 | return CreateInstance(htmlUrl, xsltUrl, xsltArgs, type, null); 30 | } 31 | 32 | /// 33 | /// Creates an instance of the given type from the specified Internet resource. 34 | /// 35 | /// The requested URL, such as "http://Myserver/Mypath/Myfile.asp". 36 | /// The URL that specifies the XSLT stylesheet to load. 37 | /// An containing the namespace-qualified arguments used as input to the transform. 38 | /// The requested type. 39 | /// A file path where the temporary XML before transformation will be saved. Mostly used for debugging purposes. 40 | /// An newly created instance. 41 | public object CreateInstance(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, Type type, 42 | string xmlPath) 43 | { 44 | StringWriter sw = new StringWriter(); 45 | XmlTextWriter writer = new XmlTextWriter(sw); 46 | if (xsltUrl == null) 47 | { 48 | LoadHtmlAsXml(htmlUrl, writer); 49 | } 50 | else 51 | { 52 | if (xmlPath == null) 53 | { 54 | LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer); 55 | } 56 | else 57 | { 58 | LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer, xmlPath); 59 | } 60 | } 61 | 62 | writer.Flush(); 63 | StringReader sr = new StringReader(sw.ToString()); 64 | XmlTextReader reader = new XmlTextReader(sr); 65 | XmlSerializer serializer = new XmlSerializer(type); 66 | object o; 67 | try 68 | { 69 | o = serializer.Deserialize(reader); 70 | } 71 | catch (InvalidOperationException ex) 72 | { 73 | throw new Exception(ex + ", --- xml:" + sw); 74 | } 75 | 76 | return o; 77 | } 78 | 79 | /// 80 | /// Loads an HTML document from an Internet resource and saves it to the specified XmlTextWriter, after an XSLT transformation. 81 | /// 82 | /// The requested URL, such as "http://Myserver/Mypath/Myfile.asp". 83 | /// The URL that specifies the XSLT stylesheet to load. 84 | /// An XsltArgumentList containing the namespace-qualified arguments used as input to the transform. 85 | /// The XmlTextWriter to which you want to save. 86 | public void LoadHtmlAsXml(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, XmlTextWriter writer) 87 | { 88 | LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer, null); 89 | } 90 | 91 | /// 92 | /// Loads an HTML document from an Internet resource and saves it to the specified XmlTextWriter, after an XSLT transformation. 93 | /// 94 | /// The requested URL, such as "http://Myserver/Mypath/Myfile.asp". May not be null. 95 | /// The URL that specifies the XSLT stylesheet to load. 96 | /// An XsltArgumentList containing the namespace-qualified arguments used as input to the transform. 97 | /// The XmlTextWriter to which you want to save. 98 | /// A file path where the temporary XML before transformation will be saved. Mostly used for debugging purposes. 99 | public void LoadHtmlAsXml(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, XmlTextWriter writer, 100 | string xmlPath) 101 | { 102 | if (htmlUrl == null) 103 | { 104 | throw new ArgumentNullException("htmlUrl"); 105 | } 106 | 107 | HtmlDocument doc = Load(htmlUrl); 108 | 109 | if (xmlPath != null) 110 | { 111 | XmlTextWriter w = new XmlTextWriter(xmlPath, doc.Encoding); 112 | doc.Save(w); 113 | w.Close(); 114 | } 115 | 116 | if (xsltArgs == null) 117 | { 118 | xsltArgs = new XsltArgumentList(); 119 | } 120 | 121 | // add some useful variables to the xslt doc 122 | xsltArgs.AddParam("url", "", htmlUrl); 123 | xsltArgs.AddParam("requestDuration", "", RequestDuration); 124 | xsltArgs.AddParam("fromCache", "", FromCache); 125 | 126 | XslCompiledTransform xslt = new XslCompiledTransform(); 127 | xslt.Load(xsltUrl); 128 | xslt.Transform(doc, xsltArgs, writer); 129 | } 130 | } 131 | } 132 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlWeb.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlWeb.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/HtmlWebException.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/HtmlWebException.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/IOLibrary.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/IOLibrary.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/InvalidProgramException.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if METRO 9 | 10 | using System.Runtime.InteropServices; 11 | 12 | namespace System 13 | { 14 | /// 15 | /// The exception that is thrown when a program contains invalid Microsoft intermediate language (MSIL) or metadata. Generally this indicates a bug in the compiler that generated the program. 16 | /// 17 | /// 2 18 | [ComVisible(true)] 19 | public sealed class InvalidProgramException : Exception 20 | { 21 | /// 22 | /// Initializes a new instance of the class with default properties. 23 | /// 24 | public InvalidProgramException() 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class with a specified error message. 30 | /// 31 | /// The error message that explains the reason for the exception. 32 | public InvalidProgramException(string message) : base(message) 33 | { 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. 38 | /// 39 | /// The error message that explains the reason for the exception. The exception that is the cause of the current exception. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. 40 | public InvalidProgramException(string message, Exception inner) : base(message, inner) 41 | { 42 | } 43 | } 44 | } 45 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/Metro/HtmlWeb.cs: -------------------------------------------------------------------------------- 1 | #if METRO 2 | using System; 3 | using System.IO; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace HtmlAgilityPack 10 | { 11 | /// 12 | /// Used for downloading and parsing html from the internet 13 | /// 14 | public class HtmlWeb 15 | { 16 | /// 17 | /// Allows for setting document defaults before loading 18 | /// 19 | public Action PreHandleDocument { get; set; } 20 | 21 | #region Instance Methods 22 | 23 | /// 24 | /// Begins the process of downloading an internet resource 25 | /// 26 | /// Url to the html document 27 | public async Task LoadFromWebAsync(string url) 28 | { 29 | return await LoadFromWebAsync(new Uri(url), null, null); 30 | } 31 | 32 | /// 33 | /// Begins the process of downloading an internet resource 34 | /// 35 | /// Url to the html document 36 | /// The encoding to use while downloading the document 37 | public async Task LoadFromWebAsync(string url, Encoding encoding) 38 | { 39 | return await LoadFromWebAsync(new Uri(url), encoding, null); 40 | } 41 | 42 | /// 43 | /// Begins the process of downloading an internet resource 44 | /// 45 | /// Url to the html document 46 | /// The encoding to use while downloading the document 47 | /// Username to use for credentials in the web request 48 | /// Password to use for credentials in the web request 49 | public async Task LoadFromWebAsync(string url, Encoding encoding, string userName, string password) 50 | { 51 | return await LoadFromWebAsync(new Uri(url), encoding, new NetworkCredential(userName, password)); 52 | } 53 | 54 | /// 55 | /// Begins the process of downloading an internet resource 56 | /// 57 | /// Url to the html document 58 | /// The encoding to use while downloading the document 59 | /// Username to use for credentials in the web request 60 | /// Password to use for credentials in the web request 61 | /// Domain to use for credentials in the web request 62 | public async Task LoadFromWebAsync(string url, Encoding encoding, string userName, string password, string domain) 63 | { 64 | return await LoadFromWebAsync(new Uri(url), encoding, new NetworkCredential(userName, password, domain)); 65 | } 66 | 67 | /// 68 | /// Begins the process of downloading an internet resource 69 | /// 70 | /// Url to the html document 71 | /// Username to use for credentials in the web request 72 | /// Password to use for credentials in the web request 73 | /// Domain to use for credentials in the web request 74 | public async Task LoadFromWebAsync(string url, string userName, string password, string domain) 75 | { 76 | return await LoadFromWebAsync(new Uri(url), null, new NetworkCredential(userName, password, domain)); 77 | } 78 | 79 | /// 80 | /// Begins the process of downloading an internet resource 81 | /// 82 | /// Url to the html document 83 | /// Username to use for credentials in the web request 84 | /// Password to use for credentials in the web request 85 | public async Task LoadFromWebAsync(string url, string userName, string password) 86 | { 87 | return await LoadFromWebAsync(new Uri(url), null, new NetworkCredential(userName, password)); 88 | } 89 | 90 | /// 91 | /// Begins the process of downloading an internet resource 92 | /// 93 | /// Url to the html document 94 | /// The credentials to use for authenticating the web request 95 | public async Task LoadFromWebAsync(string url, NetworkCredential credentials) 96 | { 97 | return await LoadFromWebAsync(new Uri(url), null, credentials); 98 | } 99 | 100 | /// 101 | /// Begins the process of downloading an internet resource 102 | /// 103 | /// Url to the html document 104 | /// The encoding to use while downloading the document 105 | /// The credentials to use for authenticating the web request 106 | public async Task LoadFromWebAsync(Uri uri, Encoding encoding, NetworkCredential credentials) 107 | { 108 | var clientHandler = new HttpClientHandler(); 109 | if (credentials == null) 110 | clientHandler.UseDefaultCredentials = true; 111 | else 112 | clientHandler.Credentials = credentials; 113 | 114 | var client = new HttpClient(clientHandler); 115 | 116 | var e = await client.GetAsync(uri); 117 | if (e.StatusCode == HttpStatusCode.OK) 118 | { 119 | var html = string.Empty; 120 | if (encoding != null) 121 | { 122 | using (var sr = new StreamReader(await e.Content.ReadAsStreamAsync(), encoding)) 123 | { 124 | html = sr.ReadToEnd(); 125 | } 126 | } 127 | else 128 | html = await e.Content.ReadAsStringAsync(); 129 | 130 | var doc = new HtmlDocument(); 131 | if (PreHandleDocument != null) 132 | PreHandleDocument(doc); 133 | doc.LoadHtml(html); 134 | return doc; 135 | } 136 | 137 | throw new Exception("Error downloading html"); 138 | } 139 | 140 | #endregion 141 | } 142 | } 143 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/Metro/InvalidProgramException.cs: -------------------------------------------------------------------------------- 1 | #if METRO 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace HtmlAgilityPack 9 | { 10 | public class InvalidProgramException : System.Exception 11 | { 12 | public InvalidProgramException(string message) 13 | : base(message) 14 | { 15 | } 16 | } 17 | } 18 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocument.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocument.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocumentCodeFragment.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocumentCodeFragment.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocumentFragment.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocumentFragment.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocumentFragmentList.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocumentFragmentList.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocumentFragmentType.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocumentFragmentType.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/MixedCodeDocumentTextFragment.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/MixedCodeDocumentTextFragment.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/NameValuePair.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | #if METRO 9 | namespace HtmlAgilityPack 10 | { 11 | internal class NameValuePair 12 | { 13 | #region Fields 14 | 15 | internal readonly string Name; 16 | internal string Value; 17 | 18 | #endregion 19 | 20 | #region Constructors 21 | 22 | internal NameValuePair() 23 | { 24 | } 25 | 26 | internal NameValuePair(string name) 27 | : 28 | this() 29 | { 30 | Name = name; 31 | } 32 | 33 | internal NameValuePair(string name, string value) 34 | : 35 | this(name) 36 | { 37 | Value = value; 38 | } 39 | 40 | #endregion 41 | } 42 | } 43 | #endif -------------------------------------------------------------------------------- /HtmlAgilityPack/NameValuePairList.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/NameValuePairList.cs -------------------------------------------------------------------------------- /HtmlAgilityPack/Trace.FullFramework.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | namespace HtmlAgilityPack 9 | { 10 | partial class Trace 11 | { 12 | partial void WriteLineIntern(string message, string category) 13 | { 14 | System.Diagnostics.Debug.WriteLine(message, category); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /HtmlAgilityPack/Trace.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | namespace HtmlAgilityPack 9 | { 10 | internal partial class Trace 11 | { 12 | internal static Trace _current; 13 | 14 | internal static Trace Current 15 | { 16 | get 17 | { 18 | if (_current == null) 19 | _current = new Trace(); 20 | return _current; 21 | } 22 | } 23 | 24 | partial void WriteLineIntern(string message, string category); 25 | 26 | public static void WriteLine(string message, string category) 27 | { 28 | Current.WriteLineIntern(message, category); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /HtmlAgilityPack/Utilities.cs: -------------------------------------------------------------------------------- 1 | // Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. 2 | // Website & Documentation: http://html-agility-pack.net 3 | // Forum & Issues: https://github.com/zzzprojects/html-agility-pack 4 | // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE 5 | // More projects: http://www.zzzprojects.com/ 6 | // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel; 11 | 12 | namespace HtmlAgilityPack 13 | { 14 | internal static class Utilities 15 | { 16 | public static TValue GetDictionaryValueOrDefault(Dictionary dict, TKey key, TValue defaultValue = default(TValue)) where TKey : class 17 | { 18 | TValue value; 19 | if (!dict.TryGetValue(key, out value)) 20 | return defaultValue; 21 | return value; 22 | } 23 | 24 | #if !(METRO || NETSTANDARD1_3 || NETSTANDARD1_6) 25 | internal static object To(this Object @this, Type type) 26 | { 27 | if (@this != null) 28 | { 29 | Type targetType = type; 30 | 31 | if (@this.GetType() == targetType) 32 | { 33 | return @this; 34 | } 35 | 36 | TypeConverter converter = TypeDescriptor.GetConverter(@this); 37 | if (converter != null) 38 | { 39 | if (converter.CanConvertTo(targetType)) 40 | { 41 | return converter.ConvertTo(@this, targetType); 42 | } 43 | } 44 | 45 | converter = TypeDescriptor.GetConverter(targetType); 46 | if (converter != null) 47 | { 48 | if (converter.CanConvertFrom(@this.GetType())) 49 | { 50 | return converter.ConvertFrom(@this); 51 | } 52 | } 53 | 54 | if (@this == DBNull.Value) 55 | { 56 | return null; 57 | } 58 | } 59 | 60 | return @this; 61 | } 62 | #endif 63 | } 64 | } -------------------------------------------------------------------------------- /HtmlAgilityPack/crc32.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/HtmlAgilityPack/crc32.cs -------------------------------------------------------------------------------- /IconChooser.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | using System; 23 | using System.Drawing; 24 | 25 | namespace CustomIconDashboarderPlugin 26 | { 27 | 28 | 29 | /// 30 | /// Description of IconChooser. 31 | /// 32 | public class IconChooser 33 | { 34 | 35 | public BestIconFinder Bif {get; private set; } 36 | 37 | public Image ChoosenIcon { 38 | get { 39 | if ((Bif.ListImageInfo != null) && 40 | ( Bif.ListImageInfo.Count > ChoosenIndex) && 41 | ( ChoosenIndex >= 0) ) { 42 | return Bif.ListImageInfo[ChoosenIndex].ImgData; 43 | } 44 | else { 45 | return null; 46 | } 47 | } 48 | 49 | } 50 | 51 | public Int32 ChoosenIndex {get; set;} 52 | 53 | public IconChooser(BestIconFinder bif) 54 | { 55 | this.Bif = bif; 56 | this.ChoosenIndex = bif.IndexOfBestImage; 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /IconStatsHandler.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | using System; 23 | using System.Collections; 24 | using System.Collections.Generic; 25 | using System.Diagnostics; 26 | using KeePassLib.Delegates; 27 | using KeePassLib; 28 | using LomsonLib.Utility; 29 | 30 | namespace CustomIconDashboarderPlugin 31 | { 32 | 33 | /// 34 | /// Description of Class1. 35 | /// 36 | public class IconStatsHandler 37 | { 38 | 39 | private Dictionary m_dicCustomIconsStats = null; 40 | private Dictionary m_dicStandardIconsStats = null; 41 | private bool m_isInitialized; 42 | 43 | public IconStatsHandler() 44 | { 45 | m_dicCustomIconsStats = new Dictionary(); 46 | m_dicStandardIconsStats = new Dictionary(); 47 | } 48 | 49 | public void Initialize( PwDatabase db) { 50 | 51 | Debug.Assert( m_dicCustomIconsStats != null ); if (m_dicCustomIconsStats == null) throw new InvalidOperationException(); 52 | Debug.Assert( m_dicStandardIconsStats != null ); if (m_dicStandardIconsStats == null) throw new InvalidOperationException(); 53 | 54 | 55 | GroupHandler gh = delegate(PwGroup pg) 56 | { 57 | if ( !(pg.CustomIconUuid.Equals(PwUuid.Zero) ) ){ 58 | if (!(m_dicCustomIconsStats.ContainsKey( pg.CustomIconUuid)) ){ 59 | m_dicCustomIconsStats.Add( pg.CustomIconUuid, new IconStats()); 60 | } 61 | m_dicCustomIconsStats[ pg.CustomIconUuid ].nbInGroups += 1; 62 | m_dicCustomIconsStats[ pg.CustomIconUuid ].listGroups.Add( pg); 63 | } 64 | else { 65 | if (!(m_dicStandardIconsStats.ContainsKey( pg.IconId)) ){ 66 | m_dicStandardIconsStats.Add( pg.IconId, new IconStats()); 67 | } 68 | m_dicStandardIconsStats[ pg.IconId ].nbInGroups += 1; 69 | m_dicStandardIconsStats[ pg.IconId ].listGroups.Add( pg); 70 | } 71 | 72 | return true; 73 | }; 74 | 75 | String urlFieldValue; 76 | Uri siteUri; 77 | List uriList; 78 | EntryHandler eh = delegate(PwEntry pe) 79 | { 80 | if (!(pe.CustomIconUuid.Equals(PwUuid.Zero))) { 81 | 82 | if (!(m_dicCustomIconsStats.ContainsKey(pe.CustomIconUuid))) { 83 | m_dicCustomIconsStats.Add(pe.CustomIconUuid, new IconStats()); 84 | } 85 | m_dicCustomIconsStats[pe.CustomIconUuid].nbInEntries += 1; 86 | m_dicCustomIconsStats[pe.CustomIconUuid].listEntries.Add(pe); 87 | uriList = m_dicCustomIconsStats[pe.CustomIconUuid].listUris; 88 | 89 | } 90 | else { 91 | if (!(m_dicStandardIconsStats.ContainsKey(pe.IconId))) { 92 | m_dicStandardIconsStats.Add(pe.IconId, new IconStats()); 93 | } 94 | m_dicStandardIconsStats[pe.IconId].nbInEntries += 1; 95 | m_dicStandardIconsStats[pe.IconId].listEntries.Add(pe); 96 | uriList = m_dicStandardIconsStats[pe.IconId].listUris; 97 | 98 | } 99 | 100 | // Get Uri 101 | urlFieldValue = pe.Strings.ReadSafe(PwDefs.UrlField); 102 | if (!string.IsNullOrEmpty(urlFieldValue)) { 103 | try { 104 | urlFieldValue = URLUtility.addUrlHttpPrefix(urlFieldValue); 105 | bool urlWellFFormatted = Uri.TryCreate(urlFieldValue, UriKind.Absolute, out siteUri); 106 | 107 | if (urlWellFFormatted) { 108 | if ((siteUri.Scheme.ToLower() == "http") || 109 | (siteUri.Scheme.ToLower() == "https")) 110 | { 111 | uriList.Add(siteUri); 112 | } 113 | } 114 | } 115 | catch (UriFormatException e) 116 | { 117 | Debug.Write(String.Format("URIFormatException during parsing uri of entry = {0}", e.Message)); 118 | } 119 | catch (Exception) { }; 120 | } 121 | 122 | return true; 123 | }; 124 | 125 | gh( db.RootGroup ); 126 | db.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); 127 | 128 | m_isInitialized = true; 129 | } 130 | 131 | 132 | /// 133 | /// Get number of usage of pci in groups for Custom Icon 134 | /// 135 | /// 136 | /// number of usage of pci in groups 137 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Nb")] 138 | public int GetNbUsageInGroups(PwCustomIcon pci) { 139 | Debug.Assert( m_isInitialized); 140 | 141 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 142 | return m_dicCustomIconsStats[pci.Uuid].nbInGroups; 143 | 144 | } 145 | else { 146 | return 0; 147 | } 148 | } 149 | 150 | /// 151 | /// Get number of usage of pci in entries for Custom Icon 152 | /// 153 | /// 154 | /// number of usage of pci in entries 155 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Nb")] 156 | public int GetNbUsageInEntries(PwCustomIcon pci) { 157 | Debug.Assert( m_isInitialized); 158 | 159 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 160 | return m_dicCustomIconsStats[pci.Uuid].nbInEntries; 161 | 162 | } 163 | else { 164 | return 0; 165 | } 166 | } 167 | 168 | /// 169 | /// Get List of entries for Custom Icon 170 | /// 171 | /// 172 | /// List of entries 173 | public ICollection GetListEntriesForPci( PwCustomIcon pci) { 174 | Debug.Assert( m_isInitialized); 175 | 176 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 177 | return m_dicCustomIconsStats[pci.Uuid].listEntries; 178 | 179 | } 180 | else { 181 | return new List(); 182 | } 183 | } 184 | 185 | /// 186 | /// Get List of entries for Standard Icon 187 | /// 188 | /// 189 | /// List of entries 190 | public ICollection GetListEntriesForStandardIcon( PwIcon stdIcon) { 191 | Debug.Assert( m_isInitialized); 192 | 193 | if ( m_dicStandardIconsStats.ContainsKey( stdIcon ) ) { 194 | return m_dicStandardIconsStats[stdIcon].listEntries; 195 | 196 | } 197 | else { 198 | return new List(); 199 | } 200 | } 201 | 202 | 203 | // 204 | /// Get List of entries for Custom Icon 205 | /// 206 | /// 207 | /// List of entries 208 | public ICollection GetListEntriesForUuid( PwUuid puuid) { 209 | Debug.Assert( m_isInitialized); 210 | 211 | if ( m_dicCustomIconsStats.ContainsKey( puuid ) ) { 212 | return m_dicCustomIconsStats[puuid].listEntries; 213 | 214 | } 215 | else { 216 | return new List(); 217 | } 218 | } 219 | 220 | /// 221 | /// Get List of groups for Custom Icon 222 | /// 223 | /// 224 | /// List of groups 225 | public ICollection GetListGroupsForPci( PwCustomIcon pci) { 226 | Debug.Assert( m_isInitialized); 227 | 228 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 229 | return m_dicCustomIconsStats[pci.Uuid].listGroups; 230 | 231 | } 232 | else { 233 | return new List(); 234 | } 235 | } 236 | 237 | /// 238 | /// Get List of groups for Standard Icon 239 | /// 240 | /// 241 | /// List of groups 242 | public ICollection GetListGroupsForStandardIcon( PwIcon stdIcon) { 243 | Debug.Assert( m_isInitialized); 244 | 245 | if ( m_dicStandardIconsStats.ContainsKey( stdIcon ) ) { 246 | return m_dicStandardIconsStats[stdIcon].listGroups; 247 | 248 | } 249 | else { 250 | return new List(); 251 | } 252 | } 253 | 254 | 255 | public ICollection GetListGroupsFromUuid( PwUuid puuid) { 256 | Debug.Assert( m_isInitialized); 257 | 258 | if ( m_dicCustomIconsStats.ContainsKey( puuid ) ) { 259 | return m_dicCustomIconsStats[puuid].listGroups; 260 | 261 | } 262 | else { 263 | return new List(); 264 | } 265 | } 266 | 267 | /// 268 | /// Get List of Uris 269 | /// 270 | /// 271 | /// List of groups 272 | public ICollection GetListUris( PwCustomIcon pci) { 273 | Debug.Assert( m_isInitialized); 274 | 275 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 276 | return m_dicCustomIconsStats[pci.Uuid].listUris; 277 | 278 | } 279 | else { 280 | return new List(); 281 | } 282 | } 283 | 284 | /// 285 | /// Get number of urls of pci in entries 286 | /// 287 | /// 288 | /// number of urls of pci in entries 289 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Nb")] 290 | public int GetNbUrlsInEntries(PwCustomIcon pci) { 291 | Debug.Assert( m_isInitialized); 292 | 293 | if ( m_dicCustomIconsStats.ContainsKey( pci.Uuid ) ) { 294 | return m_dicCustomIconsStats[pci.Uuid].listUris.Count; 295 | 296 | } 297 | else { 298 | return 0; 299 | } 300 | } 301 | 302 | 303 | private class IconStats { 304 | 305 | public int nbInGroups { get; set ;} 306 | public int nbInEntries { get; set ;} 307 | public List listEntries {get; set;} 308 | public List listGroups {get; set; } 309 | public List listUris {get; set; } 310 | 311 | public IconStats () { 312 | nbInGroups = 0; 313 | nbInEntries = 0; 314 | listEntries = new List(); 315 | listGroups = new List(); 316 | listUris = new List(); 317 | } 318 | } 319 | } 320 | 321 | 322 | } 323 | -------------------------------------------------------------------------------- /ImageInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Drawing; 23 | 24 | namespace CustomIconDashboarderPlugin 25 | { 26 | /// 27 | /// Description of ImageInfo. 28 | /// 29 | public class ImageInfo 30 | { 31 | public Image ImgData {get; private set; } 32 | public String Url {get; private set; } 33 | 34 | public ImageInfo(Image imgData, String url) 35 | { 36 | this.ImgData = imgData; 37 | this.Url = url; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /KPCIDConfig.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using KeePass.App.Configuration; 23 | using KeePass.Plugins; 24 | 25 | namespace CustomIconDashboarderPlugin 26 | { 27 | /// 28 | /// Description of KPCIDConfig. 29 | /// 30 | public class KPCIDConfig 31 | { 32 | 33 | private const String XMLPATH_PLUGINNAME = "KPCID"; 34 | 35 | private const String XMLPATH_DASHBOARD_STATE = 36 | XMLPATH_PLUGINNAME + ".dashboardState"; 37 | private const String VALUE_STATE_MAXIMIZED = "Maximized"; 38 | private const String VALUE_STATE_NORMAL = "Normal"; 39 | 40 | private const String XMLPATH_DASHBOARD_SIZE = 41 | XMLPATH_PLUGINNAME + ".dashboardSize"; 42 | 43 | private const String XMLPATH_DASHBOARD_POSITION = 44 | XMLPATH_PLUGINNAME + ".dashboardPosition"; 45 | 46 | private const String XMLPATH_DASHBOARD_DEBUGLEVEL = 47 | XMLPATH_PLUGINNAME + ".debugLevel"; // 0 or 1 for now 48 | 49 | private AceCustomConfig m_config = null; 50 | 51 | public KPCIDConfig(IPluginHost host) 52 | { 53 | m_config = host.CustomConfig; 54 | } 55 | 56 | public System.Windows.Forms.FormWindowState DashboardState { 57 | get { 58 | string strState = m_config.GetString(XMLPATH_DASHBOARD_STATE,""); 59 | return strState.ToUpper() == VALUE_STATE_MAXIMIZED.ToUpper() 60 | ? System.Windows.Forms.FormWindowState.Maximized 61 | : System.Windows.Forms.FormWindowState.Normal; 62 | } 63 | set { 64 | m_config.SetString(XMLPATH_DASHBOARD_STATE, 65 | value == System.Windows.Forms.FormWindowState.Maximized 66 | ? VALUE_STATE_MAXIMIZED 67 | : VALUE_STATE_NORMAL 68 | ); 69 | } 70 | } 71 | 72 | public Size DashboardSize { 73 | get { 74 | string strSize = m_config.GetString(XMLPATH_DASHBOARD_SIZE,""); 75 | Size readSize = Size.ParseSize(strSize); 76 | return readSize; 77 | } 78 | set { 79 | if (!value.IsNull) 80 | m_config.SetString(XMLPATH_DASHBOARD_SIZE, value.ToString()); 81 | } 82 | } 83 | 84 | public Size DashboardPosition { 85 | get { 86 | string strPosition = m_config.GetString(XMLPATH_DASHBOARD_POSITION,""); 87 | Size readPosition = Size.ParseSize(strPosition); 88 | return readPosition; 89 | } 90 | set { 91 | if (!value.IsNull) 92 | m_config.SetString(XMLPATH_DASHBOARD_POSITION, value.ToString()); 93 | } 94 | } 95 | 96 | public byte DebugLevel 97 | { 98 | get 99 | { 100 | string strDebugLevel = m_config.GetString(XMLPATH_DASHBOARD_DEBUGLEVEL, ""); 101 | byte byteDebugLevel = strDebugLevel == "0" ? (byte)0 : strDebugLevel == "1" ? (byte)1 : (byte)0; 102 | return byteDebugLevel; 103 | } 104 | set 105 | { 106 | // Assume that value is correctly formatted 107 | m_config.SetString(XMLPATH_DASHBOARD_DEBUGLEVEL, value.ToString()); 108 | } 109 | } 110 | 111 | 112 | public class Size 113 | { 114 | public int X {get; private set;} 115 | public int Y {get; private set;} 116 | public bool IsNull {get; private set;} 117 | 118 | public Size(int x, int y) 119 | { 120 | this.X = x; 121 | this.Y = y; 122 | this.IsNull = false; 123 | } 124 | 125 | // Null Size 126 | public Size() 127 | { 128 | this.X = 0; this.Y = 0; 129 | this.IsNull = true; 130 | } 131 | 132 | public override String ToString() 133 | { 134 | if (!this.IsNull) 135 | return this.X.ToString("D") + "x" + this.Y.ToString("D"); 136 | else 137 | return "NULL"; 138 | } 139 | 140 | public static Size ParseSize(string str) 141 | { 142 | string[] sizeparts = str.Split('x'); 143 | if (sizeparts.Length != 2) 144 | return new Size(); 145 | 146 | string strSizeX = sizeparts[0].Trim(); 147 | string strSizeY = sizeparts[1].Trim(); 148 | if ( (string.IsNullOrEmpty(strSizeX)) 149 | || (string.IsNullOrEmpty(strSizeY) ) ) { 150 | return new Size(); 151 | } 152 | 153 | bool parseOKX, parseOKY; 154 | int intSizeX; parseOKX = int.TryParse( strSizeX, out intSizeX); 155 | int intSizeY; parseOKY = int.TryParse( strSizeY, out intSizeY); 156 | 157 | if (!parseOKX || !parseOKY) { 158 | return new Size(); 159 | } 160 | 161 | return new Size(intSizeX, intSizeY); 162 | } 163 | 164 | } 165 | 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | KeePass Custom Icon Dashboarder 2 | ------------------------------- 3 | 4 | This program is distributed under the terms of the GNU General Public 5 | License version 2 or later. License is available here: 6 | https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html 7 | 8 | 9 | HtmlAgilityPack 10 | --------------- 11 | The library HtmlAgilityPack v1.11.12 is used. 12 | 13 | Original version is available here: 14 | https://github.com/zzzprojects/html-agility-pack 15 | Minor modifications has been performed to use it as a KeePass Plugin. 16 | 17 | This library is distributed under the terms of the MIT License (MIT) 18 | Permission is hereby granted, free of charge, to any person obtaining a copy 19 | of this software and associated documentation files (the "Software"), to deal 20 | in the Software without restriction, including without limitation the rights 21 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the Software is 23 | furnished to do so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in all 26 | copies or substantial portions of the Software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34 | SOFTWARE. -------------------------------------------------------------------------------- /LomsonLib/Collections/CollectionUtil.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2014 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Collections; 23 | using System.Collections.Generic; 24 | using System.Diagnostics; 25 | 26 | using LomsonLib.LomsonDebug; 27 | 28 | /* 29 | * LomsonLib.UI 30 | * 31 | * Version 1.1 32 | * See ListViewLayoutManager.cs for release notes 33 | */ 34 | 35 | 36 | namespace LomsonLib.Collections 37 | { 38 | /// 39 | /// Description of CollectionUtil. 40 | /// 41 | public class CollectionUtil 42 | { 43 | 44 | /// 45 | /// Get union of col1 and col2 with no duplicate entries. Comparison method is the default one; 46 | /// 47 | public static ICollection Union(ICollection col1, ICollection col2) { 48 | List result = new List(); 49 | 50 | result.AddRange(col1); 51 | 52 | foreach (T readValue in col2) { 53 | if (!result.Contains(readValue)) { 54 | result.Add(readValue); 55 | } 56 | } 57 | 58 | return result; 59 | } 60 | 61 | /// 62 | /// Get collection with all element present in col1 and not in col2 63 | /// 64 | public static ICollection OnlyInFirstCollection(ICollection col1, ICollection col2, Equals comparer) { 65 | 66 | List result = new List(); 67 | result.AddRange(col1); 68 | 69 | foreach( T readValue in col2) { 70 | T element = GetElementFromCollection( col2, readValue, comparer) ; 71 | result.Remove(element); 72 | } 73 | 74 | return result; 75 | } 76 | 77 | /// 78 | /// Get refElement in col ? default(T) if it does not exist 79 | /// 80 | public static T GetElementFromCollection(ICollection col, T refElement, Equals comparer ) { 81 | bool exists = false; 82 | 83 | IEnumerator enumeratorCol = col.GetEnumerator(); 84 | T readT = default(T); 85 | while ((enumeratorCol.MoveNext() ) && (!exists)) { 86 | readT = enumeratorCol.Current; 87 | exists = comparer(refElement, readT); 88 | } 89 | 90 | if (!exists) { 91 | return default(T); 92 | } 93 | else { 94 | return readT; 95 | } 96 | } 97 | 98 | /// 99 | /// Get array from ICollection 100 | /// 101 | public static T[] ICollectionToArray(ICollection col) { 102 | T[] result = new T[col.Count]; 103 | int i = 0; 104 | foreach (T readValue in col) { 105 | result[i] = readValue; 106 | i++; 107 | } 108 | return result; 109 | } 110 | } 111 | 112 | 113 | public delegate bool Equals(T obj1, T obj2); 114 | } 115 | -------------------------------------------------------------------------------- /LomsonLib/LomsonDebug/LomsonDebugLib.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2014 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.ComponentModel; 23 | using System.Diagnostics; 24 | using System.Windows.Forms; 25 | 26 | using System.Reflection; 27 | 28 | 29 | /* 30 | * LomsonLib.UI 31 | * 32 | * Version 1.2.1 33 | * Implement some FxCop considerations 34 | * 35 | * Version 1.1 36 | * See ListViewLayoutManager.cs for release notes 37 | */ 38 | 39 | namespace LomsonLib.LomsonDebug 40 | { 41 | /// 42 | /// Description of LomsonDebug. 43 | /// 44 | public sealed class LomsonDebug 45 | { 46 | private LomsonDebug() { 47 | 48 | } 49 | 50 | /// 51 | /// Write a timestamp message on debug output 52 | /// 53 | /// StopWatch 54 | /// Message to display 55 | public static void TimeStampedWrite(Stopwatch sw, String message) { 56 | Debug.WriteLine(sw.ElapsedMilliseconds.ToString() + "ms - " + message); 57 | } 58 | 59 | /// 60 | /// Print all fields - public and not public on debug output 61 | /// 62 | public static void WriteAllFieldOnDebugOutput( object classInstance ) { 63 | Debug.WriteLine("Entering WriteAllFieldOnDebugOutput"); 64 | Debug.Indent(); 65 | 66 | Type classType = classInstance.GetType(); 67 | FieldInfo [] test = classType.GetFields( 68 | BindingFlags.Instance | 69 | BindingFlags.Static | 70 | BindingFlags.GetField | 71 | BindingFlags.NonPublic | 72 | BindingFlags.Public ); 73 | 74 | Debug.Indent(); 75 | foreach (FieldInfo fi in test) { 76 | Debug.WriteLine("Field = " + 77 | (fi.Name + " ").Substring(0,50) + 78 | fi.FieldType.ToString()); 79 | } 80 | Debug.Unindent(); 81 | Debug.Unindent(); 82 | Debug.WriteLine("Ending WriteAllFieldOnDebugOutput"); 83 | } 84 | 85 | 86 | 87 | public static void WriteAllMethodFromAnEvent( object classInstance, string eventName, bool onelinePrinting) { 88 | if ( !onelinePrinting) { 89 | Debug.Indent(); 90 | Debug.WriteLine("Entering WriteAllMethodFromAnEvent - eventName = " + eventName); 91 | } 92 | 93 | 94 | Delegate ehl = (LomsonDebug.GetEventHandler(classInstance, eventName)) as Delegate; 95 | if (ehl != null) { 96 | 97 | MethodInfo method = ehl.Method; 98 | string name = ehl.Target == null ? "" : ehl.Target.ToString(); 99 | if (ehl.Target is Control) name = ((Control)ehl.Target).Name; 100 | 101 | if (!onelinePrinting) 102 | Debug.WriteLine(name + "; " + method.DeclaringType.Name + "." + method.Name); 103 | else 104 | Debug.WriteLine("[Event]" + eventName + " - " + name + "; " + method.DeclaringType.Name + "." + method.Name); 105 | 106 | Debug.Unindent(); 107 | } 108 | 109 | if ( !onelinePrinting) { 110 | Debug.Unindent(); 111 | if ( !onelinePrinting) Debug.WriteLine("Ending WriteAllMethodFromAnEvent"); 112 | } 113 | } 114 | 115 | public static void WriteAllMethodFromAnEvent( object classInstance, string eventName) { 116 | WriteAllMethodFromAnEvent( classInstance, eventName, false); 117 | } 118 | 119 | 120 | /// 121 | /// Get handler from event name 122 | /// 123 | /// 124 | /// 125 | /// 126 | public static object GetEventHandler(object classInstance, string eventName) 127 | { 128 | Type classType = classInstance.GetType(); 129 | 130 | try{ 131 | object eventDelegate = null; 132 | do { 133 | FieldInfo eventField = 134 | classType.GetField(eventName, 135 | BindingFlags.GetField 136 | | BindingFlags.NonPublic 137 | | BindingFlags.Instance); 138 | try{ 139 | eventDelegate = eventField.GetValue(classInstance); 140 | }catch(Exception){} 141 | classType = classType.BaseType; 142 | } while ( ( eventDelegate == null ) && (classType != null )); 143 | 144 | // eventDelegate will be null if no listeners are attached to the event 145 | if (eventDelegate == null) 146 | { 147 | return null; 148 | } 149 | return eventDelegate; 150 | } catch (Exception e) { 151 | Debug.WriteLine("GetEventHandler - Exception " + e.Message); 152 | return null; 153 | } 154 | 155 | } 156 | 157 | // Sample: http://stackoverflow.com/questions/660480/determine-list-of-event-handlers-bound-to-event 158 | // Form form = new MyForm(); 159 | // EventHandlerList events = (EventHandlerList)typeof(Component) 160 | // .GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance) 161 | // .GetValue(form, null); 162 | // object key = typeof(Form) 163 | // .GetField("EVENT_FORMCLOSING", BindingFlags.NonPublic | BindingFlags.Static) 164 | // .GetValue(null); 165 | // 166 | // Delegate handlers = events[key]; 167 | // foreach (Delegate handler in handlers.GetInvocationList()) 168 | // { 169 | // MethodInfo method = handler.Method; 170 | // string name = handler.Target == null ? "" : handler.Target.ToString(); 171 | // if (handler.Target is Control) name = ((Control)handler.Target).Name; 172 | // Console.WriteLine(name + "; " + method.DeclaringType.Name + "." + method.Name); 173 | // } 174 | 175 | //http://stackoverflow.com/questions/1129517/c-sharp-how-to-find-if-an-event-is-hooked-up 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /LomsonLib/LomsonLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F61FFD35-4B4A-4A54-84EF-7EA8B3C59B44} 8 | Library 9 | LomsonLib 10 | LomsonLib 11 | v4.5 12 | 512 13 | true 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Component 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {10938016-dee2-4a25-9a5a-8fd3444379ca} 61 | KeePass 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /LomsonLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Les informations générales relatives à un assembly dépendent de 6 | // l'ensemble d'attributs suivant. Pour modifier les informations 7 | // associées à un assembly, changez les valeurs de ces attributs. 8 | [assembly: AssemblyTitle("LomsonLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LomsonLib")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly 17 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de 18 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type. 19 | [assembly: ComVisible(false)] 20 | 21 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM 22 | [assembly: Guid("1fd6031d-ff13-4bb2-aa14-da07406da02c")] 23 | 24 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes : 25 | // 26 | // Version principale 27 | // Version secondaire 28 | // Numéro de build 29 | // Révision 30 | // 31 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut 32 | // en utilisant '*', comme indiqué ci-dessous : 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /LomsonLib/UI/CompatibilityManager.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2015 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | using System; 23 | 24 | using System.Drawing; 25 | using System.Diagnostics; 26 | using System.Reflection; 27 | using System.Collections.Generic; 28 | 29 | using System.Windows.Forms; 30 | using KeePassLib; 31 | 32 | namespace LomsonLib.UI 33 | { 34 | /// 35 | /// Class to manage different version of Keepass. 36 | /// Since version 2.29, HighDPI custom icons are taken into account. 37 | /// New methods have appeared and old methods became obsoletes. 38 | /// This class aims to use new methods when it is possible by avoiding 39 | /// compilation errors. 40 | /// 41 | /// 42 | 43 | /* 44 | * Version 1.2 - 2016/04/04 45 | * Get list of standard icons with High Definitions 46 | * 47 | * Version 1.1 - 26/10/2015 48 | * Use ScaleImage in ResizedImage method 49 | * 50 | * Version 1.0 51 | * Initial Version 52 | */ 53 | 54 | public class CompatibilityManager 55 | { 56 | // KeePass.UI.DpiUtil from version >= 2.27 57 | private static Type TYPE_DpiUtil = null; 58 | 59 | // KeePass.Properties.Resources all version and internal 60 | private static Type TYPE_Properties_Resources = null; 61 | 62 | // PwCustomIcon.GetImage from version >= 2.29 63 | private static MethodInfo METHOD_GetImage_NoParameters = null; 64 | private static MethodInfo METHOD_GetImage_TwoParameters = null; 65 | 66 | 67 | // KeePass.UI.DpiUtil.ScaleIntX from version >= 2.27 68 | // KeePass.UI.DpiUtil.ScaleIntY from version >= 2.27 69 | private static MethodInfo METHOD_ScaleIntX = null; 70 | private static MethodInfo METHOD_ScaleIntY = null; 71 | 72 | // KeePassLib.Utility.GfxUtil.ScaleImage from version >= 2.29 73 | private static MethodInfo METHOD_ScaleImage = null; 74 | 75 | // KeePass.Properties.Resources.Images_Client_HighRes from version >= 2.29 76 | // KeePass.Util.Archive.ImageArchive.Load from version >= 2.29 77 | // KeePass.Util.Archive.ImageArchive from version >= 2.29 78 | private static Type TYPE_ImageArchive = null; 79 | private static object PROPERTYVALUE_Images_Client_HighRes = null; 80 | private static MethodInfo METHOD_ImageArchive_Load = null; 81 | private static MethodInfo METHOD_ImageArchive_GetImages = null; 82 | 83 | private static bool IS_INITIALIZED = false; 84 | 85 | private CompatibilityManager() 86 | { 87 | } 88 | 89 | private static void EnsureInitialize() 90 | { 91 | if (! IS_INITIALIZED) { 92 | METHOD_GetImage_NoParameters = GetMethod( 93 | typeof(KeePassLib.PwCustomIcon).AssemblyQualifiedName, 94 | "GetImage", 95 | new Type[]{ }); 96 | 97 | METHOD_GetImage_TwoParameters = GetMethod( 98 | typeof(KeePassLib.PwCustomIcon).AssemblyQualifiedName, 99 | "GetImage", 100 | new Type[]{ typeof(int), typeof(int) }); 101 | 102 | // Get TYPE_DpiUtil and TYPE_Properties_Resources 103 | foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) 104 | { 105 | if (a.GetName().Name.Equals("KeePass")){ 106 | foreach (var b in a.GetTypes() ) { 107 | if (b.FullName.Equals("KeePass.UI.DpiUtil")) { 108 | TYPE_DpiUtil = b; 109 | } 110 | else if (b.FullName.Equals("KeePass.Properties.Resources")) { 111 | TYPE_Properties_Resources = b; 112 | } 113 | else if (b.FullName.Equals("KeePass.Util.Archive.ImageArchive")) { 114 | TYPE_ImageArchive = b; 115 | } 116 | } 117 | 118 | } 119 | } 120 | Debug.Assert( TYPE_Properties_Resources != null); 121 | 122 | // Get ScaleIntX and ScaleIntY 123 | if (TYPE_DpiUtil != null) { 124 | METHOD_ScaleIntX = GetMethod( 125 | TYPE_DpiUtil.AssemblyQualifiedName, 126 | "ScaleIntX", 127 | new []{ typeof(int) }); 128 | METHOD_ScaleIntY = GetMethod( 129 | TYPE_DpiUtil.AssemblyQualifiedName, 130 | "ScaleIntY", 131 | new []{ typeof(int) }); 132 | } 133 | 134 | 135 | // Get ScaleImage 136 | METHOD_ScaleImage = GetMethod( 137 | typeof(KeePassLib.Utility.GfxUtil).AssemblyQualifiedName, 138 | "ScaleImage", 139 | new Type[]{ typeof(System.Drawing.Image), typeof(int), typeof(int) }); 140 | 141 | // Get Image_Client property Info 142 | PROPERTYVALUE_Images_Client_HighRes = GetPropertyValue( 143 | TYPE_Properties_Resources, 144 | "Images_Client_HighRes"); 145 | 146 | // Method Load of Image Archiver 147 | if (TYPE_ImageArchive != null) { 148 | METHOD_ImageArchive_Load = GetMethod( 149 | TYPE_ImageArchive.AssemblyQualifiedName, 150 | "Load", 151 | new Type[] {typeof( byte[] )} 152 | ); 153 | METHOD_ImageArchive_GetImages = GetMethod( 154 | TYPE_ImageArchive.AssemblyQualifiedName, 155 | "GetImages", 156 | new Type[] {typeof(int), typeof(int), typeof(bool) } 157 | ); 158 | } 159 | 160 | IS_INITIALIZED = true; 161 | } 162 | 163 | AppDomain.CurrentDomain.GetAssemblies(); 164 | } 165 | 166 | /// 167 | /// Get Method from class Name, methodName and parameters 168 | /// 169 | /// Class Name 170 | /// Methode Name 171 | /// Type arrays of parameters 172 | /// 173 | private static MethodInfo GetMethod(string className, string methodName, Type[]parameters) 174 | { 175 | MethodInfo result; 176 | try { 177 | var type = Type.GetType(className,false,false); 178 | result = type.GetMethod(methodName, parameters ); 179 | } 180 | catch (System.Reflection.AmbiguousMatchException) { 181 | result= null; 182 | } 183 | return result; 184 | } 185 | 186 | /// 187 | /// Get Property value from type and propertyName 188 | /// 189 | /// type 190 | /// Property Name 191 | /// 192 | private static object GetPropertyValue(Type type, string propertyName) 193 | { 194 | object result=null; 195 | try { 196 | PropertyInfo prop = type.GetProperty(propertyName, 197 | BindingFlags.Static | 198 | BindingFlags.NonPublic); 199 | 200 | if (prop!=null) { 201 | result = prop.GetValue(null,null); 202 | } 203 | } 204 | catch (System.Reflection.AmbiguousMatchException) { 205 | result= null; 206 | } 207 | return result; 208 | } 209 | 210 | /// 211 | /// Return KeePass.UI.DpiUtil.ScaleIntX if exists (keepass >= 2.28). 212 | /// i if it does not exits 213 | /// NB: KeePass.UI.DpiUtil exists from keepass >= 2.27 214 | /// 215 | /// 216 | /// 217 | public static int ScaleIntX(int i) 218 | { 219 | EnsureInitialize(); 220 | 221 | int result=-1; 222 | 223 | try{ 224 | 225 | if (METHOD_ScaleIntX != null) { 226 | result = (int)METHOD_ScaleIntX.Invoke(null, new Object[]{i}); 227 | } 228 | else { 229 | result = i; 230 | } 231 | } 232 | catch (Exception e) { 233 | Debug.Assert(false, "Error with ScaleIntX: " + e.ToString()); 234 | result= -1; 235 | } 236 | return result; 237 | } 238 | 239 | /// 240 | /// Return KeePass.UI.DpiUtil.ScaleIntY if exists (keepass >= 2.28). 241 | /// i if it does not exits 242 | /// NB: KeePass.UI.DpiUtil exists from keepass >= 2.27 243 | /// 244 | /// 245 | /// 246 | public static int ScaleIntY(int i) 247 | { 248 | int result=-1; 249 | 250 | try{ 251 | 252 | if (METHOD_ScaleIntX != null) { 253 | result = (int)METHOD_ScaleIntY.Invoke(null, new Object[]{i}); 254 | } 255 | else { 256 | result = i; 257 | } 258 | } 259 | catch (Exception e) { 260 | Debug.Assert(false, "Error with ScaleIntY: " + e.ToString()); 261 | result= -1; 262 | } 263 | return result; 264 | } 265 | 266 | /// 267 | /// Get original image (to get Original Width for example) 268 | /// 269 | public static Image GetOriginalImage(PwCustomIcon icon) 270 | { 271 | Image result = null; 272 | EnsureInitialize(); 273 | 274 | if (METHOD_GetImage_NoParameters != null) { 275 | result = METHOD_GetImage_NoParameters.Invoke( 276 | icon, 277 | new Object[] { } ) 278 | as Image; 279 | } 280 | else { 281 | result = icon.GetType().GetProperty("Image").GetValue( 282 | icon, null) as Image; 283 | } 284 | 285 | return result; 286 | 287 | } 288 | 289 | /// 290 | /// Scale Image to fit dimensions (width x height).
291 | /// If version of keepass >= 2.28, use KeePass.UI.ScaleIntX/Y methods 292 | /// If version of keepass >= 2.29, use GetImage to get HighDPI definition 293 | ///
294 | public static Image GetScaledImage(PwCustomIcon icon, int width, int height) 295 | { 296 | Image result = null; 297 | EnsureInitialize(); 298 | 299 | if (METHOD_GetImage_TwoParameters != null) { 300 | result = METHOD_GetImage_TwoParameters.Invoke( 301 | icon, 302 | new Object[] { ScaleIntX(width), ScaleIntY(height) } ) 303 | as Image; 304 | } 305 | else { 306 | result = ResizedImage( 307 | icon.GetType().GetProperty("Image").GetValue( 308 | icon, null) as Image, 309 | ScaleIntX(width), ScaleIntY(height)); 310 | } 311 | 312 | return result; 313 | 314 | } 315 | 316 | /// 317 | /// Get list of standards icons in high definition (if version is >= 2.29) 318 | /// 319 | /// 320 | public static List GetHighDefinitionStandardIcons( 321 | KeePass.Plugins.IPluginHost iph, int width, int height) { 322 | List result = null; 323 | if (TYPE_ImageArchive != null ) { 324 | // cf MainForm_Functions.cs line 3234 from KeePass v2.31 325 | object myArchive = Activator.CreateInstance(TYPE_ImageArchive); 326 | // type of myArchive should be ImageArchive 327 | METHOD_ImageArchive_Load.Invoke( 328 | myArchive, 329 | new object[] {PROPERTYVALUE_Images_Client_HighRes}); 330 | result = (List)METHOD_ImageArchive_GetImages.Invoke( 331 | myArchive, 332 | new Object[]{width,height,true}); 333 | } 334 | else { 335 | System.Windows.Forms.ImageList imgl = iph.MainWindow.ClientIcons; 336 | ImageList.ImageCollection ic = imgl.Images; 337 | result = new List(); 338 | for (int i = 0; i 349 | /// ResizedImage without DPIScaled utility 350 | /// 351 | public static Image ResizedImage(Image imgToBeConverted, int nWidth, int nHeight) { 352 | 353 | Image imgNew = imgToBeConverted; 354 | if(imgToBeConverted == null) { Debug.Assert(false); } 355 | 356 | if((imgToBeConverted.Width != nWidth) || (imgToBeConverted.Height != nHeight)) { 357 | 358 | if ( METHOD_ScaleImage != null ) { 359 | imgNew = METHOD_ScaleImage.Invoke( 360 | null, 361 | new Object[] { imgToBeConverted, nWidth, nHeight } ) 362 | as Image; 363 | } 364 | else { 365 | imgNew = new Bitmap(imgToBeConverted, new Size(nWidth, nHeight)); 366 | } 367 | } 368 | 369 | return imgNew; 370 | } 371 | 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /LomsonLib/UI/RTFBuilder.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2014 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Windows.Forms; 23 | using System.Text; 24 | using System.Drawing; 25 | using System.Diagnostics; 26 | using System.Globalization; 27 | 28 | using System.Collections.Generic; 29 | 30 | /* 31 | * LomsonLib.UI 32 | * 33 | * Version 1.1 34 | * See ListViewLayoutManager.cs for release notes 35 | */ 36 | 37 | namespace LomsonLib.UI 38 | { 39 | // 40 | // This code is derived from RichTextBuilder class of KeePass Project v2.26 41 | // Some feature has been added: 42 | // * Can add new Font 43 | // * To Be Continued 44 | // 45 | public sealed class RTFBuilder 46 | { 47 | private StringBuilder m_sb = new StringBuilder(); 48 | 49 | private static List m_vTags; 50 | 51 | private List m_ownTags = null; 52 | 53 | private static Random m_myRandom; 54 | private static bool m_monoWorkaroundBug586901; 55 | public static void InitializeRTFBuilder(Random r, bool mwab586901) { 56 | m_myRandom = r; 57 | m_monoWorkaroundBug586901 = mwab586901; 58 | } 59 | 60 | private sealed class RtfbTag 61 | { 62 | public string IdCode { get; private set; } 63 | public string RtfCode { get; private set; } 64 | public bool StartTag { get; private set; } 65 | public FontStyle Style { get; private set; } 66 | 67 | public RtfbTag(string strId, string strRtf, bool bStartTag, FontStyle fs) 68 | { 69 | if(string.IsNullOrEmpty(strId)) strId = GenerateRandomIdCode(); 70 | this.IdCode = strId; 71 | 72 | this.RtfCode = strRtf; 73 | this.StartTag = bStartTag; 74 | this.Style = fs; 75 | } 76 | 77 | 78 | } 79 | 80 | private sealed class OwnTag 81 | { 82 | public string IdCode { get; private set; } 83 | public string RtfCode { get; private set; } 84 | public bool StartTag { get; private set; } 85 | public string ExternalCode { get; private set;} 86 | 87 | public OwnTag(string strId, string strRtf, bool bStartTag, String externalCode) 88 | { 89 | if(string.IsNullOrEmpty(strId)) strId = GenerateRandomIdCode(); 90 | this.IdCode = strId; 91 | this.RtfCode = strRtf; 92 | this.StartTag = bStartTag; 93 | this.ExternalCode = externalCode; 94 | } 95 | 96 | } 97 | 98 | 99 | internal static string GenerateRandomIdCode() 100 | { 101 | Debug.Assert( m_myRandom != null); 102 | StringBuilder sb = new StringBuilder(14); 103 | for(int i = 0; i < 12; ++i) 104 | { 105 | int n = m_myRandom.Next(62); 106 | if(n < 26) sb.Append((char)('A' + n)); 107 | else if(n < 52) sb.Append((char)('a' + (n - 26))); 108 | else sb.Append((char)('0' + (n - 52))); 109 | } 110 | return sb.ToString(); 111 | } 112 | 113 | private Font m_fDefault; 114 | public Font DefaultFont 115 | { 116 | get { return m_fDefault; } 117 | set { m_fDefault = value; } 118 | } 119 | 120 | public RTFBuilder() 121 | { 122 | EnsureInitializedStatic(); 123 | m_ownTags = new List(); 124 | } 125 | 126 | private static void EnsureInitializedStatic() 127 | { 128 | if(m_vTags != null) return; 129 | 130 | List l = new List(); 131 | l.Add(new RtfbTag(null, "\\b ", true, FontStyle.Bold)); 132 | l.Add(new RtfbTag(null, "\\b0 ", false, FontStyle.Bold)); 133 | l.Add(new RtfbTag(null, "\\i ", true, FontStyle.Italic)); 134 | l.Add(new RtfbTag(null, "\\i0 ", false, FontStyle.Italic)); 135 | l.Add(new RtfbTag(null, "\\ul ", true, FontStyle.Underline)); 136 | l.Add(new RtfbTag(null, "\\ul0 ", false, FontStyle.Underline)); 137 | l.Add(new RtfbTag(null, "\\strike ", true, FontStyle.Strikeout)); 138 | l.Add(new RtfbTag(null, "\\strike0 ", false, FontStyle.Strikeout)); 139 | m_vTags = l; 140 | } 141 | 142 | 143 | public static KeyValuePair GetStyleIdCodes(FontStyle fs) 144 | { 145 | string strL = null, strR = null; 146 | 147 | foreach(RtfbTag rTag in m_vTags) 148 | { 149 | if(rTag.Style == fs) 150 | { 151 | if(rTag.StartTag) strL = rTag.IdCode; 152 | else strR = rTag.IdCode; 153 | } 154 | } 155 | 156 | return new KeyValuePair(strL, strR); 157 | } 158 | 159 | public KeyValuePair GetStyleIdOwnCodes(string externalCode) 160 | { 161 | string strL = null, strR = null; 162 | 163 | foreach(OwnTag rTag in m_ownTags) 164 | { 165 | if(externalCode == rTag.ExternalCode ) 166 | { 167 | if(rTag.StartTag) strL = rTag.IdCode; 168 | else strR = rTag.IdCode; 169 | } 170 | } 171 | 172 | return new KeyValuePair(strL, strR); 173 | } 174 | 175 | public void AddOwnTag(string externalCode, string rtfStartCode, string rtfStopCode ) 176 | { 177 | m_ownTags.Add(new OwnTag(null, rtfStartCode, true, externalCode )); 178 | if (!string.IsNullOrEmpty(rtfStopCode) ) { 179 | m_ownTags.Add(new OwnTag(null, rtfStopCode, false, externalCode )); 180 | } 181 | } 182 | 183 | public void Append(string str) 184 | { 185 | m_sb.Append(str); 186 | } 187 | 188 | public void AppendLine() 189 | { 190 | m_sb.AppendLine(); 191 | } 192 | 193 | public void AppendLine(string str) 194 | { 195 | m_sb.AppendLine(str); 196 | } 197 | 198 | public void Append(string str, FontStyle fs) 199 | { 200 | Append(str, fs, null, null, null, null); 201 | } 202 | 203 | public void Append(string str, FontStyle fs, string strOuterPrefix, 204 | string strInnerPrefix, string strInnerSuffix, string strOuterSuffix) 205 | { 206 | KeyValuePair kvpTags = GetStyleIdCodes(fs); 207 | 208 | if(!string.IsNullOrEmpty(strOuterPrefix)) m_sb.Append(strOuterPrefix); 209 | 210 | if(!string.IsNullOrEmpty(kvpTags.Key)) m_sb.Append(kvpTags.Key); 211 | if(!string.IsNullOrEmpty(strInnerPrefix)) m_sb.Append(strInnerPrefix); 212 | m_sb.Append(str); 213 | if(!string.IsNullOrEmpty(strInnerSuffix)) m_sb.Append(strInnerSuffix); 214 | if(!string.IsNullOrEmpty(kvpTags.Value)) m_sb.Append(kvpTags.Value); 215 | 216 | if(!string.IsNullOrEmpty(strOuterSuffix)) m_sb.Append(strOuterSuffix); 217 | } 218 | 219 | /// 220 | /// Append Own tag (only start code) 221 | /// 222 | public void AppendOwnTag(string externalCode) 223 | { 224 | KeyValuePair kvpTags = GetStyleIdOwnCodes( externalCode ); 225 | 226 | if(!string.IsNullOrEmpty(kvpTags.Key)) m_sb.Append(kvpTags.Key); 227 | } 228 | 229 | 230 | public void AppendOwnTagged(string str, string externalCode, string strOuterPrefix, 231 | string strInnerPrefix, string strInnerSuffix, string strOuterSuffix) 232 | { 233 | KeyValuePair kvpTags = GetStyleIdOwnCodes( externalCode ); 234 | 235 | if(!string.IsNullOrEmpty(strOuterPrefix)) m_sb.Append(strOuterPrefix); 236 | 237 | if(!string.IsNullOrEmpty(kvpTags.Key)) m_sb.Append(kvpTags.Key); 238 | if(!string.IsNullOrEmpty(strInnerPrefix)) m_sb.Append(strInnerPrefix); 239 | m_sb.Append(str); 240 | if(!string.IsNullOrEmpty(strInnerSuffix)) m_sb.Append(strInnerSuffix); 241 | if(!string.IsNullOrEmpty(kvpTags.Value)) m_sb.Append(kvpTags.Value); 242 | 243 | if(!string.IsNullOrEmpty(strOuterSuffix)) m_sb.Append(strOuterSuffix); 244 | 245 | } 246 | 247 | 248 | public void AppendOwnTaggedLine(string str, string externalCode, string strOuterPrefix, 249 | string strInnerPrefix, string strInnerSuffix, string strOuterSuffix) 250 | { 251 | AppendOwnTagged(str, externalCode,strOuterPrefix, strInnerPrefix, strInnerSuffix, strOuterSuffix); 252 | m_sb.AppendLine(); 253 | } 254 | 255 | public void AppendLine(string str, FontStyle fs, string strOuterPrefix, 256 | string strInnerPrefix, string strInnerSuffix, string strOuterSuffix) 257 | { 258 | Append(str, fs, strOuterPrefix, strInnerPrefix, strInnerSuffix, strOuterSuffix); 259 | m_sb.AppendLine(); 260 | } 261 | 262 | public void AppendLine(string str, FontStyle fs) 263 | { 264 | Append(str, fs); 265 | m_sb.AppendLine(); 266 | } 267 | 268 | private static RichTextBox CreateOpRtb() 269 | { 270 | RichTextBox rtbOp = new RichTextBox(); 271 | rtbOp.Visible = false; // Ensure invisibility 272 | rtbOp.DetectUrls = false; 273 | rtbOp.HideSelection = true; 274 | rtbOp.Multiline = true; 275 | rtbOp.WordWrap = false; 276 | 277 | return rtbOp; 278 | } 279 | 280 | public void Build(RichTextBox rtb) 281 | { 282 | if(rtb == null) throw new ArgumentNullException("rtb"); 283 | 284 | RichTextBox rtbOp = CreateOpRtb(); 285 | string strText = m_sb.ToString(); 286 | 287 | Dictionary dEnc = new Dictionary(); 288 | if(m_monoWorkaroundBug586901) 289 | { 290 | StringBuilder sbEnc = new StringBuilder(); 291 | for(int i = 0; i < strText.Length; ++i) 292 | { 293 | char ch = strText[i]; 294 | if((int)ch <= 255) sbEnc.Append(ch); 295 | else 296 | { 297 | string strCharEnc; 298 | if(!dEnc.TryGetValue(ch, out strCharEnc)) 299 | { 300 | strCharEnc = GenerateRandomIdCode(); 301 | dEnc[ch] = strCharEnc; 302 | } 303 | sbEnc.Append(strCharEnc); 304 | } 305 | } 306 | strText = sbEnc.ToString(); 307 | } 308 | 309 | rtbOp.Text = strText; 310 | Debug.Assert(rtbOp.Text == strText); // Test committed 311 | 312 | if(m_fDefault != null) 313 | { 314 | rtbOp.Select(0, rtbOp.TextLength); 315 | rtbOp.SelectionFont = m_fDefault; 316 | } 317 | 318 | string strRtf = rtbOp.Rtf; 319 | rtbOp.Dispose(); 320 | 321 | foreach(KeyValuePair kvpEnc in dEnc) 322 | { 323 | strRtf = strRtf.Replace(kvpEnc.Value, 324 | RtfEncodeChar(kvpEnc.Key)); 325 | } 326 | foreach(RtfbTag rTag in m_vTags) 327 | { 328 | strRtf = strRtf.Replace(rTag.IdCode, rTag.RtfCode); 329 | } 330 | foreach(OwnTag oTag in m_ownTags) 331 | { 332 | strRtf = strRtf.Replace(oTag.IdCode, oTag.RtfCode); 333 | } 334 | 335 | rtb.Rtf = strRtf; 336 | } 337 | 338 | // From StrUtil of KeePass v2.26 339 | public static string RtfEncodeChar(char ch) 340 | { 341 | // Unicode character values must be encoded using 342 | // 16-bit numbers (decimal); Unicode values greater 343 | // than 32767 must be expressed as negative numbers 344 | short sh = (short)ch; 345 | return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?"); 346 | } 347 | 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /LomsonLib/UI/ScaleControlTableLayoutPanel.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2014 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | using System; 23 | using System.Drawing; 24 | using System.Windows.Forms; 25 | 26 | /* 27 | * LomsonLib.UI 28 | * 29 | * Version 1.0 30 | * See ListViewLayoutManager.cs for release notes 31 | * 32 | */ 33 | 34 | 35 | namespace LomsonLib.UI 36 | { 37 | /// 38 | /// TableLayoutPanel with autoScaling that can be switched off 39 | /// 40 | public class ScaleControlTableLayoutPanel: TableLayoutPanel 41 | { 42 | private readonly bool my_ScaleChildren; 43 | protected override bool ScaleChildren { 44 | get { 45 | return my_ScaleChildren; 46 | } 47 | } 48 | 49 | /// 50 | /// 51 | /// 52 | public bool ScaleWidth { 53 | get; set; 54 | } 55 | 56 | public bool ScaleHeight { 57 | get; set; 58 | } 59 | 60 | protected override Rectangle GetScaledBounds( 61 | Rectangle bounds, 62 | SizeF factor, 63 | BoundsSpecified specified) { 64 | int newWidth = 65 | ScaleWidth ? Convert.ToInt32(bounds.Width * factor.Width):bounds.Width; 66 | int newHeight = 67 | ScaleHeight ? Convert.ToInt32(bounds.Height * factor.Height):bounds.Height; 68 | 69 | return new Rectangle(bounds.X, bounds.Y, newWidth, newHeight); 70 | } 71 | 72 | /// 73 | /// New ScaleControlTableLayoutPanel with :
74 | /// 75 | /// ScaleChildren that returns false 76 | /// Automatic scale of width 77 | /// Automatic scale of height 78 | /// 79 | ///
80 | public ScaleControlTableLayoutPanel() 81 | { 82 | my_ScaleChildren = false; 83 | ScaleWidth = true; 84 | ScaleHeight = true; 85 | } 86 | 87 | public ScaleControlTableLayoutPanel(bool myScaleChildren) 88 | { 89 | my_ScaleChildren = myScaleChildren; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /LomsonLib/UI/SwappableComparer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2014 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Collections; 23 | using System.Diagnostics; 24 | using System.Windows.Forms; 25 | 26 | /* 27 | * LomsonLib.UI 28 | * 29 | * Version 1.1 30 | * See ListViewLayoutManager.cs for release notes 31 | * 32 | */ 33 | 34 | namespace LomsonLib.UI 35 | { 36 | /// 37 | /// Description of IListViewItemComparer. 38 | /// 39 | public interface ISwappableComparer 40 | { 41 | int Compare(T obj1, T obj2); 42 | void Swap(); 43 | void RevertSwapToDefault(); 44 | } 45 | 46 | public abstract class BaseSwappableComparer: ISwappableComparer 47 | { 48 | protected bool DefaultSwapped {get; set;} 49 | protected bool ManuallySwapped {get; set;} 50 | 51 | public abstract int Compare(T obj1, T obj2); 52 | 53 | protected BaseSwappableComparer( bool defaultSwapped ) { 54 | DefaultSwapped = defaultSwapped; 55 | ManuallySwapped = false; 56 | } 57 | 58 | public void Swap() { 59 | ManuallySwapped = !ManuallySwapped; 60 | } 61 | 62 | public void RevertSwapToDefault() { 63 | ManuallySwapped = DefaultSwapped; 64 | } 65 | 66 | public bool IsSwapped() { 67 | return ( ManuallySwapped ^ DefaultSwapped ); 68 | } 69 | 70 | } 71 | 72 | public interface ISwappableStringComparer:ISwappableComparer{}; 73 | 74 | public interface ISwappableListViewItemComparer:ISwappableComparer{}; 75 | 76 | public abstract class BaseSwappableStringComparer:BaseSwappableComparer, ISwappableStringComparer 77 | { 78 | protected BaseSwappableStringComparer( bool defaultSwapped ): base(defaultSwapped) { 79 | } 80 | 81 | public abstract override int Compare(String obj1, String obj2); 82 | 83 | protected String GetString1(String str1, String str2) { 84 | return IsSwapped()?str2:str1; 85 | } 86 | 87 | protected String GetString2(String str1, String str2) { 88 | return IsSwapped()?str1:str2; 89 | } 90 | 91 | } 92 | 93 | public class StringComparer:BaseSwappableStringComparer 94 | { 95 | private bool m_ignoreCase; 96 | 97 | public StringComparer( bool defaultSwapped, bool ignoreCase ) 98 | :base( defaultSwapped) { 99 | 100 | m_ignoreCase = ignoreCase; 101 | } 102 | 103 | public override int Compare(String obj1, String obj2) { 104 | 105 | string cmpStr1 = GetString1( obj1, obj2); 106 | string cmpStr2 = GetString2( obj1, obj2); 107 | 108 | return (String.Compare( cmpStr1, cmpStr2, m_ignoreCase) ); 109 | } 110 | 111 | } 112 | 113 | public class IntegerAsStringComparer:BaseSwappableStringComparer 114 | { 115 | 116 | public IntegerAsStringComparer( bool defaultSwapped ) 117 | :base( defaultSwapped) { 118 | 119 | } 120 | 121 | public override int Compare( String obj1, String obj2) { 122 | int compareResult; 123 | 124 | string cmpStr1 = GetString1( obj1, obj2); 125 | string cmpStr2 = GetString2( obj1, obj2); 126 | 127 | bool parseOK; 128 | int iComp1; 129 | parseOK = int.TryParse(cmpStr1, out iComp1); 130 | Debug.Assert( parseOK ); if (!parseOK) throw new InvalidOperationException("unable to parse"); 131 | int iComp2; 132 | parseOK = int.TryParse(cmpStr2, out iComp2); 133 | Debug.Assert( parseOK ); if (!parseOK) throw new InvalidOperationException("unable to parse"); 134 | 135 | if (iComp1 > iComp2) { 136 | compareResult = 1; 137 | } 138 | else if (iComp1 < iComp2) { 139 | compareResult = -1; 140 | } 141 | else { // iViewX == iViewY ) 142 | compareResult = 0; 143 | } 144 | 145 | return compareResult; 146 | } 147 | 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /LomsonLib/Utility/LomsonUtility.cs: -------------------------------------------------------------------------------- 1 | /* 2 | LomsonLib - Library to help management of various object types in program 3 | developed in c#. 4 | 5 | Copyright (C) 2015 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | using System; 22 | using System.Text.RegularExpressions; 23 | 24 | /* 25 | * LomsonLib.Utility 26 | * 27 | * 28 | */ 29 | namespace LomsonLib.Utility 30 | { 31 | /// 32 | /// Utility to manage URL. 33 | /// 34 | public static class URLUtility 35 | { 36 | /// 37 | /// Extract rootDomain from URL 38 | /// 39 | public static string RootDomain( string url) 40 | { 41 | Match match = Regex.Match(url, "([hH][tT][tT][pP][sS]?:\\/\\/)?" // remove http[s]?:// 42 | +"([^.]+\\.[^.]{1,3}(\\.[^.]{1,3})?)$"); 43 | string domain = match.Groups[2].Success ? match.Groups[2].Value : null; 44 | 45 | return domain; 46 | } 47 | 48 | /// 49 | /// Get Domain 50 | /// 51 | /// 52 | /// 53 | public static string UrlDomain( string url) 54 | { 55 | try { 56 | Uri uri = new Uri( addUrlHttpPrefix(url)); 57 | return uri.Host; 58 | } 59 | catch ( Exception ) { 60 | return ""; 61 | } 62 | 63 | 64 | //return "www.google.fr"; 65 | } 66 | 67 | /// 68 | /// Build absolute URL. 69 | /// If urlToBeTested is relative, rootUrl is prefixed. 70 | /// 71 | public static string absoluteURL( string urlToBeTested, string rootUrl ) { 72 | if (string.IsNullOrEmpty(urlToBeTested) ) { 73 | return urlToBeTested; 74 | } else { 75 | 76 | Uri test = new Uri(new Uri(rootUrl), urlToBeTested); 77 | 78 | return test.AbsoluteUri; 79 | 80 | } 81 | } 82 | 83 | /// 84 | /// Add http:// if http:// or https:// is not found 85 | /// 86 | /// 87 | /// 88 | public static string addUrlHttpPrefix( string url) { 89 | if ( (!url.ToLower().StartsWith("http://")) 90 | && (!url.ToLower().StartsWith("https://"))) { 91 | url = "http://" + url; 92 | } 93 | 94 | return url; 95 | } 96 | 97 | /// 98 | /// Remove http:// if http:// or https:// 99 | /// 100 | /// 101 | /// 102 | public static string removeHttpPrefix( string url) { 103 | if (url.ToLower().StartsWith("http://") ) { 104 | return url.Remove(0,7); 105 | } else if (url.ToLower().StartsWith("https://")) { 106 | return url.Remove(0,8); 107 | } 108 | else { 109 | return url; 110 | } 111 | } 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region Using directives 2 | 3 | using System; 4 | using System.Resources; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | #endregion 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("Custom Icon Dashboarder")] 14 | [assembly: AssemblyDescription("Provides some statistics and management operations on icons")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("Jareth Lomson")] 17 | [assembly: AssemblyProduct("KeePass Plugin")] 18 | [assembly: AssemblyCopyright("Copyright 2023 - Jareth Lomson")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // This sets the default COM visibility of types in the assembly to invisible. 23 | // If you need to expose a type to COM, use [ComVisible(true)] on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The assembly version has following format : 27 | // 28 | // Major.Minor.Build.Revision 29 | // 30 | // You can specify all the values or you can use the default the Revision and 31 | // Build Numbers by using the '*' as shown below: 32 | [assembly: AssemblyVersion("1.3.0")] 33 | 34 | 35 | // Asked by fxCop 36 | [assembly: NeutralResourcesLanguage("en-US")] 37 | [assembly: CLSCompliant(false)] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeePass Custom Icon Dashboarder 2 | 3 | 4 | This plugin provides some management features and statistics for custom icons in KeePass. 5 | 6 | High definition of custom icon can be uploaded. URLs of associated entries are used to 7 | retrieve the highest definition of icons. 8 | 9 | For each custom icon, the following information is available: 10 | - Number and list of entries that use it 11 | - Number and list of groups that use it 12 | 13 | 14 | Features are: 15 | - Download highest definition of custom icons from favicon URL 16 | - Remove custom icons 17 | - Modify custom icons of groups and entries 18 | - Get list of custom icons in KeePass 19 | - Get number and list of entries used by each custom icon 20 | - Get number and list of groups used by each custom icon 21 | 22 | 23 | ## Installation 24 | 25 | ### Pre-requisites 26 | 27 | - KeePass Password Safe 2.00+ 28 | - Framework .NET 4.5+ 29 | 30 | 31 | ### Installation steps 32 | 1. Download [latest](https://github.com/incognito1234/Keepass-Custom-Icon-Dashboarder/releases/latest) plgx release 33 | 2. Put the _.plgx_ file into a folder called **plugins** inside your KeePass Password Safe installation folder 34 | 35 | 36 | ## Screenshots 37 | A menu item is added to **Tool** menu 38 | 39 | ![screenshot-menuitem](docs/images/screenshot-menuitem.png) 40 | 41 | Custom icon Dashboard (downloading in progress) 42 | 43 | ![screenshot-dashboard](docs/images/screenshot-dashboard-1.png) 44 | 45 | 46 | ## Changelog 47 | 48 | ### Version 1.3.0 49 | - Manage malformed URL 50 | - Detect and fix corrupt icons 51 | 52 | ### Version 1.2.0 53 | - Simultaneous icon downloads by introducing multithreading 54 | - Remember size and position of dashboard when closing windows 55 | - Plugin is now hosted by github 56 | - Improvement: Update HtmlAgilityPack with version v1.11.12 57 | 58 | ### Version 1.1.0 59 | - All icons from URL are downloaded. The best-sized icon is chosen by default. 60 | Then it is possible to change manually the chosen icon. 61 | - Add support of downloading icons of entries with standard icons. 62 | - Display index of selected icon in the upper right corner of dashboard. 63 | 64 | ### Version 1.0.0 65 | - Add support for downloading icons from url of entries 66 | 67 | ### Version 0.3.0 68 | - Display size of icons in the list icon view 69 | - Display selected icon with different sizes 70 | 71 | ### Version 0.2.1 72 | - Ensure that icon list is correctly rebuilt after a removal (Ticket #2) 73 | 74 | ### Version 0.2 75 | - Add support for modifying custom icons 76 | - Add support for removing custom icons 77 | 78 | 79 | ### Version 0.1 80 | - Enhance Dashboard Form: resizable and sortable lists 81 | - Add the column "total" in the list icon view 82 | - Disable menu item if no database is open 83 | - Change version numbering: x.y.z -> x.y 84 | 85 | 86 | ### Version 0.0.1 87 | - Initial version 88 | -------------------------------------------------------------------------------- /Resource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Ce code a été généré par un outil. 4 | // Version du runtime :4.0.30319.42000 5 | // 6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si 7 | // le code est régénéré. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CustomIconDashboarderPlugin { 12 | using System; 13 | 14 | 15 | /// 16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. 17 | /// 18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder 19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio. 20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen 21 | // avec l'option /str ou régénérez votre projet VS. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resource() { 33 | } 34 | 35 | /// 36 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CustomIconDashboarderPlugin.Resource", typeof(Resource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes 51 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Recherche une chaîne localisée semblable à Current Size. 65 | /// 66 | internal static string hdr_currentSize { 67 | get { 68 | return ResourceManager.GetString("hdr_currentSize", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Recherche une chaîne localisée semblable à Full Path. 74 | /// 75 | internal static string hdr_fullPath { 76 | get { 77 | return ResourceManager.GetString("hdr_fullPath", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Recherche une chaîne localisée semblable à Group. 83 | /// 84 | internal static string hdr_group { 85 | get { 86 | return ResourceManager.GetString("hdr_group", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Recherche une chaîne localisée semblable à Group Name. 92 | /// 93 | internal static string hdr_groupName { 94 | get { 95 | return ResourceManager.GetString("hdr_groupName", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Recherche une chaîne localisée semblable à Icon. 101 | /// 102 | internal static string hdr_icon { 103 | get { 104 | return ResourceManager.GetString("hdr_icon", resourceCulture); 105 | } 106 | } 107 | 108 | /// 109 | /// Recherche une chaîne localisée semblable à Id Entry. 110 | /// 111 | internal static string hdr_idEntry { 112 | get { 113 | return ResourceManager.GetString("hdr_idEntry", resourceCulture); 114 | } 115 | } 116 | 117 | /// 118 | /// Recherche une chaîne localisée semblable à #Entry. 119 | /// 120 | internal static string hdr_nEntry { 121 | get { 122 | return ResourceManager.GetString("hdr_nEntry", resourceCulture); 123 | } 124 | } 125 | 126 | /// 127 | /// Recherche une chaîne localisée semblable à New Size. 128 | /// 129 | internal static string hdr_newSize { 130 | get { 131 | return ResourceManager.GetString("hdr_newSize", resourceCulture); 132 | } 133 | } 134 | 135 | /// 136 | /// Recherche une chaîne localisée semblable à #Group. 137 | /// 138 | internal static string hdr_nGroup { 139 | get { 140 | return ResourceManager.GetString("hdr_nGroup", resourceCulture); 141 | } 142 | } 143 | 144 | /// 145 | /// Recherche une chaîne localisée semblable à #Total. 146 | /// 147 | internal static string hdr_nTotal { 148 | get { 149 | return ResourceManager.GetString("hdr_nTotal", resourceCulture); 150 | } 151 | } 152 | 153 | /// 154 | /// Recherche une chaîne localisée semblable à #URL. 155 | /// 156 | internal static string hdr_nURL { 157 | get { 158 | return ResourceManager.GetString("hdr_nURL", resourceCulture); 159 | } 160 | } 161 | 162 | /// 163 | /// Recherche une chaîne localisée semblable à Title. 164 | /// 165 | internal static string hdr_titleEntry { 166 | get { 167 | return ResourceManager.GetString("hdr_titleEntry", resourceCulture); 168 | } 169 | } 170 | 171 | /// 172 | /// Recherche une chaîne localisée semblable à Url. 173 | /// 174 | internal static string hdr_url { 175 | get { 176 | return ResourceManager.GetString("hdr_url", resourceCulture); 177 | } 178 | } 179 | 180 | /// 181 | /// Recherche une chaîne localisée semblable à User Name. 182 | /// 183 | internal static string hdr_userName { 184 | get { 185 | return ResourceManager.GetString("hdr_userName", resourceCulture); 186 | } 187 | } 188 | 189 | /// 190 | /// Recherche une chaîne localisée semblable à Custom Icon Dashboard. 191 | /// 192 | internal static string menu_customIcon { 193 | get { 194 | return ResourceManager.GetString("menu_customIcon", resourceCulture); 195 | } 196 | } 197 | 198 | /// 199 | /// Recherche une chaîne localisée semblable à Malformed url. 200 | /// 201 | internal static string val_malformedurl { 202 | get { 203 | return ResourceManager.GetString("val_malformedurl", resourceCulture); 204 | } 205 | } 206 | 207 | /// 208 | /// Recherche une chaîne localisée semblable à Not found. 209 | /// 210 | internal static string val_na { 211 | get { 212 | return ResourceManager.GetString("val_na", resourceCulture); 213 | } 214 | } 215 | 216 | /// 217 | /// Recherche une chaîne localisée semblable à No url. 218 | /// 219 | internal static string val_nourl { 220 | get { 221 | return ResourceManager.GetString("val_nourl", resourceCulture); 222 | } 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /Resource.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Icon 122 | 123 | 124 | #Group 125 | 126 | 127 | #Entry 128 | 129 | 130 | Title 131 | 132 | 133 | Group Name 134 | 135 | 136 | User Name 137 | 138 | 139 | Full Path 140 | 141 | 142 | Custom Icon Dashboard 143 | 144 | 145 | #Total 146 | 147 | 148 | #URL 149 | 150 | 151 | Current Size 152 | 153 | 154 | New Size 155 | 156 | 157 | Not found 158 | 159 | 160 | No url 161 | 162 | 163 | Url 164 | 165 | 166 | Id Entry 167 | 168 | 169 | Group 170 | 171 | 172 | Malformed url 173 | 174 | -------------------------------------------------------------------------------- /WaitingForm.Designer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | CustomIconDashboarder - KeePass Plugin to get some information and 3 | manage custom icons 4 | 5 | Copyright (C) 2023 Jareth Lomson 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | namespace CustomIconDashboarderPlugin 23 | { 24 | partial class WaitingForm 25 | { 26 | /// 27 | /// Required designer variable. 28 | /// 29 | private System.ComponentModel.IContainer components = null; 30 | 31 | /// 32 | /// Clean up any resources being used. 33 | /// 34 | /// true if managed resources should be disposed; otherwise, false. 35 | protected override void Dispose(bool disposing) 36 | { 37 | if (disposing && (components != null)) 38 | { 39 | components.Dispose(); 40 | } 41 | base.Dispose(disposing); 42 | } 43 | 44 | #region Windows Form Designer generated code 45 | 46 | /// 47 | /// Required method for Designer support - do not modify 48 | /// the contents of this method with the code editor. 49 | /// 50 | private void InitializeComponent() 51 | { 52 | this.lbl_waitingMessage = new System.Windows.Forms.Label(); 53 | this.SuspendLayout(); 54 | // 55 | // lbl_waitingMessage 56 | // 57 | this.lbl_waitingMessage.BackColor = System.Drawing.SystemColors.GradientActiveCaption; 58 | this.lbl_waitingMessage.Dock = System.Windows.Forms.DockStyle.Fill; 59 | this.lbl_waitingMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.900001F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 60 | this.lbl_waitingMessage.Location = new System.Drawing.Point(0, 0); 61 | this.lbl_waitingMessage.Name = "lbl_waitingMessage"; 62 | this.lbl_waitingMessage.Size = new System.Drawing.Size(794, 300); 63 | this.lbl_waitingMessage.TabIndex = 0; 64 | this.lbl_waitingMessage.Text = "Text"; 65 | this.lbl_waitingMessage.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 66 | // 67 | // WaitingForm 68 | // 69 | this.AutoScaleDimensions = new System.Drawing.SizeF(16F, 31F); 70 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 71 | this.ClientSize = new System.Drawing.Size(794, 300); 72 | this.ControlBox = false; 73 | this.Controls.Add(this.lbl_waitingMessage); 74 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 75 | this.Name = "WaitingForm"; 76 | this.ShowIcon = false; 77 | this.ShowInTaskbar = false; 78 | this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; 79 | this.Text = "Please wait..."; 80 | this.TopMost = true; 81 | this.ResumeLayout(false); 82 | 83 | } 84 | 85 | #endregion 86 | 87 | private System.Windows.Forms.Label lbl_waitingMessage; 88 | } 89 | } -------------------------------------------------------------------------------- /WaitingForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace CustomIconDashboarderPlugin 11 | { 12 | public partial class WaitingForm : Form 13 | { 14 | public WaitingForm() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | public void SetMessage(string msg) 20 | { 21 | lbl_waitingMessage.Text = msg; 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /WaitingForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /cleanBinaries.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rmdir /Q /S %~dp0\obj 4 | rmdir /Q /S %~dp0\bin 5 | mkdir obj 6 | mkdir bin 7 | 8 | rmdir /Q /S %~dp0\LomsonLib\obj 9 | rmdir /Q /S %~dp0\LomsonLib\bin 10 | mkdir LomsonLib\obj 11 | mkdir LomsonLib\bin 12 | -------------------------------------------------------------------------------- /createPlgx.cmd: -------------------------------------------------------------------------------- 1 | echo off 2 | 3 | rem Uncomment this line if PATH_KEEPASS is not an environment variable 4 | set PATH_KEEPASS=C:\Temp\KeePass-2.43 5 | 6 | set SRC_PATH_PLUGIN=%~dp0 7 | 8 | rem WARNING 9 | rem this folder is removed at start and end of this command file 10 | set TMP_PATH_PLUGIN=%TEMP%\CustomIconDashboarder 11 | 12 | rmdir /s /q %TMP_PATH_PLUGIN% 13 | mkdir %TMP_PATH_PLUGIN% 14 | 15 | xcopy %SRC_PATH_PLUGIN%*.* %TMP_PATH_PLUGIN% 16 | del %TMP_PATH_PLUGIN%\CustomIconDashboarder.csproj 17 | copy %TMP_PATH_PLUGIN%\CustomIconDashboarder_plgx.csproj %TMP_PATH_PLUGIN%\CustomIconDashboarder.csproj 18 | del %TMP_PATH_PLUGIN%\CustomIconDashboarder_plgx.csproj 19 | del %TMP_PATH_PLUGIN%\%~nx0 20 | 21 | mkdir %TMP_PATH_PLUGIN%\HtmlAgilityPack 22 | xcopy /S %SRC_PATH_PLUGIN%HtmlAgilityPack %TMP_PATH_PLUGIN%\HtmlAgilityPack 23 | 24 | mkdir %TMP_PATH_PLUGIN%\Properties 25 | xcopy /S %SRC_PATH_PLUGIN%Properties %TMP_PATH_PLUGIN%\Properties 26 | 27 | mkdir %TMP_PATH_PLUGIN%\LomsonLib 28 | xcopy /S %SRC_PATH_PLUGIN%LomsonLib %TMP_PATH_PLUGIN%\LomsonLib 29 | del %TMP_PATH_PLUGIN%\LomsonLib\LomsonLib.csproj 30 | del %TMP_PATH_PLUGIN%\LomsonLib\Properties\AssemblyInfo.cs 31 | 32 | %PATH_KEEPASS%\keepass.exe --plgx-create %TMP_PATH_PLUGIN% ^ 33 | --plgx-prereq-kp:2.0 ^ 34 | --plgx-prereq-net:4.0 35 | 36 | copy %TEMP%\CustomIconDashboarder.plgx %~dp0 37 | copy %~dp0\CustomIconDashboarder.plgx C:\temp\KeePass-2.43\Plugins 38 | 39 | echo Remove Temp files 40 | 41 | rmdir /s /q %TMP_PATH_PLUGIN% 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/images/screenshot-dashboard-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/docs/images/screenshot-dashboard-1.png -------------------------------------------------------------------------------- /docs/images/screenshot-menuitem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incognito1234/KeePass-Custom-Icon-Dashboarder/6bd1c2bd7d296a244b907364043719df8f24d08e/docs/images/screenshot-menuitem.png -------------------------------------------------------------------------------- /versionInfo.txt: -------------------------------------------------------------------------------- 1 | : 2 | Custom Icon Dashboarder: 1.3.0 3 | : --------------------------------------------------------------------------------