public Yield PutFile(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            // Retrieve the file
            PageBE     page;
            string     userFileName;
            ResourceBE file = GetAttachmentFromUrl(context, false, out page, false, false);

            // If the file does not exist, attempt to retrieve the page
            if (null == file)
            {
                if (null == page)
                {
                    if (null != DreamContext.Current.GetParam <string>("fileid"))
                    {
                        throw new AttachmentNotFoundException();
                    }
                    page = PageBL_GetPageFromUrl(context, true);
                }
                userFileName = GetFilenameFromPathSegment(DreamContext.Current.GetParam <string>("filename"));
            }
            else
            {
                string fileNameParam = DreamContext.Current.GetParam("filename", null);
                if (fileNameParam == null)
                {
                    userFileName = file.Name;
                }
                else
                {
                    userFileName = GetFilenameFromPathSegment(fileNameParam);
                }
            }

            // Retrieve the file description
            string userDescription = context.GetParam("description", string.Empty);

            if (userDescription.Length > AttachmentBL.MAX_DESCRIPTION_LENGTH)
            {
                userDescription = userDescription.Substring(0, AttachmentBL.MAX_DESCRIPTION_LENGTH);
            }

            // Validate the page
            PageBL.AuthorizePage(DekiContext.Current.User, Permissions.UPDATE, page, false);

            // Get entire stream so it can be reused
            var        isMSWebDAV        = MSWEBDAV_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty);
            ResourceBE savedFileRevision = AttachmentBL.Instance.AddAttachment(file, request.AsStream(), request.ContentLength, request.ContentType, page, userDescription, userFileName, isMSWebDAV);

            // report an error on failure, and don't redirect
            if (savedFileRevision == null)
            {
                throw new AttachmentUploadSaveFatalException();
            }
            response.Return(DreamMessage.Ok(AttachmentBL.Instance.GetFileXml(savedFileRevision, true, null, null)));
            yield break;
        }
        private ResourceBE GetAttachment(DreamContext context, DreamMessage request, Permissions access, bool allowRevs, bool allowDeleted, out PageBE parentPage)
        {
            ResourceBE file = GetAttachmentFromUrl(context, true, out parentPage, allowRevs, allowDeleted);

            PageBL.AuthorizePage(DekiContext.Current.User, access, parentPage, false);
            DreamContext.Current.SetState <UserBE>(DekiContext.Current.User);
            DreamContext.Current.SetState <PageBE>(parentPage);

            //Identify images for upgrades
            List <ResourceBE> fileList = new List <ResourceBE>();

            fileList.Add(file);
            AttachmentBL.Instance.IdentifyUnknownImages(fileList);

            return(file);
        }
        //--- Methods ---
        public void Append(XDoc exportDoc)
        {
            _manifestDoc.Attr("date.created", DateTime.UtcNow).Attr("preserve-local", false);
            foreach (XDoc exportXml in exportDoc.Elements)
            {
                // Retrieve the current page
                try {
                    if (exportXml.HasName("page"))
                    {
                        // Generate the manifest and request needed to export the page
                        PageBE page = null;
                        if (!exportXml["@id"].IsEmpty)
                        {
                            uint pageId = DbUtils.Convert.To <uint>(exportXml["@id"].Contents, 0);
                            if (0 < pageId)
                            {
                                page = PageBL.GetPageById(pageId);
                            }
                        }
                        else if (!exportXml["@path"].IsEmpty)
                        {
                            page = PageBL.GetPageByTitle(Title.FromPrefixedDbPath(exportXml["@path"].Contents, null));
                        }
                        if ((null == page) || (0 == page.ID))
                        {
                            throw new PageNotFoundException();
                        }

                        // Check whether to exclude subpages, files, and/or properties
                        bool recursive            = exportXml["@recursive"].AsBool ?? false;
                        ExportExcludeType exclude = ExportExcludeType.NONE;
                        if (!exportXml["@exclude"].IsEmpty)
                        {
                            exclude = SysUtil.ChangeType <ExportExcludeType>(exportXml["@exclude"].Contents);
                        }

                        // Export the page
                        PageExport(recursive, exclude, page);
                    }
                    else if (exportXml.HasName("file"))
                    {
                        // Generate the manifest and request needed to export the file
                        ResourceBE file = null;
                        if (!exportXml["@id"].IsEmpty)
                        {
                            uint fileId = DbUtils.Convert.To <uint>(exportXml["@id"].Contents, 0);
                            if (0 < fileId)
                            {
                                uint resourceId = ResourceMapBL.GetResourceIdByFileId(fileId) ?? 0;
                                if (resourceId > 0)
                                {
                                    file = ResourceBL.Instance.GetResource(resourceId);
                                }
                            }
                        }
                        if (null == file)
                        {
                            throw new AttachmentNotFoundException();
                        }

                        // Check whether to exclude properties
                        ExportExcludeType exclude = ExportExcludeType.NONE;
                        if (!exportXml["@exclude"].IsEmpty)
                        {
                            exclude = SysUtil.ChangeType <ExportExcludeType>(exportXml["@exclude"].Contents);
                        }

                        // Perform the file export
                        PageBE page = PageBL.GetPageById(file.ParentPageId.Value);
                        page = PageBL.AuthorizePage(DekiContext.Current.User, Permissions.READ, page, false);
                        AttachmentExport(exclude, page, file);
                    }
                    else
                    {
                        throw new DreamResponseException(DreamMessage.NotImplemented(exportXml.Name));
                    }
                } catch (ResourcedMindTouchException e) {
                    AddError(e.Message, (int)e.Status, exportXml);
                } catch (DreamAbortException e) {
                    AddError(e.Message, (int)e.Response.Status, exportXml);
                } catch (Exception e) {
                    AddError(e.Message, (int)DreamStatus.InternalError, exportXml);
                }
            }
        }
        private void PageExport(bool recursive, ExportExcludeType exclude, PageBE page)
        {
            // Validate the page export
            page = PageBL.AuthorizePage(DekiContext.Current.User, Permissions.READ, page, false);
            if (page.IsRedirect)
            {
                throw new SiteExportRedirectInvalidOperationException();
            }

            // Export the page
            XUri uri = PageBL.GetUriCanonical(page).At("contents")
                       .With("mode", "edit")
                       .With("reltopath", _relToTitle.AsPrefixedDbPath())
                       .With("format", "xhtml");

            if (!_uris.ContainsKey(uri))
            {
                _uris.Add(uri, null);
                var dateModified = page.TimeStamp;
                var lastImport   = PropertyBL.Instance.GetPageProperty((uint)page.ID, SiteImportBuilder.LAST_IMPORT);
                if (lastImport != null)
                {
                    var content   = lastImport.Content;
                    var importDoc = XDocFactory.From(content.ToStream(), content.MimeType);
                    if (importDoc["etag"].AsText.EqualsInvariant(page.Etag))
                    {
                        dateModified = importDoc["date.modified"].AsDate ?? DateTime.MinValue;
                    }
                }
                var manifestDoc = new XDoc("page").Elem("title", page.Title.DisplayName)
                                  .Elem("path", page.Title.AsRelativePath(_relToTitle))
                                  .Elem("language", page.Language)
                                  .Elem("etag", page.Etag)
                                  .Elem("date.modified", dateModified.ToSafeUniversalTime())
                                  .Start("contents").Attr("type", page.ContentType).End();
                Add(uri, manifestDoc);
            }

            // Export page tags (if not excluded)
            if (ExportExcludeType.NONE == (ExportExcludeType.TAGS & exclude))
            {
                XUri tagUri = PageBL.GetUriCanonical(page).At("tags");
                if (!_uris.ContainsKey(tagUri))
                {
                    _uris.Add(tagUri, null);
                    XDoc manifestDoc = new XDoc("tags").Elem("path", page.Title.AsRelativePath(_relToTitle));
                    Add(tagUri, manifestDoc);
                }
            }

            // Export page properties (if not excluded)
            if (ExportExcludeType.NONE == (ExportExcludeType.PROPS & exclude))
            {
                IList <ResourceBE> properties = PropertyBL.Instance.GetPageProperties(page.ID);
                foreach (ResourceBE property in properties)
                {
                    if (property.Name.EqualsInvariant(SiteImportBuilder.LAST_IMPORT))
                    {
                        continue;
                    }
                    PropertyExport(page, null, property);
                }
            }

            // Export page files (if not excluded)
            if (ExportExcludeType.NONE == (ExportExcludeType.FILES & exclude))
            {
                IList <ResourceBE> files = AttachmentBL.Instance.GetPageAttachments(page.ID);
                foreach (ResourceBE file in files)
                {
                    AttachmentExport(exclude, page, file);
                }
            }

            // Export talk page (if not excluded)
            if ((ExportExcludeType.NONE == (ExportExcludeType.TALK & exclude)) && (!page.Title.IsTalk))
            {
                PageBE talkPage = PageBL.GetPageByTitle(page.Title.AsTalk());
                if ((null != talkPage) && (0 < talkPage.ID))
                {
                    PageExport(false, exclude, talkPage);
                }
            }

            // Export subpages (if not excluded)
            if (recursive)
            {
                ICollection <PageBE> children = PageBL.GetChildren(page, true);
                children = PermissionsBL.FilterDisallowed(DekiContext.Current.User, PageBL.GetChildren(page, true), false, Permissions.READ);
                if (children != null)
                {
                    foreach (PageBE child in children)
                    {
                        PageExport(recursive, exclude, child);
                    }
                }
            }
        }