public void Attach(Blog blog)
        {
            // detach from any existing work
            Detach();

            // record context
            lock (this)
            {
                _blogId = blog.Id;
                _hostBlogId = blog.HostBlogId;
                _homepageUrl = blog.HomepageUrl;
                _postApiUrl = blog.PostApiUrl;
                _buttonIds = new ArrayList();

                foreach (IBlogProviderButtonDescription buttonDescription in blog.ButtonDescriptions)
                {
                    if (buttonDescription.SupportsNotification)
                        _buttonIds.Add(buttonDescription.Id);
                }

                // if we have notifications to poll for then force an immediate polling
                // (we will adjust the polling interval within the callback to the
                // standard interval after processing the first call)
                if (_buttonIds.Count > 0)
                {
                    _pollingTimer.Change(_immediatePollingInterval, _disablePollingInterval);
                }
            }
        }
        void IBlogPostEditor.OnBlogChanged(Blog newBlog)
        {
            _targetBlog = newBlog ;

            if ( newBlog.ClientOptions.SupportsMultipleCategories )
                CategoryContext.SelectionMode = CategoryContext.SelectionModes.MultiSelect;
            else
                CategoryContext.SelectionMode = CategoryContext.SelectionModes.SingleSelect;

            CategoryContext.SetBlogCategories(_targetBlog.Categories);
            CategoryContext.SelectedCategories = new BlogPostCategory[0];
        }
 public void ThreadMain()
 {
     try
     {
         using (Blog blog = new Blog(_postInfo.BlogId))
         {
             _blogPost = blog.GetPost(_postInfo.BlogPostId, _postInfo.IsPage);
         }
     }
     catch
     {
     }
 }
        public static BlogPost SafeRetrievePost(PostInfo postInfo, int timeoutMs)
        {
            try
            {
                // null for invalid blogs
                if (!BlogSettings.BlogIdIsValid(postInfo.BlogId))
                    return null;

                // null if the user can't authenticate
                using (Blog blog = new Blog(postInfo.BlogId))
                {
                    if (!blog.VerifyCredentials())
                        return null;
                }

                // fire up the get post thread
                GetPostThread getPostThread = new GetPostThread(postInfo);
                Thread thread = ThreadHelper.NewThread(new ThreadStart(getPostThread.ThreadMain), "GetPostThread", true, false, true);
                thread.Start();

                // wait for it to complete
                thread.Join(timeoutMs);

                // return the post if we successfully got one
                BlogPost blogPost = getPostThread.BlogPost;
                if (blogPost != null)
                {
                    // Clone in case there are ever issues sharing these accross threads
                    // (not aware of any right now)
                    return blogPost.Clone() as BlogPost;
                }
                else
                {
                    return null;
                }
            }
            catch
            {
                return null;
            }
        }
        public static bool SafeDeleteRemotePost(string blogId, string postId, bool isPage)
        {
            // screen non-existent blog ids
            if (!BlogSettings.BlogIdIsValid(blogId))
                return true;

            using (Blog blog = new Blog(blogId))
            {
                try
                {
                    if (blog.VerifyCredentials())
                    {
                        // try to delete the post on the remote blog
                        blog.DeletePost(postId, isPage, true);

                        // return success
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                catch (BlogClientOperationCancelledException)
                {
                    // show no UI for operation cancelled
                    Debug.WriteLine("BlogClient operation cancelled");
                    return false;
                }
                catch (Exception ex)
                {
                    DisplayableExceptionDisplayForm.Show(Win32WindowImpl.ForegroundWin32Window, ex);
                    return false;
                }
            }
        }
        public ServiceUpdateSettingsDetectionContext(string blogId)
        {
            using (BlogSettings settings = BlogSettings.ForBlogId(blogId))
            {
                _blogId = blogId;
                _homepageUrl = settings.HomepageUrl;
                _providerId = settings.ProviderId;
                _manifestDownloadInfo = settings.ManifestDownloadInfo;
                _hostBlogId = settings.HostBlogId;
                _postApiUrl = settings.PostApiUrl;
                _clientType = settings.ClientType;
                _userOptionOverrides = settings.UserOptionOverrides;
                _homepageOptionOverrides = settings.HomePageOverrides;

                _initialCategoryScheme = settings.OptionOverrides != null
                    ? settings.OptionOverrides[BlogClientOptions.CATEGORY_SCHEME] as string
                    : null;

                BlogCredentialsHelper.Copy(settings.Credentials, _credentials);

                using (Blog blog = new Blog(settings))
                    _blogSupportsCategories = blog.ClientOptions.SupportsCategories;

                _initialBlogSettingsContents = GetBlogSettingsContents(settings);
                _initialCategoriesContents = GetCategoriesContents(settings.Categories);

            }
        }
 void IBlogPostEditor.OnBlogChanged(Blog newBlog)
 {
 }
 private void buttonUpdateStyle_Click(object sender, System.EventArgs e)
 {
     try
     {
         using (Blog blog = new Blog(TemporaryBlogSettings))
         {
             if (blog.VerifyCredentials())
             {
                 BlogClientUIContextImpl uiContext = new BlogClientUIContextImpl(FindForm());
                 Color? backgroundColor;
                 BlogEditingTemplateFile[] editingTemplates = BlogEditingTemplateDetector.DetectTemplate(
                     uiContext,
                     panelBrowserParent,
                     TemporaryBlogSettings,
                     !BlogIsAutoUpdatable(blog),
                     out backgroundColor); // only probe for manifest if blog is not auto-updatable
                 if (editingTemplates.Length != 0)
                 {
                     TemporaryBlogSettings.TemplateFiles = editingTemplates;
                     if (backgroundColor != null)
                         TemporaryBlogSettings.UpdatePostBodyBackgroundColor(backgroundColor.Value);
                     TemporaryBlogSettingsModified = true;
                 }
             }
         }
     }
     catch (Exception ex)
     {
         UnexpectedErrorMessage.Show(FindForm(), ex, "Unexpected Error Updating Style");
     }
 }
 private bool BlogIsAutoUpdatable(Blog blog)
 {
     return PostEditorSettings.AllowSettingsAutoUpdate && blog.ClientOptions.SupportsAutoUpdate;
 }
        private void RefreshLayout(bool blogChanged)
        {
            // no-op if we do not have an active weblog
            // (solves order of initialization problem)
            if (_postEditingSite.CurrentAccountId == null)
                return;

            UpdatePostLists();

            // compute text height
            int textHeight = (int) Math.Ceiling(Font.GetHeight());

            Point openPanelPoint = new Point(PANEL_HORIZONTAL_INSET, PANEL_TOP_INSET);

            _headerControl.Width = Width - 2*PANEL_HORIZONTAL_INSET;
            if (blogChanged)
            {
                using (Blog blog = new Blog(_postEditingSite.CurrentAccountId))
                {
                    _headerControl.HeaderText = blog.Name;

                    if (!string.IsNullOrEmpty(blog.ClientOptions.HomepageLinkText))
                        _headerControl.LinkText = blog.ClientOptions.HomepageLinkText;
                    else
                        _headerControl.LinkText = Res.Get(StringId.ViewWeblog);
                    _headerControl.LinkUrl = blog.HomepageUrl;

                    if (!string.IsNullOrEmpty(blog.AdminUrl))
                    {
                        if (!string.IsNullOrEmpty(blog.ClientOptions.AdminLinkText))
                            _headerControl.SecondLinkText = blog.ClientOptions.AdminLinkText;
                        else
                            _headerControl.SecondLinkText = Res.Get(StringId.ManageWeblog);
                        _headerControl.SecondLinkUrl = blog.AdminUrl;
                    }
                    else
                    {
                        _headerControl.SecondLinkText = "";
                        _headerControl.SecondLinkUrl = "";
                    }
                    _headerControl.RefreshLayout();
                }
            }
            _headerControl.Location = openPanelPoint;

            openPanelPoint.Y += _headerControl.Height;
            openPanelPoint.X -= SECONDARY_HEADER_INSET;

            int tertiaryLeft = openPanelPoint.X + TERTIARY_INSET;

            // open panel
            _openPanelHeader.Layout(openPanelPoint);

            // drafts
            _draftsSectionHeader.Layout(new Point(tertiaryLeft, _openPanelHeader.Bounds.Bottom));
            _draftsPostList.Layout(new Point(tertiaryLeft, _draftsSectionHeader.CaptionLocation.Y + textHeight));

            _openDraftCommand.Visible = ShouldShowMoreDrafts;
            _openDraftCommand.Layout(
                new Point(_draftsSectionHeader.CaptionLocation.X + OPEN_COMMAND_LEFT_OFFSET,
                          _draftsPostList.Bounds.Bottom + OPEN_COMMAND_PADDING));

            // recent posts
            _recentPostsSectionHeader.Layout(
                new Point(tertiaryLeft, _openDraftCommand.Bounds.Bottom + PANEL_SECTION_PADDING));
            _recentPostList.Layout(new Point(tertiaryLeft, _recentPostsSectionHeader.CaptionLocation.Y + textHeight));

            // commands
            _openPostCommand.Visible = ShouldShowMoreRecentPosts;
            _openPostCommand.Layout(
                new Point(_recentPostsSectionHeader.CaptionLocation.X + OPEN_COMMAND_LEFT_OFFSET,
                          _recentPostList.Bounds.Bottom + OPEN_COMMAND_PADDING));

            // body
            _openPanelBody.Layout(_openPanelHeader.Bounds, _openPostCommand.Bounds.Bottom);

            // insert panel
            Point insertHeaderPoint =
                new Point(openPanelPoint.X, _openPanelBody.Bounds.Bottom + PANEL_SECTION_PADDING);

            _separator2.Top = insertHeaderPoint.Y;
            _separator2.Left = Width/2 - _separator2.Width/2;

            insertHeaderPoint.Y += _separator2.Height + PANEL_SECTION_PADDING;

            _insertPanelHeader.Layout(insertHeaderPoint);
            Point p = new Point(insertHeaderPoint.X + LINK_COMMAND_PADDING,
                                _insertPanelHeader.Bounds.Bottom + PANEL_SECTION_PADDING_FIRST);
            foreach (LinkCommand linkCommand in new LinkCommand[] { _insertLinkCommand, _insertPictureCommand, _insertPhotoAlbumCommand, _insertWebImage, _insertTableCommand })
            {
                if (linkCommand != null)
                {
                    linkCommand.Layout(p);
                    p.Y = linkCommand.Bounds.Bottom + LINK_COMMAND_PADDING;
                }
            }
            _contentInsertCommands.Layout(p);

            Rectangle bounds = _insertPanelHeader.Bounds;
            bounds.Height += SECTION_SPACING;
            _insertPanelBody.Layout(bounds, _contentInsertCommands.Bounds.Bottom + INSERT_EXTRA_BOTTOM_PAD);

            BidiHelper.RtlLayoutFixup(this);
            MinimumSize = new Size(0, _insertPanelBody.Bounds.Bottom + INSERT_EXTRA_BOTTOM_PAD);
            Refresh();
        }
 protected virtual object[] GetDefaultItems(Blog blog) { return new object[0]; }
 private void CheckForServiceUpdates(Blog blog)
 {
     if (_editingManager.BlogIsAutoUpdatable && !ApplicationDiagnostics.SuppressBackgroundRequests)
     {
         ServiceUpdateChecker checker = new ServiceUpdateChecker(blog.Id, new WeblogSettingsChangedHandler(FireWeblogSettingsChangedEvent));
         checker.Start();
     }
 }
Example #13
0
 private static string ReadBlogName(Storage postStorage)
 {
     string blogId = ReadString(postStorage, DESTINATION_BLOG_ID);
     if (BlogSettings.BlogIdIsValid(blogId))
     {
         using (Blog blog = new Blog(blogId))
             return blog.Name;
     }
     else
     {
         return String.Empty;
     }
 }
        private void SetSupportValues()
        {
            using (Blog blog = new Blog(TemporaryBlogSettings))
            {
                clientSupportsScripts = blog.ClientOptions.SupportsScripts;
                clientSupportsEmbeds = blog.ClientOptions.SupportsEmbeds;
            }
            //scripts
            comboScripts.Items.Add(new SupportsOptionItem(SupportsFeature.Yes));
            comboScripts.Items.Add(new SupportsOptionItem(SupportsFeature.Unknown));
            comboScripts.Items.Add(new SupportsOptionItem(SupportsFeature.No));
            string userScriptOverride = (string)TemporaryBlogSettings.UserOptionOverrides[BlogClientOptions.SUPPORTS_SCRIPTS];
            if (userScriptOverride != null && userScriptOverride != String.Empty)
            {
                switch (userScriptOverride)
                {
                    case "yes":
                        {
                            comboScripts.SelectedItem = new SupportsOptionItem(SupportsFeature.Yes);
                            break;
                        }
                    case "no":
                        {
                            comboScripts.SelectedItem = new SupportsOptionItem(SupportsFeature.No);
                            break;
                        }
                    default:
                        {
                            comboScripts.SelectedItem = new SupportsOptionItem(SupportsFeature.Unknown);
                            break;
                        }
                }
            }
            else
            {
                comboScripts.SelectedItem = new SupportsOptionItem(clientSupportsScripts);
            }

            //embeds
            comboEmbeds.Items.Add(new SupportsOptionItem(SupportsFeature.Yes));
            comboEmbeds.Items.Add(new SupportsOptionItem(SupportsFeature.Unknown));
            comboEmbeds.Items.Add(new SupportsOptionItem(SupportsFeature.No));
            string userEmbedOverride = (string)TemporaryBlogSettings.UserOptionOverrides[BlogClientOptions.SUPPORTS_EMBEDS];
            if (userEmbedOverride != null && userEmbedOverride != String.Empty)
            {
                switch (userEmbedOverride)
                {
                    case "yes":
                        {
                            comboEmbeds.SelectedItem = new SupportsOptionItem(SupportsFeature.Yes);
                            break;
                        }
                    case "no":
                        {
                            comboEmbeds.SelectedItem = new SupportsOptionItem(SupportsFeature.No);
                            break;
                        }
                    default:
                        {
                            comboEmbeds.SelectedItem = new SupportsOptionItem(SupportsFeature.Unknown);
                            break;
                        }
                }
            }
            else
            {
                comboEmbeds.SelectedItem = new SupportsOptionItem(clientSupportsEmbeds);
            }
        }
 void IBlogPostEditor.OnBlogSettingsChanged(bool templateChanged)
 {
     using (Blog blog = new Blog(_editingManager.BlogId))
         AdaptToBlog(blog);
 }
        protected override void DoWork()
        {
            using (new BlogClientUIContextScope(_uiContext))
            {
                // NOTE: LocalSupportingFileUploader temporarily modifies the contents of the BlogPost.Contents to
                // have the correct remote references to embedded images, etc. When it is disposed it returns the
                // value of BlogPost.Contents to its original value.
                using (LocalSupportingFileUploader supportingFileUploader = new LocalSupportingFileUploader(_publishingContext))
                {
                    //hook to publish files before the post is published
                    supportingFileUploader.UploadFilesBeforePublish();

                    // now submit the post
                    using (Blog blog = new Blog(_publishingContext.EditingContext.BlogId))
                    {
                        BlogPost blogPost = _publishingContext.GetBlogPostForPublishing();

                        PostResult postResult;
                        if (blogPost.IsNew)
                        {
                            postResult = blog.NewPost(blogPost, _publishingContext, _publish);
                        }
                        else
                        {
                            postResult = blog.EditPost(blogPost, _publishingContext, _publish);
                        }

                        // try to get published post hash and permalink (but failure shouldn't
                        // stop publishing -- if we allow this then the user will end up
                        // "double-posting" content because the actual publish did succeed
                        // whereas Writer's status would indicate it hadn't)
                        string publishedPostHash = null, permaLink = null, slug = null;
                        try
                        {
                            BlogPost publishedPost = blog.GetPost(postResult.PostId, blogPost.IsPage);
                            publishedPostHash = BlogPost.CalculateContentsSignature(publishedPost);
                            permaLink = publishedPost.Permalink;
                            slug = publishedPost.Slug;
                        }
                        catch (Exception ex)
                        {
                            Trace.WriteLine("Unexpected error retrieving published post: " + ex.ToString());
                        }

                        BlogPostPublishingResult publishingResult = new BlogPostPublishingResult();

                        // Hook to publish files after the post is published (note that if this
                        // fails it is not a fatal error since the publish itself already
                        // succeeded. In the case of a failure note the exception so that the
                        // UI layer can inform/prompt the user as appropriate
                        try
                        {
                            supportingFileUploader.UploadFilesAfterPublish(postResult.PostId);
                        }
                        catch (Exception ex)
                        {
                            publishingResult.AfterPublishFileUploadException = ex;
                        }

                        // populate the publishing result
                        publishingResult.PostResult = postResult;
                        publishingResult.PostPermalink = permaLink;
                        publishingResult.PostContentHash = publishedPostHash;
                        publishingResult.Slug = slug;
                        publishingResult.PostPublished = _publish;

                        // set the post result
                        _publishingContext.SetPublishingPostResult(publishingResult);

                        // send pings if appropriate
                        if (_publish && PostEditorSettings.Ping && !blogPost.IsTemporary)
                            SafeAsyncSendPings(blog.Name, blog.HomepageUrl);
                    }
                }
            }
        }
 public LocalSupportingFileUploader(IBlogPostPublishingContext publishingContext)
 {
     // save references to parameters/post contents
     _publishingContext = publishingContext;
     _originalPostContents = _publishingContext.EditingContext.BlogPost.Contents;
     _blog = new Blog(_publishingContext.EditingContext.BlogId);
 }
            protected override void DoWork()
            {
                using (BlogClientUIContextScope uiScope = new BlogClientUIContextScope(_uiContext))
                {
                    using (Blog blog = new Blog(_blogId))
                    {
                        // Fix bug 457160 - New post created with a new category
                        // becomes without a category when opened in WLW
                        //
                        // See also PostEditorPostSource.GetPost(string)
                        try
                        {
                            blog.RefreshCategories();
                        }
                        catch (Exception e)
                        {
                            Trace.Fail("Exception while attempting to refresh categories: " + e.ToString());
                        }

                        _serverBlogPost = blog.GetPost(_blogPost.Id, _blogPost.IsPage);
                        if (_serverBlogPost == null)
                            _noPostAvailable = true;
                    }
                }
            }
 private static bool VerifyBlogCredentials(string destinationBlogId)
 {
     using (Blog blog = new Blog(destinationBlogId))
         return blog.VerifyCredentials();
 }
        /// <summary>
        ///  Does this blog support post-sync? (default to true if we can't figure this out)
        /// </summary>
        /// <param name="blogId"></param>
        /// <returns></returns>
        private static bool SynchronizationSupportedForBlog(string blogId)
        {
            try
            {
                if (!BlogSettings.BlogIdIsValid(blogId))
                    return false;

                // verify synchronization is supported for this blog service
                using (Blog blog = new Blog(blogId))
                    return blog.ClientOptions.SupportsPostSynchronization;
            }
            catch (Exception ex)
            {
                Trace.Fail("Unexpected exception getting post sync options: " + ex.ToString());
                return false;
            }
        }
 void IBlogPostEditor.OnBlogChanged(Blog newBlog)
 {
     AdaptToBlog(newBlog);
     CheckForServiceUpdates(newBlog);
 }
        /// <summary>
        /// Perform a blog operation with a timeout. If the operation could not be completed for any reason (including
        /// an invalid blog, no credentials, a network error, or a timeout) then null is returned.
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="blogId"></param>
        /// <param name="operation"></param>
        /// <param name="timeoutMs"></param>
        /// <returns></returns>
        public static object PerformBlogOperationWithTimeout(string blogId, BlogClientOperation operation, int timeoutMs, bool verifyCredentials)
        {
            try
            {
                // null for invalid blogs
                if (!BlogSettings.BlogIdIsValid(blogId))
                    return null;

                // null if the user can't authenticate
                if (verifyCredentials)
                {
                    using (Blog blog = new Blog(blogId))
                    {
                        if (!blog.VerifyCredentials())
                            return null;
                    }
                }

                // fire up the thread
                BlogClientOperationThread operationThread = new BlogClientOperationThread(blogId, operation);
                Thread thread = ThreadHelper.NewThread(new ThreadStart(operationThread.ThreadMain), "BlogClientOperationThread", true, false, true);
                thread.Start();

                // wait for it to complete
                thread.Join(timeoutMs);

                // return the result
                return operationThread.Result;
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occurred performing BlogOperation: " + ex.ToString());
                return null;
            }
        }
        private void AdaptToBlog(Blog newBlog)
        {
            // if the blog supports posting to draft or not
            commandPostAsDraft.Enabled = newBlog.ClientOptions.SupportsPostAsDraft;
            if (newBlog.ClientOptions.SupportsPostAsDraft)
                commandSavePost.CommandBarButtonContextMenuDefinition = _savePostContextMenuDefinition;
            else
                commandSavePost.CommandBarButtonContextMenuDefinition = null;

            // if the blog supports post draft and edit online
            commandPostAsDraftAndEditOnline.Enabled = newBlog.ClientOptions.SupportsPostAsDraft && (newBlog.ClientOptions.PostEditingUrl != String.Empty);

            // if the blog supports pages or not
            bool enablePages = newBlog.ClientOptions.SupportsPages;
            commandNewPage.Enabled = enablePages;
            if (enablePages)
                commandNewPost.CommandBarButtonContextMenuDefinition = _newPostContextMenuDefinition;
            else
                commandNewPost.CommandBarButtonContextMenuDefinition = null;
        }
 public void ThreadMain()
 {
     try
     {
         using (Blog blog = new Blog(_blogId))
         {
             _result = _operation(blog);
         }
     }
     catch (Exception ex)
     {
         Debug.WriteLine("Exception occurred performing BlogOperation: " + ex.ToString());
     }
 }
 public PublishOperationManager(UpdateWeblogProgressForm form, Blog blog)
 {
     _form = form;
     _blog = blog;
 }
        private void SetCurrentBlog(string blogId)
        {
            DisposeCurrentBlog();
            _blog = new Blog(blogId);

            // update the default
            BlogSettings.DefaultBlogId = blogId;
        }
        public static BlogFileUploader CreateFileUploader(Blog blog, string postContextName)
        {
            string destinationContext = GetFileUploadDestinationContext(blog.Id, blog.FileUploadSupport, blog.FileUploadSettings);
            switch (blog.FileUploadSupport)
            {
                case FileUploadSupport.Weblog:
                    return new WeblogBlogFileUploader(destinationContext, postContextName, blog.Id, blog.HostBlogId);

                case FileUploadSupport.FTP:
                    return new FTPBlogFileUploader(destinationContext, postContextName, new FtpUploaderSettings(blog.FileUploadSettings), blog.Id);

                default:
                    Trace.Fail("Unexpected value for blog.FileUploadSupport: " + blog.FileUploadSupport.ToString());
                    goto case FileUploadSupport.Weblog;
            }
        }
        public void OnBlogChanged(Blog newBlog)
        {
            _clientOptions = newBlog.ClientOptions;
            _targetBlog = newBlog;

            controller.OnBlogChanged(newBlog);
            ((IBlogPostEditor)postPropertiesForm).OnBlogChanged(newBlog);

            ManageLayout();
        }
        private IBlogProviderButtonNotification GetButtonNotification()
        {
            string notificationUrl = String.Format(
                CultureInfo.InvariantCulture,
                "{0}?blog_id={1}&button_id={2}&image_url={3}",
                NotificationUrl,
                HttpUtility.UrlEncode(_hostBlogId),
                HttpUtility.UrlEncode(_buttonId),
                HttpUtility.UrlEncode(ImageUrl));

            // get the content
            HttpWebResponse response = null;
            XmlDocument xmlDocument = new XmlDocument();
            try
            {
                using (Blog blog = new Blog(_blogId))
                    response = blog.SendAuthenticatedHttpRequest(notificationUrl, 10000);

                // parse the results
                xmlDocument.Load(response.GetResponseStream());
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (response != null)
                    response.Close();
            }

            // create namespace manager
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);
            nsmgr.AddNamespace("n", "http://schemas.microsoft.com/wlw/buttons/notification");

            // throw if the root element is not manifest
            if (xmlDocument.DocumentElement.LocalName.ToLower(CultureInfo.InvariantCulture) != "notification")
                throw new ArgumentException("Not a valid writer button notification");

            // polling interval
            int checkAgainMinutes = XmlHelper.NodeInt(xmlDocument.SelectSingleNode("//n:checkAgainMinutes", nsmgr), 0);
            if (checkAgainMinutes == 0)
            {
                throw new ArgumentException("You must specify a value for checkAgainMinutes");
            }
            TimeSpan pollingInterval = TimeSpan.FromMinutes(checkAgainMinutes);

            // notification text
            string notificationText = XmlHelper.NodeText(xmlDocument.SelectSingleNode("//n:text", nsmgr));

            // notification image
            Bitmap notificationImage = null;
            string notificationImageUrl = XmlHelper.NodeText(xmlDocument.SelectSingleNode("//n:imageUrl", nsmgr));
            if (notificationImageUrl != String.Empty)
            {
                // compute the absolute url then allow parameter substitution
                notificationImageUrl = BlogClientHelper.GetAbsoluteUrl(notificationImageUrl, NotificationUrl);
                notificationImageUrl = BlogClientHelper.FormatUrl(notificationImageUrl, _homepageUrl, _postApiUrl, _hostBlogId);

                // try to download it (will use the cache if available)
                // note that failing to download it is a recoverable error, we simply won't show a notification image
                try
                {
                    // try to get a credentials context for the download
                    WinInetCredentialsContext credentialsContext = null;
                    try
                    {
                        credentialsContext = BlogClientHelper.GetCredentialsContext(_blogId, notificationImageUrl);
                    }
                    catch (BlogClientOperationCancelledException)
                    {
                    }

                    // execute the download
                    notificationImage = ImageHelper.DownloadBitmap(notificationImageUrl, credentialsContext);
                }
                catch (Exception ex)
                {
                    Trace.WriteLine("Error downloading notification image: " + ex.ToString());
                }
            }

            // clear notification on click
            bool clearNotificationOnClick = XmlHelper.NodeBool(xmlDocument.SelectSingleNode("//n:resetOnClick", nsmgr), true);

            // return the notification
            return new BlogProviderButtonNotification(pollingInterval, notificationText, notificationImage, clearNotificationOnClick);
        }
 protected abstract object BlogFetchOperation(Blog blog);