public void Tick() { if (_currentTicks < _ticks) { _progress.UpdateProgress(++_currentTicks, _ticks); } }
private BlogPost PostTemplate(IProgressHost progress) { progress.UpdateProgress(50, 100); // make a test post that we can use to do analysis BlogPost testPost = new BlogPost(); testPost.IsTemporary = true; testPost.Title = TEMPORARY_POST_TITLE; //plant a <p> around the contents so that the blog provider doesn't try to add their own //and so we'll know it can be safely removed later //Note: this fixes an issue where the editor's postBody <div> was being parented improperly by //a <p> element that the blog service was adding... string postContents = String.Format(CultureInfo.InvariantCulture, "<p>{0}</p>", TEMPORARY_POST_BODY); testPost.Contents = postContents; string etag; XmlDocument remotePost; testPost.Id = _blogClient.NewPost(_blogAccount.BlogId, testPost, new IgnoreNewCategoryContext(), true, out etag, out remotePost); testPost.ETag = etag; testPost.AtomRemotePost = remotePost; progress.UpdateProgress(100, 100); return(testPost); }
private BlogEditingTemplate ParseBlogPostIntoTemplate(BlogPostRegionLocatorStrategy regionLocator, IProgressHost progress, string postUrl) { progress.UpdateProgress(Res.Get(StringId.ProgressCreatingEditingTemplate)); BlogPostRegions regions = regionLocator.LocateRegionsOnUIThread(progress, postUrl); IHTMLElement primaryTitleRegion = GetPrimaryEditableTitleElement(regions.BodyRegion, regions.Document, regions.TitleRegions); // IF // - primaryTitleRegion is not null (title found) // - BodyRegion is null (no post body found) // - AND primaryTitleRegion is a link if (primaryTitleRegion != null && regions.BodyRegion == null && primaryTitleRegion.tagName.ToLower() == "a") { // Title region was detected, but body region was not. // It is possible that only titles are shown on the homepage // Try requesting the post itself, and loading regions from the post itself // HACK Somewhere the 'about:' protocol replaces http/https, replace it again with the correct protocol var pathMatch = new Regex("^about:(.*)$").Match((primaryTitleRegion as IHTMLAnchorElement).href); Debug.Assert(pathMatch.Success); // Assert that this URL is to the format we expect var newPostPath = pathMatch.Groups[1].Value; // Grab the path from the URL var homepageUri = new Uri(_blogHomepageUrl); var newPostUrl = $"{homepageUri.Scheme}://{homepageUri.Host}{newPostPath}"; // Recreate the full post URL // Set the NextTryPostUrl flag in the region locater // This will indicate to the other thread that another page should be parsed _nextTryPostUrl = newPostUrl; return(null); } BlogEditingTemplate template = GenerateBlogTemplate((IHTMLDocument3)regions.Document, primaryTitleRegion, regions.TitleRegions, regions.BodyRegion); progress.UpdateProgress(100, 100); return(template); }
private string DownloadTemplateFiles(string templateContents, string templateUrl, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressDownloadingSupportingFiles)); FileBasedSiteStorage files = new FileBasedSiteStorage(_blogTemplateDir); // convert the string to a stream MemoryStream templateStream = new MemoryStream(); StreamWriter writer = new StreamWriter(templateStream, Encoding.UTF8); writer.Write(templateContents); writer.Flush(); templateStream.Seek(0, SeekOrigin.Begin); //read the stream into a lightweight HTML. Note that we use from LightWeightHTMLDocument.FromIHTMLDocument2 //instead of LightWeightHTMLDocument.FromStream because from stream improperly shoves a saveFrom declaration //above the docType (bug 289357) IHTMLDocument2 doc = HTMLDocumentHelper.StreamToHTMLDoc(templateStream, templateUrl, true); LightWeightHTMLDocument ldoc = LightWeightHTMLDocument.FromIHTMLDocument2(doc, templateUrl, true, false); PageDownloadContext downloadContext = new PageDownloadContext(0); ApplyCredentials(downloadContext, templateUrl); using (PageToDownloadFactory downloadFactory = new PageToDownloadFactory(ldoc, downloadContext, _parentControl)) { //calculate the dependent styles and resources ProgressTick tick = new ProgressTick(progress, 50, 100); downloadFactory.CreatePagesToDownload(tick); tick.UpdateProgress(100, 100); //download the dependent styles and resources tick = new ProgressTick(progress, 50, 100); PageAndReferenceDownloader downloader = new PageAndReferenceDownloader(downloadFactory.PagesToDownload, files); this.ApplyCredentials(downloader, templateUrl); downloader.Download(tick); tick.UpdateProgress(100, 100); //Expand out the relative paths in the downloaded HTML file with absolute paths. //Note: this is necessary so that template resources are not improperly resolved relative // to the location of the file the editor is editing. string blogTemplateFile = Path.Combine(_blogTemplateDir, files.RootFile); string origFile = blogTemplateFile + ".token"; File.Move(blogTemplateFile, origFile); string absPath = String.Format(CultureInfo.InvariantCulture, "file:///{0}/{1}", _blogTemplateDir.Replace('\\', '/'), downloader.PathToken); TextHelper.ReplaceInFile(origFile, downloader.PathToken, blogTemplateFile, absPath); File.Delete(origFile); //fix up the files FixupDownloadedFiles(blogTemplateFile, files, downloader.PathToken); //complete the progress. progress.UpdateProgress(100, 100); File.WriteAllText(blogTemplateFile + ".path", absPath); return(blogTemplateFile); } }
private BlogEditingTemplate ParseBlogPostIntoTemplate(BlogPostRegionLocatorStrategy regionLocator, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressCreatingEditingTemplate)); BlogPostRegions regions = regionLocator.LocateRegionsOnUIThread(progress); IHTMLElement primaryTitleRegion = GetPrimaryEditableTitleElement(regions.BodyRegion, regions.Document, regions.TitleRegions); BlogEditingTemplate template = GenerateBlogTemplate((IHTMLDocument3)regions.Document, primaryTitleRegion, regions.TitleRegions, regions.BodyRegion); progress.UpdateProgress(100, 100); return(template); }
public void UpdateProgress(int complete, int total, string message) { ConvertTicksToParent(ref complete, ref total); // If they send back a bogus progress value, just ignore the values if (complete < 0) { ParentProgress.UpdateProgress(message); } else { ParentProgress.UpdateProgress(complete, total, message); } }
private void DeletePost(BlogPost post, IProgressHost progress) { try { progress.UpdateProgress(Res.Get(StringId.ProgressFinalizingEditingTemplateConfig)); _blogClient.DeletePost(_blogAccount.BlogId, post.Id, true); progress.UpdateProgress(100, 100); } catch (Exception ex) { Trace.Fail("Unexpected exception occurred while deleting temporary post: " + ex.ToString()); //show a message that user needs to delete their post DisplayMessage.Show(MessageId.TempPostDeleteFailed); } }
public void UpdateProgress(int complete, int total, string message) { if (Allowed(MessageType.UpdateCompletion) && Allowed(MessageType.UpdateMessage)) { pHost.UpdateProgress(complete, total, message); } else if (Allowed(MessageType.UpdateCompletion)) { pHost.UpdateProgress(complete, total); } else if (Allowed(MessageType.UpdateMessage)) { pHost.UpdateProgress(message); } }
/// <summary> /// Initiate a download, using the progressHost to provide progress feedback /// </summary> /// <param name="progressHost">The progressHost to provide feedback to</param> /// <returns>this</returns> public object DownloadHTMLDocument(IProgressHost progressHost) { _downloadComplete = false; // Call the download method on the parent STA thread // Then wait for it to complete (the Monitor will be pulsed upon completion) _parentControl.Invoke(new Download(DoDownload), new object[] { progressHost }); lock (this) { if (_downloadComplete) { return(this); } DateTime endDateTime = DateTime.Now.AddMilliseconds(TimeoutMs); while (!_downloadComplete) { if (!Monitor.Wait(this, Math.Max(0, (int)endDateTime.Subtract(DateTime.Now).TotalMilliseconds))) { throw new OperationTimedOutException(); } } if (_downloader.Result.Exception != null) { throw _downloader.Result.Exception; } progressHost.UpdateProgress(1, 1); return(this); } }
protected void UpdateProgress(IProgressHost progressHost, int percent, string message) { //if ( CancelRequested ) // throw new OperationCancelledException() ; progressHost.UpdateProgress(percent, 100, message); }
public override void CleanupRegions(IProgressHost progress) { if (blogHomepageContents != null) { blogHomepageContents.Close(); blogHomepageContents = null; } progress.UpdateProgress(100, 100); }
public override BlogPostRegions LocateRegionsOnUIThread(IProgressHost progress) { blogHomepageContents.Seek(0, SeekOrigin.Begin); IHTMLDocument2 doc2 = HTMLDocumentHelper.GetHTMLDocumentFromStream(blogHomepageContents, _blogHomepageUrl); // Ensure that the document is fully loaded. // If it is not fully loaded, then viewing its current style is non-deterministic. DateTime startedDoingEvents = DateTime.Now; while (!progress.CancelRequested && !HTMLDocumentHelper.IsReady(doc2)) { if (DateTime.Now.Subtract(startedDoingEvents).TotalMilliseconds > 10000) { // Timing out here is not fatal. Trace.WriteLine("Timed out while loading blog homepage for theme detection."); break; } Application.DoEvents(); } //The Google/Blogger dynamic templates load the pages dynmaically usig Ajax, so we dont have any template to use. if (IsUsingDynamicTemplate(doc2)) { throw new BlogClientAbortGettingTemplateException(); } IHTMLElement[] titles = FindText(_titleText, doc2.body); IHTMLElement[] bodies = FindText(_bodyText, doc2.body); if (titles.Length == 0 || bodies.Length == 0) { throw new Exception("Unable to locate blog post elements using most recent post"); } if (IsSmartContent(bodies[0])) { throw new Exception("Most recent post is smart content"); } BlogPostRegions regions = new BlogPostRegions(); regions.TitleRegions = titles; //scrub the post body element to avoid improperly including extraneous parent elements regions.BodyRegion = ScrubPostBodyRegionParentElements(bodies[0]); regions.Document = doc2; progress.UpdateProgress(100, 100); return(regions); }
private BlogPostRegions ParseBlogPostIntoTemplate(Stream stream, string postSourceUrl, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressCreatingEditingTemplate)); //parse the document to create the blog template IHTMLDocument2 doc2 = HTMLDocumentHelper.GetHTMLDocumentFromStream(stream, postSourceUrl); IHTMLDocument3 doc = (IHTMLDocument3)doc2; IHTMLElement[] titleElements = HTMLDocumentHelper.FindElementsContainingText(doc2, TEMPORARY_POST_TITLE_GUID); IHTMLElement bodyElement = HTMLDocumentHelper.FindElementContainingText(doc2, TEMPORARY_POST_BODY_GUID); if (bodyElement != null && bodyElement.tagName == "P") { //the body element is the <p> we planted, so replace it with a DIV since that will be the safest //element to have a as parent to all post content. IHTMLElement div = doc2.createElement("div"); (bodyElement.parentElement as IHTMLDOMNode).replaceChild(div as IHTMLDOMNode, bodyElement as IHTMLDOMNode); bodyElement = div; } //locate the title element. Note that is there are more than 1 copies of the title text detected, we use the one //that is anchored closest to the left or the body element. if (titleElements.Length > 0) { BlogPostRegions regions = new BlogPostRegions(); regions.Document = (IHTMLDocument)doc; regions.TitleRegions = titleElements; regions.BodyRegion = bodyElement; progress.UpdateProgress(100, 100); return(regions); } else { throw new Exception("unable to access test post."); } }
private string DownloadManifestTemplate(IProgressHost progress, string manifestTemplateUrl) { try { // update progress progress.UpdateProgress(0, 100, Res.Get(StringId.ProgressDownloadingEditingTemplate)); // process any parameters within the url string templateUrl = BlogClientHelper.FormatUrl(manifestTemplateUrl, _blogHomepageUrl, _blogAccount.PostApiUrl, _blogAccount.BlogId); // download the url using (StreamReader streamReader = new StreamReader(_blogClient.SendAuthenticatedHttpRequest(templateUrl, 20000, null).GetResponseStream())) return(streamReader.ReadToEnd()); } catch (Exception ex) { Trace.WriteLine("Exception occurred while attempting to download template from " + manifestTemplateUrl + " :" + ex.ToString()); return(null); } finally { progress.UpdateProgress(100, 100); } }
/// <summary> /// Fetch a blog page from the URL specified and transfer it into blogPageContents /// </summary> /// <param name="progress"></param> /// <param name="url"></param> public override void FetchTemporaryPostPage(IProgressHost progress, string url) { blogPageContents = new MemoryStream(); // Download the webpage that is contains the temporary blog post // WARNING, DownloadBlogPage uses an MSHTML Document on a non-UI thread...which is a no-no! // its been this way through several betas without problem, so we'll keep it that way for now, but // it needs to be fixed eventually. Stream postHtmlContents = DownloadBlogPage(url, progress); CheckCancelRequested(progress); using (postHtmlContents) { StreamHelper.Transfer(postHtmlContents, blogPageContents); } progress.UpdateProgress(100, 100); }
/// <summary> /// The moniker calls this method repeatedly to indicate the current progress of the bind /// operation, typically at reasonable intervals during a lengthy operation. /// /// The client can use the progress notification to provide progress information to the /// user from the ulProgress, ulProgressMax, and szStatusText parameters, or to make /// programmatic decisions based on the ulStatusCode parameter. /// </summary> int IBindStatusCallback.OnProgress(uint ulProgress, uint ulProgressMax, BINDSTATUS ulStatusCode, string szStatusText) { //Debug.WriteLine( String.Format( "IBindStatusCallback.OnProgress {0}: {1} ({2}/{3})", ulStatusCode, szStatusText != null ? szStatusText : String.Empty, ulProgress, ulProgressMax ) ) ; // check for timeout if (TimeoutMs != NO_TIMEOUT) { if (DateTime.Now > _timeoutTime) { _timedOut = true; return(HRESULT.E_ABORT); } } if (ulStatusCode == BINDSTATUS.ENDDOWNLOADDATA) { // We've completed the download of the file return(HRESULT.S_OK); } else if (ulStatusCode == BINDSTATUS.MIMETYPEAVAILABLE) { // record the mime type m_contentType = szStatusText; } else if (ulStatusCode == BINDSTATUS.REDIRECTING) { _finalUrl = szStatusText; } else if ((ProgressHost != null && ProgressHost.CancelRequested) || ThreadHelper.Interrupted) { // Cancel this operation return(HRESULT.E_ABORT); } else { if (ProgressHost != null) { // UrlDownloadToFile can sometimes return progress that exceeds 100%- stop this from happening ProgressHost.UpdateProgress((int)(Math.Min(ulProgressMax, ulProgress)), (int)ulProgressMax, String.Format(CultureInfo.CurrentCulture, Res.Get(StringId.ProgressDownloading), Url)); } } return(HRESULT.S_OK); }
private void PrepareRegionsUsingTemporaryPost(IProgressHost progress) { // Publish a temporary post so that we can examine HTML that will surround posts created with the editor temporaryPost = PostTemplate(new ProgressTick(progress, 25, 100)); CheckCancelRequested(progress); blogHomepageContents = new MemoryStream(); // Download the webpage that is contains the temporary blog post // WARNING, DownloadBlogPage uses an MSHTML Document on a non-UI thread...which is a no-no! // its been this way through several betas without problem, so we'll keep it that way for now, but // it needs to be fixed eventually. Stream postHtmlContents = DownloadBlogPage(_blogHomepageUrl, progress); CheckCancelRequested(progress); using (postHtmlContents) { StreamHelper.Transfer(postHtmlContents, blogHomepageContents); } progress.UpdateProgress(100, 100); }
public object DetectSettings(IProgressHost progressHost) { using (_silentMode ? new BlogClientUIContextSilentMode() : null) { if (IncludeButtons || IncludeOptionOverrides || IncludeImages) { using (new ProgressContext(progressHost, 40, Res.Get(StringId.ProgressDetectingWeblogSettings))) { // attempt to download editing manifest WriterEditingManifest editingManifest = SafeDownloadEditingManifest(); if (editingManifest != null) { // always update the download info if (editingManifest.DownloadInfo != null) _context.ManifestDownloadInfo = editingManifest.DownloadInfo; // images if (IncludeImages) { // image if provided if (editingManifest.Image != null) _context.Image = editingManifest.Image; // watermark if provided if (editingManifest.Watermark != null) _context.WatermarkImage = editingManifest.Watermark; } // buttons if provided if (IncludeButtons && (editingManifest.ButtonDescriptions != null)) _context.ButtonDescriptions = editingManifest.ButtonDescriptions; // option overrides if provided if (IncludeOptionOverrides) { if (editingManifest.ClientType != null) _context.ClientType = editingManifest.ClientType; if (editingManifest.OptionOverrides != null) _context.OptionOverrides = editingManifest.OptionOverrides; } } } } using (new ProgressContext(progressHost, 40, Res.Get(StringId.ProgressDetectingWeblogCharSet))) { if (IncludeOptionOverrides && IncludeHomePageSettings) { DetectHomePageSettings(); } } IBlogClient blogClient = CreateBlogClient(); if (IncludeInsecureOperations || blogClient.IsSecure) { if (blogClient is ISelfConfiguringClient) { // This must happen before categories detection but after manifest!! ((ISelfConfiguringClient)blogClient).DetectSettings(_context, this); } // detect categories if (IncludeCategories) { using ( new ProgressContext(progressHost, 20, Res.Get(StringId.ProgressDetectingWeblogCategories))) { BlogPostCategory[] categories = SafeDownloadCategories(); if (categories != null) _context.Categories = categories; BlogPostKeyword[] keywords = SafeDownloadKeywords(); if (keywords != null) _context.Keywords = keywords; } } // detect favicon (only if requested AND we don't have a PNG already // for the small image size) if (IncludeFavIcon) { using (new ProgressContext(progressHost, 10, Res.Get(StringId.ProgressDetectingWeblogIcon))) { byte[] favIcon = SafeDownloadFavIcon(); if (favIcon != null) _context.FavIcon = favIcon; } } if (IncludeImageEndpoints) { Debug.WriteLine("Detecting image endpoints"); ITemporaryBlogSettingsDetectionContext tempContext = _context as ITemporaryBlogSettingsDetectionContext; Debug.Assert(tempContext != null, "IncludeImageEndpoints=true but non-temporary context (type " + _context.GetType().Name + ") was used"); if (tempContext != null) { tempContext.AvailableImageEndpoints = null; try { BlogInfo[] imageEndpoints = blogClient.GetImageEndpoints(); tempContext.AvailableImageEndpoints = imageEndpoints; Debug.WriteLine(imageEndpoints.Length + " image endpoints detected"); } catch (NotImplementedException) { Debug.WriteLine("Image endpoints not implemented"); } catch (Exception e) { Trace.Fail("Exception detecting image endpoints: " + e.ToString()); } } } } // completed progressHost.UpdateProgress(100, 100, Res.Get(StringId.ProgressCompletedSettingsDetection)); } return this; }
private BlogEditingTemplate ParseBlogPostIntoTemplate(BlogPostRegionLocatorStrategy regionLocator, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressCreatingEditingTemplate)); BlogPostRegions regions = regionLocator.LocateRegionsOnUIThread(progress); IHTMLElement primaryTitleRegion = GetPrimaryEditableTitleElement(regions.BodyRegion, regions.Document, regions.TitleRegions); BlogEditingTemplate template = GenerateBlogTemplate((IHTMLDocument3)regions.Document, primaryTitleRegion, regions.TitleRegions, regions.BodyRegion); progress.UpdateProgress(100, 100); return template; }
private string DownloadTemplateFiles(string templateContents, string templateUrl, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressDownloadingSupportingFiles)); FileBasedSiteStorage files = new FileBasedSiteStorage(_blogTemplateDir); // convert the string to a stream MemoryStream templateStream = new MemoryStream(); StreamWriter writer = new StreamWriter(templateStream, Encoding.UTF8); writer.Write(templateContents); writer.Flush(); templateStream.Seek(0, SeekOrigin.Begin); //read the stream into a lightweight HTML. Note that we use from LightWeightHTMLDocument.FromIHTMLDocument2 //instead of LightWeightHTMLDocument.FromStream because from stream improperly shoves a saveFrom declaration //above the docType (bug 289357) IHTMLDocument2 doc = HTMLDocumentHelper.StreamToHTMLDoc(templateStream, templateUrl, true); LightWeightHTMLDocument ldoc = LightWeightHTMLDocument.FromIHTMLDocument2(doc, templateUrl, true, false); PageDownloadContext downloadContext = new PageDownloadContext(0); ApplyCredentials(downloadContext, templateUrl); using (PageToDownloadFactory downloadFactory = new PageToDownloadFactory(ldoc, downloadContext, _parentControl)) { //calculate the dependent styles and resources ProgressTick tick = new ProgressTick(progress, 50, 100); downloadFactory.CreatePagesToDownload(tick); tick.UpdateProgress(100, 100); //download the dependent styles and resources tick = new ProgressTick(progress, 50, 100); PageAndReferenceDownloader downloader = new PageAndReferenceDownloader(downloadFactory.PagesToDownload, files); this.ApplyCredentials(downloader, templateUrl); downloader.Download(tick); tick.UpdateProgress(100, 100); //Expand out the relative paths in the downloaded HTML file with absolute paths. //Note: this is necessary so that template resources are not improperly resolved relative // to the location of the file the editor is editing. string blogTemplateFile = Path.Combine(_blogTemplateDir, files.RootFile); string origFile = blogTemplateFile + ".token"; File.Move(blogTemplateFile, origFile); string absPath = String.Format(CultureInfo.InvariantCulture, "file:///{0}/{1}", _blogTemplateDir.Replace('\\', '/'), downloader.PathToken); TextHelper.ReplaceInFile(origFile, downloader.PathToken, blogTemplateFile, absPath); File.Delete(origFile); //fix up the files FixupDownloadedFiles(blogTemplateFile, files, downloader.PathToken); //complete the progress. progress.UpdateProgress(100, 100); File.WriteAllText(blogTemplateFile + ".path", absPath); return blogTemplateFile; } }
private BlogPost PostTemplate(IProgressHost progress) { progress.UpdateProgress(50, 100); // make a test post that we can use to do analysis BlogPost testPost = new BlogPost(); testPost.IsTemporary = true; testPost.Title = TEMPORARY_POST_TITLE; //plant a <p> around the contents so that the blog provider doesn't try to add their own //and so we'll know it can be safely removed later //Note: this fixes an issue where the editor's postBody <div> was being parented improperly by //a <p> element that the blog service was adding... string postContents = String.Format(CultureInfo.InvariantCulture, "<p>{0}</p>", TEMPORARY_POST_BODY); testPost.Contents = postContents; string etag; XmlDocument remotePost; testPost.Id = _blogClient.NewPost(_blogAccount.BlogId, testPost, new IgnoreNewCategoryContext(), true, out etag, out remotePost); testPost.ETag = etag; testPost.AtomRemotePost = remotePost; progress.UpdateProgress(100, 100); return testPost; }
private void DeletePost(BlogPost post, IProgressHost progress) { try { progress.UpdateProgress(Res.Get(StringId.ProgressFinalizingEditingTemplateConfig)); _blogClient.DeletePost(_blogAccount.BlogId, post.Id, true); progress.UpdateProgress(100, 100); } catch (Exception ex) { Trace.Fail("Unexpected exception occurred while deleting temporary post: " + ex.ToString()); //show a message that user needs to delete their post DisplayMessage.Show(MessageId.TempPostDeleteFailed); } }
/// <summary> /// /// </summary> /// <param name="progress"></param> /// <param name="targetTemplateTypes"></param> /// <param name="templateStrategies">equivalent strategies for manipulating the blog homepage DOM into an editing template type</param> /// <returns></returns> private BlogEditingTemplateFile[] DetectTemplates(IProgressHost progress, BlogEditingTemplateType[] targetTemplateTypes, BlogEditingTemplateStrategy[] templateStrategies) { RecentPostRegionLocatorStrategy recentPostLocatorStrategy = new RecentPostRegionLocatorStrategy(_blogClient, _blogAccount, _credentials, _blogHomepageUrl, new PageDownloader(RequestPageDownload)); TemporaryPostRegionLocatorStrategy tempPostLocatorStrategy = new TemporaryPostRegionLocatorStrategy(_blogClient, _blogAccount, _credentials, _blogHomepageUrl, new PageDownloader(RequestPageDownload), new BlogPostRegionLocatorBooleanCallback(recentPostLocatorStrategy.HasBlogPosts)); //setup the strategies for locating the title/body regions in the blog homepage. BlogPostRegionLocatorStrategy[] regionLocatorStrategies = new BlogPostRegionLocatorStrategy[] { recentPostLocatorStrategy, tempPostLocatorStrategy }; // template files to return BlogEditingTemplateFile[] blogTemplateFiles = null; // try each strategy as necessary for (int i = 0; i < regionLocatorStrategies.Length && blogTemplateFiles == null; i++) { CheckCancelRequested(progress); //reset the progress for each iteration BlogPostRegionLocatorStrategy regionLocatorStrategy = regionLocatorStrategies[i]; try { blogTemplateFiles = GetBlogTemplateFiles(progress, regionLocatorStrategy, templateStrategies, targetTemplateTypes); progress.UpdateProgress(100, 100); //if any exception occured along the way, clear them since one of the template strategies //was successful. _exception = null; } catch (OperationCancelledException) { // cancel just means our template will be String.Empty _exception = null; } catch (BlogClientOperationCancelledException e) { // cancel just means our template will be String.Empty // (setting this exception here means that at least the user // will be notified that they won't be able to edit with style) _exception = e; } catch (WebException e) { _exception = e; Trace.WriteLine("Error occurred while downloading weblog style: " + e.ToString()); if (e.Response != null) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Blogpost homepage request failed: {0}", _blogHomepageUrl)); //Debug.WriteLine(HttpRequestHelper.DumpResponse((HttpWebResponse)e.Response)); } } catch (Exception e) { _exception = e; Trace.WriteLine("Error occurred while downloading weblog style: " + e.ToString()); } } // return the detected tempaltes return blogTemplateFiles; }
private BlogPostRegions ParseBlogPostIntoTemplate(Stream stream, string postSourceUrl, IProgressHost progress) { progress.UpdateProgress(Res.Get(StringId.ProgressCreatingEditingTemplate)); //parse the document to create the blog template IHTMLDocument2 doc2 = HTMLDocumentHelper.GetHTMLDocumentFromStream(stream, postSourceUrl); IHTMLDocument3 doc = (IHTMLDocument3)doc2; IHTMLElement[] titleElements = HTMLDocumentHelper.FindElementsContainingText(doc2, TEMPORARY_POST_TITLE_GUID); IHTMLElement bodyElement = HTMLDocumentHelper.FindElementContainingText(doc2, TEMPORARY_POST_BODY_GUID); if (bodyElement != null && bodyElement.tagName == "P") { //the body element is the <p> we planted, so replace it with a DIV since that will be the safest //element to have a as parent to all post content. IHTMLElement div = doc2.createElement("div"); (bodyElement.parentElement as IHTMLDOMNode).replaceChild(div as IHTMLDOMNode, bodyElement as IHTMLDOMNode); bodyElement = div; } //locate the title element. Note that is there are more than 1 copies of the title text detected, we use the one //that is anchored closest to the left or the body element. if (titleElements.Length > 0) { BlogPostRegions regions = new BlogPostRegions(); regions.Document = (IHTMLDocument)doc; regions.TitleRegions = titleElements; regions.BodyRegion = bodyElement; progress.UpdateProgress(100, 100); return regions; } else { throw new Exception("unable to access test post."); } }
private BlogEditingTemplateFiles SafeGetTemplates(IProgressHost progress) { WriterEditingManifest editingManifest = null; BlogEditingTemplateFiles templateFiles = new BlogEditingTemplateFiles(); try { // if we have a manifest url then try to get our manifest if (_manifestDownloadInfo != null) { // try to get the editing manifest string manifestUrl = _manifestDownloadInfo.SourceUrl; editingManifest = WriterEditingManifest.FromUrl( new Uri(manifestUrl), _blogClient, _credentials, true); // progress CheckCancelRequested(progress); progress.UpdateProgress(20, 100); } // if we have no editing manifest then probe (if allowed) if ((editingManifest == null) && _probeForManifest) { editingManifest = WriterEditingManifest.FromHomepage( new LazyHomepageDownloader(_blogHomepageUrl, new HttpRequestHandler(_blogClient.SendAuthenticatedHttpRequest)), new Uri(_blogHomepageUrl), _blogClient, _credentials); } // progress CheckCancelRequested(progress); progress.UpdateProgress(40, 100); // if we got one then return templates from it as-appropriate if (editingManifest != null) { if (editingManifest.WebLayoutUrl != null) { string webLayoutTemplate = DownloadManifestTemplate(new ProgressTick(progress, 10, 100), editingManifest.WebLayoutUrl); if (BlogEditingTemplate.ValidateTemplate(webLayoutTemplate)) { // download supporting files string templateFile = DownloadTemplateFiles(webLayoutTemplate, _blogHomepageUrl, new ProgressTick(progress, 20, 100)); // return the template templateFiles.FramedTemplate = new BlogEditingTemplateFile(BlogEditingTemplateType.Framed, templateFile); } else { Trace.WriteLine("Invalid webLayoutTemplate specified in manifest"); } } if (editingManifest.WebPreviewUrl != null) { string webPreviewTemplate = DownloadManifestTemplate(new ProgressTick(progress, 10, 100), editingManifest.WebPreviewUrl); if (BlogEditingTemplate.ValidateTemplate(webPreviewTemplate)) { // download supporting files string templateFile = DownloadTemplateFiles(webPreviewTemplate, _blogHomepageUrl, new ProgressTick(progress, 20, 100)); // return the template templateFiles.WebPageTemplate = new BlogEditingTemplateFile(BlogEditingTemplateType.Webpage, templateFile); } else { Trace.WriteLine("Invalid webPreviewTemplate specified in manifest"); } } } } catch { } finally { progress.UpdateProgress(100, 100); } return templateFiles; }
/// <summary> /// Creates a set of BlogTemplateFiles using a specific region locator strategy. /// </summary> /// <param name="progress"></param> /// <param name="regionLocatorStrategy"></param> /// <param name="templateStrategies"></param> /// <param name="templateTypes"></param> /// <param name="targetUrl"> /// The URL to analyze. If a post can be located, but not the body, this is used /// to reiterate into the post it fetch it's content directly. /// </param> /// <returns></returns> private BlogEditingTemplateFile[] GetBlogTemplateFiles(IProgressHost progress, BlogPostRegionLocatorStrategy regionLocatorStrategy, BlogEditingTemplateStrategy[] templateStrategies, BlogEditingTemplateType[] templateTypes, string targetUrl) { BlogEditingTemplateFile[] blogTemplateFiles = null; try { regionLocatorStrategy.PrepareRegions(new ProgressTick(progress, 25, 100)); ArrayList templateFiles = new ArrayList(); ProgressTick tick = new ProgressTick(progress, 50, 100); for (int i = 0; i < templateTypes.Length; i++) { ProgressTick parseTick = new ProgressTick(tick, 1, templateTypes.Length); try { CheckCancelRequested(parseTick); templateStrategy = templateStrategies[i]; // Clear _nextTryPostUrl flag _nextTryPostUrl = null; // Parse the blog post HTML into an editing template. // Note: we can't use MarkupServices to parse the document from a non-UI thread, // so we have to execute the parsing portion of the template download operation on the UI thread. string editingTemplate = ParseWebpageIntoEditingTemplate_OnUIThread(_parentControl, regionLocatorStrategy, new ProgressTick(parseTick, 1, 5), targetUrl); // If there's no editing template, there should be a URL to try next Debug.Assert(editingTemplate != null || (editingTemplate == null && _nextTryPostUrl != null)); // If the homepage has just been analysed and the _nextTryPostUrl flag is set if (targetUrl == _blogHomepageUrl && _nextTryPostUrl != null && regionLocatorStrategy.CanRefetchPage) { // Try fetching the URL that has been specified, and reparse progress.UpdateProgress(Res.Get(StringId.ProgressDownloadingWeblogEditingStyleDeep)); // Fetch the post page regionLocatorStrategy.FetchTemporaryPostPage(SilentProgressHost.Instance, _nextTryPostUrl); // Parse out the template editingTemplate = ParseWebpageIntoEditingTemplate_OnUIThread(_parentControl, regionLocatorStrategy, new ProgressTick(parseTick, 1, 5), _nextTryPostUrl); } // check for cancel CheckCancelRequested(parseTick); string baseUrl = HTMLDocumentHelper.GetBaseUrl(editingTemplate, _blogHomepageUrl); // Download the template stylesheets and embedded resources (this lets the editing template load faster..and works offline!) string templateFile = DownloadTemplateFiles(editingTemplate, baseUrl, new ProgressTick(parseTick, 4, 5)); templateFiles.Add(new BlogEditingTemplateFile(templateTypes[i], templateFile)); } catch (BlogClientAbortGettingTemplateException) { Trace.WriteLine(String.Format(CultureInfo.CurrentCulture, "Failed to download template {0}. Aborting getting further templates", templateTypes[i].ToString())); throw; } catch (Exception e) { Trace.WriteLine(String.Format(CultureInfo.CurrentCulture, "Failed to download template {0}: {1}", templateTypes[i].ToString(), e.ToString())); } } if (templateFiles.Count > 0) { blogTemplateFiles = (BlogEditingTemplateFile[])templateFiles.ToArray(typeof(BlogEditingTemplateFile)); } } finally { regionLocatorStrategy.CleanupRegions(new ProgressTick(progress, 25, 100)); } return(blogTemplateFiles); }
public object DetectTemplate(IProgressHost progress) { // if our context has not been set then just return without doing anything // (supports this being an optional step at the end of a chain of // other progress operations) if (_contextSet == false) { return(this); } using (BlogClientUIContextScope uiContextScope = new BlogClientUIContextScope(_uiContext)) { // initial progress progress.UpdateProgress(Res.Get(StringId.ProgressDetectingWeblogEditingStyle)); // build list of detected templates ArrayList blogTemplateFiles = new ArrayList(); // build list of template types that we need to auto-detect ArrayList detectionTargetTypes = new ArrayList(); ArrayList detectionTargetStrategies = new ArrayList(); // try explicit detection of templates BlogEditingTemplateFiles templateFiles = SafeGetTemplates(new ProgressTick(progress, 50, 100)); // see if we got the FramedTemplate if (templateFiles.FramedTemplate != null) { blogTemplateFiles.Add(templateFiles.FramedTemplate); } else { detectionTargetTypes.Add(BlogEditingTemplateType.Framed); detectionTargetStrategies.Add(BlogEditingTemplateStrategies.GetTemplateStrategy(BlogEditingTemplateStrategies.StrategyType.NoSiblings)); } // see if we got the WebPageTemplate if (templateFiles.WebPageTemplate != null) { blogTemplateFiles.Add(templateFiles.WebPageTemplate); } else { detectionTargetTypes.Add(BlogEditingTemplateType.Webpage); detectionTargetStrategies.Add(BlogEditingTemplateStrategies.GetTemplateStrategy(BlogEditingTemplateStrategies.StrategyType.Site)); } // perform detection if we have detection targets if (detectionTargetTypes.Count > 0) { BlogEditingTemplateFile[] detectedBlogTemplateFiles = DetectTemplates(new ProgressTick(progress, 50, 100), detectionTargetTypes.ToArray(typeof(BlogEditingTemplateType)) as BlogEditingTemplateType[], detectionTargetStrategies.ToArray(typeof(BlogEditingTemplateStrategy)) as BlogEditingTemplateStrategy[]); if (detectedBlogTemplateFiles != null) { blogTemplateFiles.AddRange(detectedBlogTemplateFiles); } } // updates member if we succeeded if (blogTemplateFiles.Count > 0) { // capture template files _blogTemplateFiles = blogTemplateFiles.ToArray(typeof(BlogEditingTemplateFile)) as BlogEditingTemplateFile[]; // if we got at least one template by some method then clear any exception // that occurs so we can at least update that template _exception = null; } foreach (BlogEditingTemplateFile file in blogTemplateFiles) { if (file.TemplateType == BlogEditingTemplateType.Webpage) { _postBodyBackgroundColor = BackgroundColorDetector.DetectColor(UrlHelper.SafeToAbsoluteUri(new Uri(file.TemplateFile)), _postBodyBackgroundColor); } } // return return(this); } }
public ProgressContext(IProgressHost progressHost, int complete, string message) { _progressHost = progressHost; _progressHost.UpdateProgress(complete, 100, message); }
public override void CleanupRegions(IProgressHost progress) { if (blogHomepageContents != null) { blogHomepageContents.Close(); blogHomepageContents = null; } progress.UpdateProgress(100, 100); }
public object DetectTemplate(IProgressHost progress) { // if our context has not been set then just return without doing anything // (supports this being an optional step at the end of a chain of // other progress operations) if (_contextSet == false) return this; using (BlogClientUIContextScope uiContextScope = new BlogClientUIContextScope(_uiContext)) { // initial progress progress.UpdateProgress(Res.Get(StringId.ProgressDetectingWeblogEditingStyle)); // build list of detected templates ArrayList blogTemplateFiles = new ArrayList(); // build list of template types that we need to auto-detect ArrayList detectionTargetTypes = new ArrayList(); ArrayList detectionTargetStrategies = new ArrayList(); // try explicit detection of templates BlogEditingTemplateFiles templateFiles = SafeGetTemplates(new ProgressTick(progress, 50, 100)); // see if we got the FramedTempalte if (templateFiles.FramedTemplate != null) blogTemplateFiles.Add(templateFiles.FramedTemplate); else { detectionTargetTypes.Add(BlogEditingTemplateType.Framed); detectionTargetStrategies.Add(BlogEditingTemplateStrategies.GetTemplateStrategy(BlogEditingTemplateStrategies.StrategyType.NoSiblings)); } // see if we got the WebPageTemplate if (templateFiles.WebPageTemplate != null) blogTemplateFiles.Add(templateFiles.WebPageTemplate); else { detectionTargetTypes.Add(BlogEditingTemplateType.Webpage); detectionTargetStrategies.Add(BlogEditingTemplateStrategies.GetTemplateStrategy(BlogEditingTemplateStrategies.StrategyType.Site)); } // perform detection if we have detection targets if (detectionTargetTypes.Count > 0) { BlogEditingTemplateFile[] detectedBlogTemplateFiles = DetectTemplates(new ProgressTick(progress, 50, 100), detectionTargetTypes.ToArray(typeof(BlogEditingTemplateType)) as BlogEditingTemplateType[], detectionTargetStrategies.ToArray(typeof(BlogEditingTemplateStrategy)) as BlogEditingTemplateStrategy[]); if (detectedBlogTemplateFiles != null) blogTemplateFiles.AddRange(detectedBlogTemplateFiles); } // updates member if we succeeded if (blogTemplateFiles.Count > 0) { // capture template files _blogTemplateFiles = blogTemplateFiles.ToArray(typeof(BlogEditingTemplateFile)) as BlogEditingTemplateFile[]; // if we got at least one template by some method then clear any exception // that occurs so we can at least update that tempalte _exception = null; } foreach (BlogEditingTemplateFile file in blogTemplateFiles) { if (file.TemplateType == BlogEditingTemplateType.Webpage) { _postBodyBackgroundColor = BackgroundColorDetector.DetectColor(UrlHelper.SafeToAbsoluteUri(new Uri(file.TemplateFile)), _postBodyBackgroundColor); } } // return return this; } }
/// <summary> /// Actually downloads the pages /// </summary> private PageToDownload[] DownloadPages(IProgressHost progress, string url, LightWeightHTMLDocument lightWeightDocument, PageToDownload parentPageToDownload) { // Check for cancel if (progress.CancelRequested) throw new OperationCancelledException(); _currentDepth++; ArrayList downloadedPages = new ArrayList(); // Set up our progress int thisPageTicks = FIRSTPAGETICKS; if (_context.Depth == _currentDepth) thisPageTicks = TOTALTICKS; ProgressTick firstPagedownloadProgress = new ProgressTick(progress, thisPageTicks, TOTALTICKS); string safeUrl = UrlHelper.GetUrlWithoutAnchorIdentifier(url); // Look up the content type of this pageToDownload UrlContentTypeInfo headerInfo = null; if (_headerInfo.ContainsKey(safeUrl)) { headerInfo = (UrlContentTypeInfo)_headerInfo[safeUrl]; } else { if (lightWeightDocument != null) headerInfo = new UrlContentTypeInfo("text/html", url); else if (headerInfo == null && !_context.IsTimedOutUrl(url) && _context.ShouldDownloadThisUrl(url)) { progress.UpdateProgress(string.Format(CultureInfo.CurrentCulture, Res.Get(StringId.ProgressDeterminingType), url)); if (lightWeightDocument == null) headerInfo = ContentTypeHelper.ExpensivelyGetUrlContentType(url, _context.TimeoutMS); else headerInfo = ContentTypeHelper.InexpensivelyGetUrlContentType(url); } _headerInfo.Add(safeUrl, headerInfo); } // If this is a web page and we should download it, do it! if ((lightWeightDocument != null && IsDownloadablePageResource(headerInfo)) || (lightWeightDocument == null && IsDownloadablePageResource(headerInfo) && _context.ShouldDownloadThisUrl(headerInfo)) ) { bool downloadWorked = false; int downloadAttempts = -1; bool timedOut = true; // Max sure we are retrying the correct number of times ProgressTick pageDownloadProgress = new ProgressTick(firstPagedownloadProgress, 80, 100); while (!downloadWorked && downloadAttempts++ < _context.RetryCount && timedOut) { timedOut = false; pageDownloadProgress.UpdateProgress(0, 1); try { // If we haven't downloaded this page yet download it PageToDownload thisPageToDownload = null; if (!_context.UrlAlreadyDownloaded(safeUrl)) { if (lightWeightDocument == null) thisPageToDownload = DownloadUrl(url, parentPageToDownload, pageDownloadProgress); else { LightWeightHTMLDocument htmlDoc = lightWeightDocument; // Only redownload if we absolutely need to if (htmlDoc.HasFramesOrStyles && (htmlDoc.Frames == null || htmlDoc.StyleResourcesUrls == null)) { string html = htmlDoc.GenerateHtml(); string tempFile = TempFileManager.Instance.CreateTempFile("temp.htm"); using (StreamWriter writer = new StreamWriter(tempFile, false, Encoding.UTF8)) writer.Write(html); using (HTMLDocumentDownloader downloader = new HTMLDocumentDownloader(_parentControl, UrlHelper.GetLocalFileUrl(tempFile), htmlDoc.Title, _context.CookieString, _context.TimeoutMS, false)) { downloader.DownloadHTMLDocument(pageDownloadProgress); htmlDoc.UpdateBasedUponHTMLDocumentData(downloader.HtmlDocument, url); } } thisPageToDownload = new PageToDownload(htmlDoc, url, null, parentPageToDownload); if (htmlDoc.StyleResourcesUrls != null) foreach (HTMLDocumentHelper.ResourceUrlInfo styleUrl in htmlDoc.StyleResourcesUrls) thisPageToDownload.AddReference(new ReferenceToDownload(styleUrl.ResourceUrl, thisPageToDownload, styleUrl.ResourceAbsoluteUrl)); } // Add this page to our lists _context.AddPageToDownload(safeUrl, thisPageToDownload, true); downloadedPages.Add(thisPageToDownload); } else thisPageToDownload = (PageToDownload)_context.CreatedPageToDownloadTable[safeUrl]; // If we're downloading a site, add a second copy of the root page in the references subdir // This was, if the root page gets renamed, links back to it will still work correctly // This is a bit of a hack, but otherwise, we'll need to escape urls whenever we output // the site and change the root file name if (thisPageToDownload.IsRootPage && _context.Depth > 0) { PageToDownload copyOfThisPageToDownload = new PageToDownload(thisPageToDownload.LightWeightHTMLDocument.Clone(), thisPageToDownload.UrlToReplace, thisPageToDownload.FileName, thisPageToDownload); downloadedPages.Add(copyOfThisPageToDownload); } // enumerate the frames of this page and add them to the list of pages PageToDownload[] subFramesToDownload = GetFramePagesToDownload(thisPageToDownload); downloadedPages.AddRange(subFramesToDownload); foreach (PageToDownload pageToDownload in subFramesToDownload) _context.AddPageToDownload(pageToDownload.AbsoluteUrl, pageToDownload, false); // Now drill down based upon the depth configuration if (_context.ShouldContinue(_currentDepth)) { ProgressTick otherPagesdownloadProgress = new ProgressTick(progress, TOTALTICKS - thisPageTicks, TOTALTICKS); downloadedPages.AddRange(GetSubPagesToDownload(otherPagesdownloadProgress, downloadedPages, thisPageToDownload)); } downloadWorked = true; firstPagedownloadProgress.UpdateProgress(1, 1); } catch (OperationTimedOutException) { timedOut = true; } catch (WebPageDownloaderException htex) { HandleException(new Exception(htex.Message, htex)); } catch (Exception ex) { HandleException(new Exception(String.Format(CultureInfo.CurrentCulture, "{0} could not be downloaded", _url), ex)); } } // If we never got the download to succeed, add it to the list of timed out Urls if (!downloadWorked && timedOut) { _context.AddTimedOutUrl(_url); firstPagedownloadProgress.UpdateProgress(1, 1); } } // If it isn't a page we'll just add the file to the reference list for the parent page // There is not an else, because we could be looking at a reference, but a reference that // should not be downloaded (in which case we just ignore it) else if (headerInfo != null && _context.ShouldDownloadThisUrl(headerInfo)) { parentPageToDownload.AddReference(new ReferenceToDownload(url, parentPageToDownload)); progress.UpdateProgress(1, 1); } progress.UpdateProgress(1, 1); _currentDepth--; return (PageToDownload[])downloadedPages.ToArray(typeof(PageToDownload)); }
private BlogEditingTemplateFiles SafeGetTemplates(IProgressHost progress) { WriterEditingManifest editingManifest = null; BlogEditingTemplateFiles templateFiles = new BlogEditingTemplateFiles(); try { // if we have a manifest url then try to get our manifest if (_manifestDownloadInfo != null) { // try to get the editing manifest string manifestUrl = _manifestDownloadInfo.SourceUrl; editingManifest = WriterEditingManifest.FromUrl( new Uri(manifestUrl), _blogClient, _credentials, true); // progress CheckCancelRequested(progress); progress.UpdateProgress(20, 100); } // if we have no editing manifest then probe (if allowed) if ((editingManifest == null) && _probeForManifest) { editingManifest = WriterEditingManifest.FromHomepage( new LazyHomepageDownloader(_blogHomepageUrl, new HttpRequestHandler(_blogClient.SendAuthenticatedHttpRequest)), new Uri(_blogHomepageUrl), _blogClient, _credentials); } // progress CheckCancelRequested(progress); progress.UpdateProgress(40, 100); // if we got one then return templates from it as-appropriate if (editingManifest != null) { if (editingManifest.WebLayoutUrl != null) { string webLayoutTemplate = DownloadManifestTemplate(new ProgressTick(progress, 10, 100), editingManifest.WebLayoutUrl); if (BlogEditingTemplate.ValidateTemplate(webLayoutTemplate)) { // download supporting files string templateFile = DownloadTemplateFiles(webLayoutTemplate, _blogHomepageUrl, new ProgressTick(progress, 20, 100)); // return the template templateFiles.FramedTemplate = new BlogEditingTemplateFile(BlogEditingTemplateType.Framed, templateFile); } else { Trace.WriteLine("Invalid webLayoutTemplate specified in manifest"); } } if (editingManifest.WebPreviewUrl != null) { string webPreviewTemplate = DownloadManifestTemplate(new ProgressTick(progress, 10, 100), editingManifest.WebPreviewUrl); if (BlogEditingTemplate.ValidateTemplate(webPreviewTemplate)) { // download supporting files string templateFile = DownloadTemplateFiles(webPreviewTemplate, _blogHomepageUrl, new ProgressTick(progress, 20, 100)); // return the template templateFiles.WebPageTemplate = new BlogEditingTemplateFile(BlogEditingTemplateType.Webpage, templateFile); } else { Trace.WriteLine("Invalid webPreviewTemplate specified in manifest"); } } } } catch { } finally { progress.UpdateProgress(100, 100); } return(templateFiles); }
private void PrepareRegionsUsingTemporaryPost(IProgressHost progress) { // Publish a temporary post so that we can examine HTML that will surround posts created with the editor temporaryPost = PostTemplate(new ProgressTick(progress, 25, 100)); CheckCancelRequested(progress); blogHomepageContents = new MemoryStream(); // Download the webpage that is contains the temporary blog post // WARNING, DownloadBlogPage uses an MSHTML Document on a non-UI thread...which is a no-no! // its been this way through several betas without problem, so we'll keep it that way for now, but // it needs to be fixed eventually. Stream postHtmlContents = DownloadBlogPage(_blogHomepageUrl, progress); CheckCancelRequested(progress); using (postHtmlContents) { StreamHelper.Transfer(postHtmlContents, blogHomepageContents); } progress.UpdateProgress(100, 100); }
/// <summary> /// /// </summary> /// <param name="progress"></param> /// <param name="targetTemplateTypes"></param> /// <param name="templateStrategies">equivalent strategies for manipulating the blog homepage DOM into an editing template type</param> /// <returns></returns> private BlogEditingTemplateFile[] DetectTemplates(IProgressHost progress, BlogEditingTemplateType[] targetTemplateTypes, BlogEditingTemplateStrategy[] templateStrategies) { RecentPostRegionLocatorStrategy recentPostLocatorStrategy = new RecentPostRegionLocatorStrategy(_blogClient, _blogAccount, _credentials, _blogHomepageUrl, new PageDownloader(RequestPageDownload)); TemporaryPostRegionLocatorStrategy tempPostLocatorStrategy = new TemporaryPostRegionLocatorStrategy(_blogClient, _blogAccount, _credentials, _blogHomepageUrl, new PageDownloader(RequestPageDownload), new BlogPostRegionLocatorBooleanCallback(recentPostLocatorStrategy.HasBlogPosts)); //setup the strategies for locating the title/body regions in the blog homepage. BlogPostRegionLocatorStrategy[] regionLocatorStrategies = new BlogPostRegionLocatorStrategy[] { recentPostLocatorStrategy, tempPostLocatorStrategy }; // template files to return BlogEditingTemplateFile[] blogTemplateFiles = null; // try each strategy as necessary for (int i = 0; i < regionLocatorStrategies.Length && blogTemplateFiles == null; i++) { CheckCancelRequested(progress); //reset the progress for each iteration BlogPostRegionLocatorStrategy regionLocatorStrategy = regionLocatorStrategies[i]; try { blogTemplateFiles = GetBlogTemplateFiles(progress, regionLocatorStrategy, templateStrategies, targetTemplateTypes, _blogHomepageUrl); progress.UpdateProgress(100, 100); //if any exception occurred along the way, clear them since one of the template strategies //was successful. _exception = null; } catch (OperationCancelledException) { // cancel just means our template will be String.Empty _exception = null; } catch (BlogClientOperationCancelledException e) { // cancel just means our template will be String.Empty // (setting this exception here means that at least the user // will be notified that they won't be able to edit with style) _exception = e; } catch (BlogClientAbortGettingTemplateException e) { _exception = e; //Do not proceed with the other strategies if getting the template was aborted. break; } catch (WebException e) { _exception = e; Trace.WriteLine("Error occurred while downloading weblog style: " + e.ToString()); if (e.Response != null) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Blogpost homepage request failed: {0}", _blogHomepageUrl)); //Debug.WriteLine(HttpRequestHelper.DumpResponse((HttpWebResponse)e.Response)); } } catch (Exception e) { _exception = e; Trace.WriteLine("Error occurred while downloading weblog style: " + e.ToString()); } } // return the detected templates return(blogTemplateFiles); }
public override BlogPostRegions LocateRegionsOnUIThread(IProgressHost progress) { blogHomepageContents.Seek(0, SeekOrigin.Begin); IHTMLDocument2 doc2 = HTMLDocumentHelper.GetHTMLDocumentFromStream(blogHomepageContents, _blogHomepageUrl); // Ensure that the document is fully loaded. // If it is not fully loaded, then viewing its current style is non-deterministic. DateTime startedDoingEvents = DateTime.Now; while (!progress.CancelRequested && !HTMLDocumentHelper.IsReady(doc2)) { if (DateTime.Now.Subtract(startedDoingEvents).TotalMilliseconds > 10000) { // Timing out here is not fatal. Trace.WriteLine("Timed out while loading blog homepage for theme detection."); break; } Application.DoEvents(); } IHTMLElement[] titles = FindText(_titleText, doc2.body); IHTMLElement[] bodies = FindText(_bodyText, doc2.body); if (titles.Length == 0 || bodies.Length == 0) throw new Exception("Unable to locate blog post elements using most recent post"); if (IsSmartContent(bodies[0])) throw new Exception("Most recent post is smart content"); BlogPostRegions regions = new BlogPostRegions(); regions.TitleRegions = titles; //scrub the post body element to avoid improperly including extraneous parent elements regions.BodyRegion = ScrubPostBodyRegionParentElements(bodies[0]); regions.Document = doc2; progress.UpdateProgress(100, 100); return regions; }
/// <summary> /// Downloads the pages and their references, providing progress feedback /// </summary> /// <param name="progressHost">The progresshost to use for feedback</param> /// <returns>this</returns> public object Download(IProgressHost progressHost) { // Prepare the list of references to download progressHost.UpdateProgress(Res.Get(StringId.ProgressPreparingListOfFiles)); foreach (PageToDownload pageToDownload in _pagesToDownload) { // Lay down a placeholder file with the correct file name try { string destination = Path.Combine(_siteStorage.BasePath, pageToDownload.RelativePath); destination = PathHelper.GetNonConflictingPath(destination); pageToDownload.FileName = Path.GetFileName(destination); using (Stream htmlStream = _siteStorage.Open(destination, AccessMode.Write)) { } } catch (Exception e) { HandleException(e); } foreach (ReferenceToDownload reference in pageToDownload.References) { // Don't add the same item more than once if (!_referencesToDownload.ContainsKey(reference.AbsoluteUrl)) _referencesToDownload.Add(reference.AbsoluteUrl, reference); } } // Enqueue the work items progressHost.UpdateProgress(Res.Get(StringId.ProgressStartingDownloadOfReferences)); IProgressHost[] progressHosts = new JointProgressHosts(progressHost, _referencesToDownload.Count, 8000, 10000).ProgressHosts; int tickNum = 0; foreach (ReferenceToDownload reference in _referencesToDownload.Values) workQueue.Enqueue(new DownloadWorkItem(reference, _siteStorage, progressHosts[tickNum++])); // Start up the parallel execution of the downloads ParallelExecution parallelExecution = new ParallelExecution(new ThreadStart(WorkerThreadStart), 2); parallelExecution.Execute(); parallelExecution = null; // Now go through and get HTML for each page, and emit the HTML to disk ProgressTick allPagesProgress = new ProgressTick(progressHost, 2000, 10000); for (int i = 0; i < _pagesToDownload.Length; i++) { try { allPagesProgress.UpdateProgress(i, _pagesToDownload.Length, string.Format(CultureInfo.CurrentCulture, Res.Get(StringId.ProgressSaving), _pagesToDownload[i].FileName)); WriteHtmlToDisk(_pagesToDownload[i], _siteStorage); } catch (Exception e) { HandleException(e); } if (allPagesProgress.CancelRequested) throw new OperationCancelledException(); } // We're complete! progressHost.UpdateProgress(1, 1, Res.Get(StringId.ProgressDownloadFinished)); return this; }
private string DownloadManifestTemplate(IProgressHost progress, string manifestTemplateUrl) { try { // update progress progress.UpdateProgress(0, 100, Res.Get(StringId.ProgressDownloadingEditingTemplate)); // process any parameters within the url string templateUrl = BlogClientHelper.FormatUrl(manifestTemplateUrl, _blogHomepageUrl, _blogAccount.PostApiUrl, _blogAccount.BlogId); // download the url using (StreamReader streamReader = new StreamReader(_blogClient.SendAuthenticatedHttpRequest(templateUrl, 20000, null).GetResponseStream())) return streamReader.ReadToEnd(); } catch (Exception ex) { Trace.WriteLine("Exception occurred while attempting to download template from " + manifestTemplateUrl + " :" + ex.ToString()); return null; } finally { progress.UpdateProgress(100, 100); } }
public object DetectSettings(IProgressHost progressHost) { using (_silentMode ? new BlogClientUIContextSilentMode() : null) { if (IncludeButtons || IncludeOptionOverrides || IncludeImages) { using (new ProgressContext(progressHost, 40, Res.Get(StringId.ProgressDetectingWeblogSettings))) { // attempt to download editing manifest WriterEditingManifest editingManifest = SafeDownloadEditingManifest(); if (editingManifest != null) { // always update the download info if (editingManifest.DownloadInfo != null) { _context.ManifestDownloadInfo = editingManifest.DownloadInfo; } // images if (IncludeImages) { // image if provided if (editingManifest.Image != null) { _context.Image = editingManifest.Image; } // watermark if provided if (editingManifest.Watermark != null) { _context.WatermarkImage = editingManifest.Watermark; } } // buttons if provided if (IncludeButtons && (editingManifest.ButtonDescriptions != null)) { _context.ButtonDescriptions = editingManifest.ButtonDescriptions; } // option overrides if provided if (IncludeOptionOverrides) { if (editingManifest.ClientType != null) { _context.ClientType = editingManifest.ClientType; } if (editingManifest.OptionOverrides != null) { _context.OptionOverrides = editingManifest.OptionOverrides; } } } } } using (new ProgressContext(progressHost, 40, Res.Get(StringId.ProgressDetectingWeblogCharSet))) { if (IncludeOptionOverrides && IncludeHomePageSettings) { DetectHomePageSettings(); } } IBlogClient blogClient = CreateBlogClient(); if (IncludeInsecureOperations || blogClient.IsSecure) { if (blogClient is ISelfConfiguringClient) { // This must happen before categories detection but after manifest!! ((ISelfConfiguringClient)blogClient).DetectSettings(_context, this); } // detect categories if (IncludeCategories) { using ( new ProgressContext(progressHost, 20, Res.Get(StringId.ProgressDetectingWeblogCategories))) { BlogPostCategory[] categories = SafeDownloadCategories(); if (categories != null) { _context.Categories = categories; } BlogPostKeyword[] keywords = SafeDownloadKeywords(); if (keywords != null) { _context.Keywords = keywords; } } } // detect favicon (only if requested AND we don't have a PNG already // for the small image size) if (IncludeFavIcon) { using (new ProgressContext(progressHost, 10, Res.Get(StringId.ProgressDetectingWeblogIcon))) { byte[] favIcon = SafeDownloadFavIcon(); if (favIcon != null) { _context.FavIcon = favIcon; } } } if (IncludeImageEndpoints) { Debug.WriteLine("Detecting image endpoints"); ITemporaryBlogSettingsDetectionContext tempContext = _context as ITemporaryBlogSettingsDetectionContext; Debug.Assert(tempContext != null, "IncludeImageEndpoints=true but non-temporary context (type " + _context.GetType().Name + ") was used"); if (tempContext != null) { tempContext.AvailableImageEndpoints = null; try { BlogInfo[] imageEndpoints = blogClient.GetImageEndpoints(); tempContext.AvailableImageEndpoints = imageEndpoints; Debug.WriteLine(imageEndpoints.Length + " image endpoints detected"); } catch (NotImplementedException) { Debug.WriteLine("Image endpoints not implemented"); } catch (Exception e) { Trace.Fail("Exception detecting image endpoints: " + e.ToString()); } } } } // completed progressHost.UpdateProgress(100, 100, Res.Get(StringId.ProgressCompletedSettingsDetection)); } return(this); }
/// <summary> /// Downloads the pages and their references, providing progress feedback /// </summary> /// <param name="progressHost">The progresshost to use for feedback</param> /// <returns>this</returns> public object Download(IProgressHost progressHost) { // Prepare the list of references to download progressHost.UpdateProgress(Res.Get(StringId.ProgressPreparingListOfFiles)); foreach (PageToDownload pageToDownload in _pagesToDownload) { // Lay down a placeholder file with the correct file name try { string destination = Path.Combine(_siteStorage.BasePath, pageToDownload.RelativePath); destination = PathHelper.GetNonConflictingPath(destination); pageToDownload.FileName = Path.GetFileName(destination); using (Stream htmlStream = _siteStorage.Open(destination, AccessMode.Write)) { } } catch (Exception e) { HandleException(e); } foreach (ReferenceToDownload reference in pageToDownload.References) { // Don't add the same item more than once if (!_referencesToDownload.ContainsKey(reference.AbsoluteUrl)) { _referencesToDownload.Add(reference.AbsoluteUrl, reference); } } } // Enqueue the work items progressHost.UpdateProgress(Res.Get(StringId.ProgressStartingDownloadOfReferences)); IProgressHost[] progressHosts = new JointProgressHosts(progressHost, _referencesToDownload.Count, 8000, 10000).ProgressHosts; int tickNum = 0; foreach (ReferenceToDownload reference in _referencesToDownload.Values) { workQueue.Enqueue(new DownloadWorkItem(reference, _siteStorage, progressHosts[tickNum++])); } // Start up the parallel execution of the downloads ParallelExecution parallelExecution = new ParallelExecution(new ThreadStart(WorkerThreadStart), 2); parallelExecution.Execute(); parallelExecution = null; // Now go through and get HTML for each page, and emit the HTML to disk ProgressTick allPagesProgress = new ProgressTick(progressHost, 2000, 10000); for (int i = 0; i < _pagesToDownload.Length; i++) { try { allPagesProgress.UpdateProgress(i, _pagesToDownload.Length, string.Format(CultureInfo.CurrentCulture, Res.Get(StringId.ProgressSaving), _pagesToDownload[i].FileName)); WriteHtmlToDisk(_pagesToDownload[i], _siteStorage); } catch (Exception e) { HandleException(e); } if (allPagesProgress.CancelRequested) { throw new OperationCancelledException(); } } // We're complete! progressHost.UpdateProgress(1, 1, Res.Get(StringId.ProgressDownloadFinished)); return(this); }
protected void UpdateProgress(IProgressHost progressHost, int percent, string message) { if (CancelRequested) throw new OperationCancelledException(); progressHost.UpdateProgress(percent, 100, message); }
/// <summary> /// Actually downloads the pages /// </summary> private PageToDownload[] DownloadPages(IProgressHost progress, string url, LightWeightHTMLDocument lightWeightDocument, PageToDownload parentPageToDownload) { // Check for cancel if (progress.CancelRequested) { throw new OperationCancelledException(); } _currentDepth++; ArrayList downloadedPages = new ArrayList(); // Set up our progress int thisPageTicks = FIRSTPAGETICKS; if (_context.Depth == _currentDepth) { thisPageTicks = TOTALTICKS; } ProgressTick firstPagedownloadProgress = new ProgressTick(progress, thisPageTicks, TOTALTICKS); string safeUrl = UrlHelper.GetUrlWithoutAnchorIdentifier(url); // Look up the content type of this pageToDownload UrlContentTypeInfo headerInfo = null; if (_headerInfo.ContainsKey(safeUrl)) { headerInfo = (UrlContentTypeInfo)_headerInfo[safeUrl]; } else { if (lightWeightDocument != null) { headerInfo = new UrlContentTypeInfo("text/html", url); } else if (headerInfo == null && !_context.IsTimedOutUrl(url) && _context.ShouldDownloadThisUrl(url)) { progress.UpdateProgress(string.Format(CultureInfo.CurrentCulture, Res.Get(StringId.ProgressDeterminingType), url)); if (lightWeightDocument == null) { headerInfo = ContentTypeHelper.ExpensivelyGetUrlContentType(url, _context.TimeoutMS); } else { headerInfo = ContentTypeHelper.InexpensivelyGetUrlContentType(url); } } _headerInfo.Add(safeUrl, headerInfo); } // If this is a web page and we should download it, do it! if ((lightWeightDocument != null && IsDownloadablePageResource(headerInfo)) || (lightWeightDocument == null && IsDownloadablePageResource(headerInfo) && _context.ShouldDownloadThisUrl(headerInfo)) ) { bool downloadWorked = false; int downloadAttempts = -1; bool timedOut = true; // Max sure we are retrying the correct number of times ProgressTick pageDownloadProgress = new ProgressTick(firstPagedownloadProgress, 80, 100); while (!downloadWorked && downloadAttempts++ < _context.RetryCount && timedOut) { timedOut = false; pageDownloadProgress.UpdateProgress(0, 1); try { // If we haven't downloaded this page yet download it PageToDownload thisPageToDownload = null; if (!_context.UrlAlreadyDownloaded(safeUrl)) { if (lightWeightDocument == null) { thisPageToDownload = DownloadUrl(url, parentPageToDownload, pageDownloadProgress); } else { LightWeightHTMLDocument htmlDoc = lightWeightDocument; // Only redownload if we absolutely need to if (htmlDoc.HasFramesOrStyles && (htmlDoc.Frames == null || htmlDoc.StyleResourcesUrls == null)) { string html = htmlDoc.GenerateHtml(); string tempFile = TempFileManager.Instance.CreateTempFile("temp.htm"); using (StreamWriter writer = new StreamWriter(tempFile, false, Encoding.UTF8)) writer.Write(html); using (HTMLDocumentDownloader downloader = new HTMLDocumentDownloader(_parentControl, UrlHelper.GetLocalFileUrl(tempFile), htmlDoc.Title, _context.CookieString, _context.TimeoutMS, false)) { downloader.DownloadHTMLDocument(pageDownloadProgress); htmlDoc.UpdateBasedUponHTMLDocumentData(downloader.HtmlDocument, url); } } thisPageToDownload = new PageToDownload(htmlDoc, url, null, parentPageToDownload); if (htmlDoc.StyleResourcesUrls != null) { foreach (HTMLDocumentHelper.ResourceUrlInfo styleUrl in htmlDoc.StyleResourcesUrls) { thisPageToDownload.AddReference(new ReferenceToDownload(styleUrl.ResourceUrl, thisPageToDownload, styleUrl.ResourceAbsoluteUrl)); } } } // Add this page to our lists _context.AddPageToDownload(safeUrl, thisPageToDownload, true); downloadedPages.Add(thisPageToDownload); } else { thisPageToDownload = (PageToDownload)_context.CreatedPageToDownloadTable[safeUrl]; } // If we're downloading a site, add a second copy of the root page in the references subdir // This was, if the root page gets renamed, links back to it will still work correctly // This is a bit of a hack, but otherwise, we'll need to escape urls whenever we output // the site and change the root file name if (thisPageToDownload.IsRootPage && _context.Depth > 0) { PageToDownload copyOfThisPageToDownload = new PageToDownload(thisPageToDownload.LightWeightHTMLDocument.Clone(), thisPageToDownload.UrlToReplace, thisPageToDownload.FileName, thisPageToDownload); downloadedPages.Add(copyOfThisPageToDownload); } // enumerate the frames of this page and add them to the list of pages PageToDownload[] subFramesToDownload = GetFramePagesToDownload(thisPageToDownload); downloadedPages.AddRange(subFramesToDownload); foreach (PageToDownload pageToDownload in subFramesToDownload) { _context.AddPageToDownload(pageToDownload.AbsoluteUrl, pageToDownload, false); } // Now drill down based upon the depth configuration if (_context.ShouldContinue(_currentDepth)) { ProgressTick otherPagesdownloadProgress = new ProgressTick(progress, TOTALTICKS - thisPageTicks, TOTALTICKS); downloadedPages.AddRange(GetSubPagesToDownload(otherPagesdownloadProgress, downloadedPages, thisPageToDownload)); } downloadWorked = true; firstPagedownloadProgress.UpdateProgress(1, 1); } catch (OperationTimedOutException) { timedOut = true; } catch (WebPageDownloaderException htex) { HandleException(new Exception(htex.Message, htex)); } catch (Exception ex) { HandleException(new Exception(String.Format(CultureInfo.CurrentCulture, "{0} could not be downloaded", _url), ex)); } } // If we never got the download to succeed, add it to the list of timed out Urls if (!downloadWorked && timedOut) { _context.AddTimedOutUrl(_url); firstPagedownloadProgress.UpdateProgress(1, 1); } } // If it isn't a page we'll just add the file to the reference list for the parent page // There is not an else, because we could be looking at a reference, but a reference that // should not be downloaded (in which case we just ignore it) else if (headerInfo != null && _context.ShouldDownloadThisUrl(headerInfo)) { parentPageToDownload.AddReference(new ReferenceToDownload(url, parentPageToDownload)); progress.UpdateProgress(1, 1); } progress.UpdateProgress(1, 1); _currentDepth--; return((PageToDownload[])downloadedPages.ToArray(typeof(PageToDownload))); }
public ProgressContext(IProgressHost progressHost, int complete, string message) { _progressHost = progressHost; _progressHost.UpdateProgress(complete, 100, message); }
/// <summary> /// Initiate a download, using the progressHost to provide progress feedback /// </summary> /// <param name="progressHost">The progressHost to provide feedback to</param> /// <returns>this</returns> public object DownloadHTMLDocument(IProgressHost progressHost) { _downloadComplete = false; // Call the download method on the parent STA thread // Then wait for it to complete (the Monitor will be pulsed upon completion) _parentControl.Invoke(new Download(DoDownload), new object[] { progressHost }); lock (this) { if (_downloadComplete) return this; DateTime endDateTime = DateTime.Now.AddMilliseconds(TimeoutMs); while (!_downloadComplete) { if (!Monitor.Wait(this, Math.Max(0, (int)endDateTime.Subtract(DateTime.Now).TotalMilliseconds))) throw new OperationTimedOutException(); } if (_downloader.Result.Exception != null) throw _downloader.Result.Exception; progressHost.UpdateProgress(1, 1); return this; } }