/// <summary>
        /// Given a template, make a new book
        /// </summary>
        /// <param name="sourceBookFolder"></param>
        /// <param name="parentCollectionPath"></param>
        /// <returns>path to the new book folder</returns>
        public string CreateBookOnDiskFromTemplate(string sourceBookFolder, string parentCollectionPath)
        {
            Logger.WriteEvent("BookStarter.CreateBookOnDiskFromTemplate({0}, {1})", sourceBookFolder, parentCollectionPath);

            // We use the "initial name" to make the initial copy, and it gives us something
            //to name the folder and file until such time as the user enters a title in for the book.
            string initialBookName = GetInitialName(parentCollectionPath);
            var    newBookFolder   = Path.Combine(parentCollectionPath, initialBookName);

            CopyFolder(sourceBookFolder, newBookFolder);
            //if something bad happens from here on out, we need to delete that folder we just made
            try
            {
                var oldNamedFile = Path.Combine(newBookFolder, Path.GetFileName(GetPathToHtmlFile(sourceBookFolder)));
                var newNamedFile = Path.Combine(newBookFolder, initialBookName + ".htm");
                RobustFile.Move(oldNamedFile, newNamedFile);

                //the destination may change here...
                newBookFolder = SetupNewDocumentContents(sourceBookFolder, newBookFolder);

                if (OnNextRunSimulateFailureMakingBook)
                {
                    throw new ApplicationException("Simulated failure for unit test");
                }
            }
            catch (Exception)
            {
                SIL.IO.RobustIO.DeleteDirectory(newBookFolder, true);
                throw;
            }
            return(newBookFolder);
        }
        public static void SimulateRename(Bloom.TeamCollection.TeamCollection tc, string oldName, string newName)
        {
            var oldPath = Path.Combine(tc.LocalCollectionFolder, oldName);
            var newPath = Path.Combine(tc.LocalCollectionFolder, newName);

            RobustIO.MoveDirectory(oldPath, newPath);
            RobustFile.Move(Path.Combine(newPath, oldName + ".htm"), Path.Combine(newPath, newName + ".htm"));
            tc.HandleBookRename(oldName, newName);
        }
Exemple #3
0
        private static void SaveBadFile(string filepath)
        {
            var savedBadFile = filepath + "-BAD";

            if (RobustFile.Exists(savedBadFile))
            {
                RobustFile.Delete(savedBadFile);
            }
            RobustFile.Move(filepath, savedBadFile);
        }
        public static string RenameCollection(string fromDirectory, string toDirectory)
        {
            if (!Directory.Exists(fromDirectory))
            {
                throw new ApplicationException("Bloom could not complete the renaming of the collection, because there isn't a directory with the source name anymore: " + fromDirectory);
            }

            if (Directory.Exists(toDirectory))             //there's already a folder taking this name
            {
                throw new ApplicationException("Bloom could not complete the renaming of the collection, because there is already a directory with the new name: " + toDirectory);
            }

            //this is just a sanity check, it will throw if the existing directory doesn't have a collection
            FindSettingsFileInFolder(fromDirectory);

//first rename the directory, as that is the part more likely to fail (because *any* locked file in there will cause a failure)
            SIL.IO.RobustIO.MoveDirectory(fromDirectory, toDirectory);
            string collectionSettingsPath;

            try
            {
                collectionSettingsPath = FindSettingsFileInFolder(toDirectory);
            }
            catch (Exception)
            {
                throw;
            }

            try
            {
                //we now make a default name based on the name of the directory
                string destinationPath = Path.Combine(toDirectory, Path.GetFileName(toDirectory) + ".bloomCollection");
                if (!RobustFile.Exists(destinationPath))
                {
                    RobustFile.Move(collectionSettingsPath, destinationPath);
                }

                return(destinationPath);
            }
            catch (Exception error)
            {
                //change the directory name back, so the rename isn't half-done.
                SIL.IO.RobustIO.MoveDirectory(toDirectory, fromDirectory);
                throw new ApplicationException(string.Format("Could change the folder name, but not the collection file name", fromDirectory, toDirectory), error);
            }
        }
Exemple #5
0
        public void WriteToFolder(string bookFolderPath)
        {
            string tempFilePath;
            var    metaDataPath = MetaDataPath(bookFolderPath);

            using (var temp = TempFile.InFolderOf(metaDataPath))
            {
                tempFilePath = temp.Path;
            }
            RobustFile.WriteAllText(tempFilePath, Json);
            if (RobustFile.Exists(metaDataPath))
            {
                RobustFile.Replace(tempFilePath, metaDataPath, Path.ChangeExtension(metaDataPath, "bak"));
            }
            else
            {
                RobustFile.Move(tempFilePath, metaDataPath);
            }
        }
Exemple #6
0
        /// <summary>
        /// Make a metadata, usually by just reading the meta.json file in the book folder.
        /// If some exception is thrown while trying to do that, or if it doesn't exist,
        /// Try reading a backup (and restore it if successful).
        /// If that also fails, return null.
        /// </summary>
        /// <param name="bookFolderPath"></param>
        /// <returns></returns>
        public static BookMetaData FromFolder(string bookFolderPath)
        {
            var          metaDataPath = MetaDataPath(bookFolderPath);
            BookMetaData result;

            if (TryReadMetaData(metaDataPath, out result))
            {
                return(result);
            }

            var backupPath = Path.ChangeExtension(metaDataPath, "bak");

            if (RobustFile.Exists(backupPath) && TryReadMetaData(backupPath, out result))
            {
                RobustFile.Delete(metaDataPath);                 // Don't think it's worth saving the corrupt one
                RobustFile.Move(backupPath, metaDataPath);
                return(result);
            }
            return(null);
        }
        private static TestFolderTeamCollection MakeAndRenameBook(TemporaryFolder collectionFolder,
                                                                  TemporaryFolder repoFolder,
                                                                  out string bookPath, out string newBookFolderPath)
        {
            var mockTcManager = new Mock <ITeamCollectionManager>();
            var tc            = new TestFolderTeamCollection(mockTcManager.Object, collectionFolder.FolderPath,
                                                             repoFolder.FolderPath);
            var bookFolderPath = Path.Combine(collectionFolder.FolderPath, "My book");

            Directory.CreateDirectory(bookFolderPath);
            bookPath = Path.Combine(bookFolderPath, "My book.htm");
            RobustFile.WriteAllText(bookPath, "This is just a dummy");
            tc.PutBook(bookFolderPath);
            tc.AttemptLock("My book", "*****@*****.**");
            RobustFile.WriteAllText(bookPath, "This is the edited content");
            var newBookPath = Path.Combine(bookFolderPath, "Renamed book");

            RobustFile.Move(bookPath, newBookPath);
            newBookFolderPath = Path.Combine(collectionFolder.FolderPath, "Renamed book");
            Directory.Move(bookFolderPath, newBookFolderPath);
            tc.HandleBookRename("My book", "Renamed book");
            return(tc);
        }
Exemple #8
0
        // We want to move the file specified in the first path to a new location to use
        // as a backup while we typically replace it.
        // A previous backup, possibly of the same or another file, is no longer needed (if it exists)
        // and should be deleted, if possible, on a background thread.
        // The path to the backup will be updated to the new backup.
        // Typically the new name matches the original with the extension changed to .bak.
        // If necessary (because the desired backup file already exists), we will add a counter
        // to get the a name that is not in use.
        // A goal is (for performance reasons) not to have to wait while a file is deleted
        // (and definitely not while one is copied).
        private static bool PrepareBackupFile(string path, ref string backupPath, ApiRequest request)
        {
            int counter = 0;

            backupPath = path + ".bak";
            var originalExtension   = Path.GetExtension(path);
            var pathWithNoExtension = Path.GetFileNameWithoutExtension(path);

            while (File.Exists(backupPath))
            {
                counter++;
                backupPath = pathWithNoExtension + counter + originalExtension + ".bak";
            }
            // An earlier version copied the file to a temp file. We can't MOVE to a file in the system temp
            // directory, though, because we're not sure it is on the same volume. And sometimes the time
            // required to copy the file was noticeable and resulted in the user starting to speak before
            // the system started recording. So we pay the price of a small chance of backups being left
            // around the book directory to avoid that danger.
            if (RobustFile.Exists(path))
            {
                try
                {
                    RobustFile.Move(path, backupPath);
                }
                catch (Exception err)
                {
                    ErrorReport.NotifyUserOfProblem(err,
                                                    "The old copy of the recording at " + path +
                                                    " is locked up, so Bloom can't record over it at the moment. If it remains stuck, you may need to restart your computer.");
                    request.Failed("Audio file locked");
                    return(false);
                }
            }

            return(true);
        }
Exemple #9
0
 public void Dispose()
 {
     RobustFile.Move($"{_wsFile}{_localrepoupdate}", _wsFile);
 }
        /// ------------------------------------------------------------------------------------
        public void Load()
        {
            try
            {
                // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this
                // using some non-roman collection names...specifically, one involving the Northern Pashti
                // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the
                // implementation of Linq.XElement.Load() the path is converted to a URL and then back
                // to a path and something changes in that process so that a valid path passed to Load()
                // raises an invalid path exception. Reading the file directly and then parsing the string
                // works around this problem.
                var settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8);
                var nameMigrations  = new[]
                {
                    new[] { "LanguageName", "Language1Name" },
                    new[] { "IsShellLibrary", "IsSourceCollection" },
                    new[] { "National1Iso639Code", "Language2Iso639Code" },
                    new[] { "National2Iso639Code", "Language3Iso639Code" },
                    new[] { "IsShellMakingProject", "IsSourceCollection" },
                    new[] { "Local Community", "Local-Community" }                   // migrate for 4.4
                };

                foreach (var fromTo in nameMigrations)
                {
                    settingsContent = settingsContent.Replace(fromTo[0], fromTo[1]);
                }

                var xml = XElement.Parse(settingsContent);

                Language1.ReadFromXml(xml, true, "en");
                Language2.ReadFromXml(xml, true, "self");
                Language3.ReadFromXml(xml, true, Language2.Iso639Code);

                SignLanguageIso639Code = ReadString(xml, "SignLanguageIso639Code",                  /* old name */
                                                    ReadString(xml, "SignLanguageIso639Code", ""));
                XMatterPackName = ReadString(xml, "XMatterPack", "Factory");

                var style = ReadString(xml, "PageNumberStyle", "Decimal");

                //for historical (and maybe future?) reasons, we collect the page number style as one of the
                //CSS counter number styles
                PageNumberStyle           = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal";
                OneTimeCheckVersionNumber = ReadInteger(xml, "OneTimeCheckVersionNumber", 0);
                BrandingProjectKey        = ReadString(xml, "BrandingProjectName", "Default");
                SubscriptionCode          = ReadString(xml, "SubscriptionCode", null);

                if (BrandingProjectKey != "Default" && BrandingProjectKey != "Local-Community" && !Program.RunningHarvesterMode)
                {
                    // Validate branding, so things can't be circumvented by just typing something into settings
                    var expirationDate = CollectionSettingsApi.GetExpirationDate(SubscriptionCode);
                    if (expirationDate < DateTime.Now || BrandingProject.GetProjectChoices().All(bp => bp.Key != BrandingProjectKey))
                    {
                        InvalidBranding    = BrandingProjectKey;
                        BrandingProjectKey = "Default";                         // keep the code, but don't use it as active branding.
                    }
                }
                SignLanguageName   = ReadString(xml, "SignLanguageName", GetSignLanguageName_NoCache());
                Country            = ReadString(xml, "Country", "");
                Province           = ReadString(xml, "Province", "");
                District           = ReadString(xml, "District", "");
                AllowNewBooks      = ReadBoolean(xml, "AllowNewBooks", true);
                IsSourceCollection = ReadBoolean(xml, "IsSourceCollection", false);

                string audioRecordingModeStr = ReadString(xml, "AudioRecordingMode", "Unknown");
                TalkingBookApi.AudioRecordingMode parsedAudioRecordingMode;
                if (!Enum.TryParse(audioRecordingModeStr, out parsedAudioRecordingMode))
                {
                    parsedAudioRecordingMode = TalkingBookApi.AudioRecordingMode.Unknown;
                }
                AudioRecordingMode = parsedAudioRecordingMode;
                AudioRecordingTrimEndMilliseconds = ReadInteger(xml, "AudioRecordingTrimEndMilliseconds",
                                                                kDefaultAudioRecordingTrimEndMilliseconds);
            }
            catch (Exception e)
            {
                string settingsContents = "";
                try
                {
                    settingsContents = RobustFile.ReadAllText(SettingsFilePath);
                }
                catch (Exception error)
                {
                    settingsContents = error.Message;
                }
                Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents);
                SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}.  Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath);
                throw;
            }

            try
            {
                string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css");
                if (RobustFile.Exists(oldcustomCollectionStylesPath))
                {
                    string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css");

                    RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath);
                }
            }
            catch (Exception)
            {
                //ah well, we tried, no big deal, only a couple of beta testers used this old name
            }

            // Check if we need to do a one time check (perhaps migrate to a new Settings value)
            if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber)
            {
                DoOneTimeCheck();
            }

            SetAnalyticsProperties();
        }
Exemple #11
0
        private void ConfigureBookInternal(string bookPath)
        {
            /* setup jquery in chrome console (first open a local file):
             * script = document.createElement("script");
             *              script.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
             *
             *
             * Other snippets
             *
             * document.body.appendChild(script);
             *
             * alert(jQuery.parseJSON('{\"message\": \"triscuit\"}').message)
             *
             *
             * alert($().jquery)
             */

            var dom = XmlHtmlConverter.GetXmlDomFromHtmlFile(bookPath, false);

            XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(dom);
            XmlHtmlConverter.SaveDOMAsHtml5(dom, bookPath);

            var b = new GeckoWebBrowser();
            var neededToMakeThingsWork = b.Handle;

            NavigateAndWait(b, bookPath);

            //Now we call the method which takes that confuration data and adds/removes/updates pages.
            //We have the data as json string, so first we turn it into object for the updateDom's convenience.
            RunJavaScript(b, "runUpdate(" + GetAllData() + ")");

            //Ok, so we should have a modified DOM now, which we can save back over the top.

            //nice non-ascii paths kill this, so let's go to a temp file first
            var temp = TempFile.CreateAndGetPathButDontMakeTheFile();             //we don't want to wrap this in using

            b.SaveDocument(temp.Path);
            RobustFile.Delete(bookPath);
            RobustFile.Move(temp.Path, bookPath);

            var sanityCheckDom = XmlHtmlConverter.GetXmlDomFromHtmlFile(bookPath, false);

            // Because the Mozilla code loaded the document from a filename initially, and we later save to a
            // different directory, Geckofx45's SaveDocument writes out the stylesheet links as absolute paths
            // using the file:// protocol markup. When we try to open the new file, Mozilla then complains
            // vociferously about security issues, and refuses to access the stylesheets as far as I can tell.
            // Eventually, several of the stylesheets are cleaned up by being added in again, but a couple of
            // them end up with invalid relative paths because they never get re-added.  So let's go through
            // all the stylesheet links here and remove everything except the bare filenames.
            // See https://silbloom.myjetbrains.com/youtrack/issue/BL-3573 for what happens without this fix.
            foreach (System.Xml.XmlElement link in sanityCheckDom.SafeSelectNodes("//link[@rel='stylesheet']"))
            {
                var href = link.GetAttribute("href");
                if (href.StartsWith("file://"))
                {
                    link.SetAttribute("href", Path.GetFileName(href.Replace("file:///", "").Replace("file://", "")));
                }
            }
            XmlHtmlConverter.SaveDOMAsHtml5(sanityCheckDom, bookPath);

            //NB: this check only makes sense for the calendar, which is the only template we've create that
            // uses this class, and there are no other templates on the drawing board that would use it.
            // If/when we use this for something else, this
            //won't work. But by then, we should be using a version of geckofx that can reliably tell us
            //when it is done with the previous navigation.
            if (sanityCheckDom.SafeSelectNodes("//div[contains(@class,'bloom-page')]").Count < 24) //should be 24 pages
            {
                Logger.WriteMinorEvent(RobustFile.ReadAllText(bookPath));                          //this will come to us if they report it
                throw new ApplicationException("Malformed Calendar (code assumes only calendar uses the Configurator, and they have at least 24 pages)");
            }

            //NB: we *want* exceptions thrown from the above to make it out.
        }
Exemple #12
0
        ///  <summary>
        ///
        ///  </summary>
        /// <param name="pdfPath">this is the path where it already exists, and the path where we leave the transformed version</param>
        /// <param name="incomingPaperSize"></param>
        /// <param name="booketLayoutMethod"></param>
        /// <param name="layoutPagesForRightToLeft"></param>
        private void MakeBooklet(string pdfPath, string incomingPaperSize, PublishModel.BookletLayoutMethod booketLayoutMethod, bool layoutPagesForRightToLeft)
        {
            //TODO: we need to let the user chose the paper size, as they do in PdfDroplet.
            //For now, just assume a size double the original

            PageSize pageSize;

            switch (incomingPaperSize)
            {
            case "A3":
                pageSize = PageSize.A2;
                break;

            case "A4":
                pageSize = PageSize.A3;
                break;

            case "A5":
                pageSize = PageSize.A4;
                break;

            case "A6":
                pageSize = PageSize.A5;
                break;

            case "B5":
                pageSize = PageSize.B4;
                break;

            case "Letter":
                pageSize = PageSize.Ledger;
                break;

            case "HalfLetter":
                pageSize = PageSize.Letter;
                break;

            case "QuarterLetter":
                pageSize = PageSize.Statement;                          // ?? Wikipedia says HalfLetter is aka Statement
                break;

            case "Legal":
                pageSize = PageSize.Legal;                        //TODO... what's reasonable?
                break;

            case "HalfLegal":
                pageSize = PageSize.Legal;
                break;

            default:
                throw new ApplicationException("PdfMaker.MakeBooklet() does not contain a map from " + incomingPaperSize + " to a PdfSharp paper size.");
            }

            using (var incoming = new TempFile())
            {
                RobustFile.Delete(incoming.Path);
                RobustFile.Move(pdfPath, incoming.Path);

                LayoutMethod method;
                switch (booketLayoutMethod)
                {
                case PublishModel.BookletLayoutMethod.NoBooklet:
                    method = new NullLayoutMethod();
                    break;

                case PublishModel.BookletLayoutMethod.SideFold:
                    // To keep the GUI simple, we assume that A6 page size for booklets
                    // implies 4up printing on A4 paper.  This feature was requested by
                    // https://jira.sil.org/browse/BL-1059 "A6 booklets should print 4
                    // to an A4 sheet".  The same is done for QuarterLetter booklets
                    // printing on Letter size sheets.
                    if (incomingPaperSize == "A6")
                    {
                        method   = new SideFold4UpBookletLayouter();
                        pageSize = PageSize.A4;
                    }
                    else if (incomingPaperSize == "QuarterLetter")
                    {
                        method   = new SideFold4UpBookletLayouter();
                        pageSize = PageSize.Letter;
                    }
                    else
                    {
                        method = new SideFoldBookletLayouter();
                    }
                    break;

                case PublishModel.BookletLayoutMethod.CutAndStack:
                    method = new CutLandscapeLayout();
                    break;

                case PublishModel.BookletLayoutMethod.Calendar:
                    method = new CalendarLayouter();
                    break;

                default:
                    throw new ArgumentOutOfRangeException("booketLayoutMethod");
                }
                var paperTarget = new PaperTarget("ZZ" /*we're not displaying this anyhwere, so we don't need to know the name*/, pageSize);
                var pdf         = XPdfForm.FromFile(incoming.Path);        //REVIEW: this whole giving them the pdf and the file too... I checked once and it wasn't wasting effort...the path was only used with a NullLayout option
                method.Layout(pdf, incoming.Path, pdfPath, paperTarget, layoutPagesForRightToLeft, ShowCropMarks);
            }
        }
Exemple #13
0
        /// ------------------------------------------------------------------------------------
        public void Load()
        {
            try
            {
                // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this
                // using some non-roman collection names...specifically, one involving the Northern Pashti
                // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the
                // implementation of Linq.XElement.Load() the path is converted to a URL and then back
                // to a path and something changes in that process so that a valid path passed to Load()
                // raises an invalid path exception. Reading the file directly and then parsing the string
                // works around this problem.
                var      settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8);
                XElement library         = XElement.Parse(settingsContent);

                Language1Iso639Code = GetValue(library, "Language1Iso639Code", /* old name */ GetValue(library, "Language1Iso639Code", ""));
                Language2Iso639Code = GetValue(library, "Language2Iso639Code", /* old name */ GetValue(library, "National1Iso639Code", "en"));
                Language3Iso639Code = GetValue(library, "Language3Iso639Code", /* old name */ GetValue(library, "National2Iso639Code", ""));
                XMatterPackName     = GetValue(library, "XMatterPack", "Factory");

                var style = GetValue(library, "PageNumberStyle", "Decimal");

                //for historical (and maybe future?) reasons, we collect the page number style as one of the
                //CSS counter number styles
                PageNumberStyle = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal";

                BrandingProjectKey = GetValue(library, "BrandingProjectName", "Default");

                Language1Name                    = GetValue(library, "Language1Name", /* old name */ GetValue(library, "LanguageName", ""));
                Language2Name                    = GetValue(library, "Language2Name", GetLanguage2Name_NoCache(Language2Iso639Code));
                Language3Name                    = GetValue(library, "Language3Name", GetLanguage3Name_NoCache(Language2Iso639Code));
                DefaultLanguage1FontName         = GetValue(library, "DefaultLanguage1FontName", GetDefaultFontName());
                DefaultLanguage2FontName         = GetValue(library, "DefaultLanguage2FontName", GetDefaultFontName());
                DefaultLanguage3FontName         = GetValue(library, "DefaultLanguage3FontName", GetDefaultFontName());
                OneTimeCheckVersionNumber        = GetIntegerValue(library, "OneTimeCheckVersionNumber", 0);
                IsLanguage1Rtl                   = GetBoolValue(library, "IsLanguage1Rtl", false);
                IsLanguage2Rtl                   = GetBoolValue(library, "IsLanguage2Rtl", false);
                IsLanguage3Rtl                   = GetBoolValue(library, "IsLanguage3Rtl", false);
                Language1LineHeight              = GetDecimalValue(library, "Language1LineHeight", 0);
                Language2LineHeight              = GetDecimalValue(library, "Language2LineHeight", 0);
                Language3LineHeight              = GetDecimalValue(library, "Language3LineHeight", 0);
                Language1BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language1BreaksLinesOnlyAtSpaces", false);
                Language2BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language2BreaksLinesOnlyAtSpaces", false);
                Language3BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language3BreaksLinesOnlyAtSpaces", false);

                Country            = GetValue(library, "Country", "");
                Province           = GetValue(library, "Province", "");
                District           = GetValue(library, "District", "");
                AllowNewBooks      = GetBoolValue(library, "AllowNewBooks", true);
                IsSourceCollection = GetBoolValue(library, "IsSourceCollection", GetBoolValue(library, "IsShellLibrary" /*the old name*/, GetBoolValue(library, "IsShellMakingProject" /*an even older name*/, false)));
            }
            catch (Exception e)
            {
                string settingsContents = "";
                try
                {
                    settingsContents = RobustFile.ReadAllText(SettingsFilePath);
                }
                catch (Exception error)
                {
                    settingsContents = error.Message;
                }
                Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents);
                SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}.  Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath);
                throw;
            }

            try
            {
                string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css");
                if (RobustFile.Exists(oldcustomCollectionStylesPath))
                {
                    string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css");

                    RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath);
                }
            }
            catch (Exception)
            {
                //ah well, we tried, no big deal, only a couple of beta testers used this old name
            }

            // Check if we need to do a one time check (perhaps migrate to a new Settings value)
            if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber)
            {
                DoOneTimeCheck();
            }

            // Remove an obsolete page numbering rule if it exists in the collection styles file.
            // See https://issues.bloomlibrary.org/youtrack/issue/BL-5017.
            // Saving the styles doesn't write the obsolete rule, effectively removing it.  Doing
            // this unconditionally ensures any future similar problems are covered automatically.
            SaveSettingsCollectionStylesCss();

            SetAnalyticsProperties();
        }
Exemple #14
0
        ///  <summary>
        ///
        ///  </summary>
        /// <param name="specs">All the information about what sort of PDF file to make where</param>
        /// <param name="worker">If not null, the Background worker which is running this task, and may be queried to determine whether a cancel is being attempted</param>
        /// <param name="doWorkEventArgs">The event passed to the worker when it was started. If a cancel is successful, it's Cancel property should be set true.</param>
        /// <param name="owner">A control which can be used to invoke parts of the work which must be done on the ui thread.</param>
        public void MakePdf(PdfMakingSpecs specs, BackgroundWorker worker, DoWorkEventArgs doWorkEventArgs, Control owner)
        {
            // Try up to 4 times. This is a last-resort attempt to handle BL-361.
            // Most likely that was caused by a race condition in MakePdfUsingGeckofxHtmlToPdfComponent.MakePdf,
            // but as it was an intermittent problem and we're not sure that was the cause, this might help.
            for (int i = 0; i < 4; i++)
            {
                new MakePdfUsingGeckofxHtmlToPdfProgram().MakePdf(specs,
                                                                  owner, worker, doWorkEventArgs);

                if (doWorkEventArgs.Cancel || (doWorkEventArgs.Result != null && doWorkEventArgs.Result is Exception))
                {
                    return;
                }
                if (RobustFile.Exists(specs.OutputPdfPath))
                {
                    break;                     // normally the first time
                }
            }
            if (!RobustFile.Exists(specs.OutputPdfPath) && owner != null)
            {
                // Should never happen, but...
                owner.Invoke((Action)(() =>
                {
                    // Review: should we localize this? Hopefully the user never sees it...don't want to increase burden on localizers...
                    MessageBox.Show(
                        "Bloom unexpectedly failed to create the PDF. If this happens repeatedy please report it to the developers. Probably it will work if you just try again.",
                        "Pdf creation failed", MessageBoxButtons.OK);
                }));
                doWorkEventArgs.Result = MakingPdfFailedException.CreatePdfException();
                return;
            }

            try
            {
                // Shrink the PDF file, especially if it has large color images.  (BL-3721)
                // Also if the book is full bleed we need to remove some spurious pages.
                // Removing spurious pages must be done BEFORE we switch pages around to make a booklet!
                // Note: previously compression was the last step, after making a booklet. We moved it before for
                // the reason above. Seems like it would also have performance benefits, if anything, to shrink
                // the file before manipulating it further. Just noting it in case there are unexpected issues.
                var fixPdf = new ProcessPdfWithGhostscript(ProcessPdfWithGhostscript.OutputType.DesktopPrinting, worker);
                fixPdf.ProcessPdfFile(specs.OutputPdfPath, specs.OutputPdfPath, specs.BookIsFullBleed);
                if (specs.BookletPortion != PublishModel.BookletPortions.AllPagesNoBooklet || specs.PrintWithFullBleed)
                {
                    //remake the pdf by reording the pages (and sometimes rotating, shrinking, etc)
                    MakeBooklet(specs);
                }

                // Check that we got a valid, readable PDF.
                // If we get a reliable fix to BL-932 we can take this out altogether.
                // It's probably redundant, since the compression process would probably fail with this
                // sort of corruption, and we are many generations beyond gecko29 where we observed it.
                // However, we don't have data to reliably reproduce the BL-932, and the check doesn't take
                // long, so leaving it in for now.
                CheckPdf(specs.OutputPdfPath);
            }
            catch (KeyNotFoundException e)
            {
                // This is characteristic of BL-932, where Gecko29 fails to make a valid PDF, typically
                // because the user has embedded a really huge image, something like 4000 pixels wide.
                // We think it could also happen with a very long book or if the user is short of memory.
                // The resulting corruption of the PDF file takes the form of a syntax error in an embedded
                // object so that the parser finds an empty string where it expected a 'generationNumber'
                // (currently line 106 of Parser.cs). This exception is swallowed but leads to an empty
                // externalIDs dictionary in PdfImportedObjectTable, and eventually a new exception trying
                // to look up an object ID at line 121 of that class. We catch that exception here and
                // suggest possible actions the user can take until we find a better solution.
                SIL.Reporting.ErrorReport.NotifyUserOfProblem(e,
                                                              LocalizationManager.GetString("PublishTab.PdfMaker.BadPdf", "Bloom had a problem making a PDF of this book. You may need technical help or to contact the developers. But here are some things you can try:")
                                                              + Environment.NewLine + "- "
                                                              + LocalizationManager.GetString("PublishTab.PdfMaker.TryRestart", "Restart your computer and try this again right away")
                                                              + Environment.NewLine + "- "
                                                              +
                                                              LocalizationManager.GetString("PublishTab.PdfMaker.TrySmallerImages",
                                                                                            "Replace large, high-resolution images in your document with lower-resolution ones")
                                                              + Environment.NewLine + "- "
                                                              + LocalizationManager.GetString("PublishTab.PdfMaker.TryMoreMemory", "Try doing this on a computer with more memory"));

                RobustFile.Move(specs.OutputPdfPath, specs.OutputPdfPath + "-BAD");
                doWorkEventArgs.Result = MakingPdfFailedException.CreatePdfException();
            }
        }
Exemple #15
0
        public AzureMonitorLogger(EnvironmentSetting environment, string harvesterId)
        {
            _issueReporter = YouTrackIssueConnector.GetInstance(environment);

            // Get the Instrumentation Key for Azure from an environment variable.
            string environmentVarName = "BloomHarvesterAzureAppInsightsKeyDev";

            if (environment == EnvironmentSetting.Test)
            {
                environmentVarName = "BloomHarvesterAzureAppInsightsKeyTest";
            }
            else if (environment == EnvironmentSetting.Prod)
            {
                environmentVarName = "BloomHarvesterAzureAppInsightsKeyProd";
            }

            string instrumentationKey = Environment.GetEnvironmentVariable(environmentVarName);

            Debug.Assert(!String.IsNullOrWhiteSpace(instrumentationKey), "Azure Instrumentation Key is invalid. Azure logging probably won't work.");

            try
            {
                Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey;
            }
            catch (ArgumentNullException e)
            {
                _issueReporter.ReportException(e, $"InstrumentationKey: {instrumentationKey ?? "null"}.\nenvironmentVarName: {environmentVarName}", null);
            }

            _telemetry.Context.User.Id                = "BloomHarvester " + harvesterId;
            _telemetry.Context.Session.Id             = Guid.NewGuid().ToString();
            _telemetry.Context.Device.OperatingSystem = Environment.OSVersion.ToString();

            string logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "BloomHarvester", "log.txt");

            Console.Out.WriteLine("Creating log file at: " + logFilePath);
            try
            {
                if (File.Exists(logFilePath))
                {
                    // Check if the file is too big (~10 MB)
                    if (new FileInfo(logFilePath).Length > 10000000)
                    {
                        var oldPath = logFilePath + "-OLD";
                        // Preserve one previous log file for debugging help, and start over with
                        // an empty log file.
                        // (The data is in Azure too anyway, but having it local may speed things up.)
                        if (RobustFile.Exists(oldPath))
                        {
                            RobustFile.Delete(oldPath);
                        }
                        RobustFile.Move(logFilePath, oldPath);
                    }
                }
            }
            catch
            {
                // Doesn't matter if there are any errors
            }

            try
            {
                _fileLogger = new FileLogger(logFilePath);
            }
            catch
            {
                // That's unfortunate that creating the logger failed, but I don't really want to throw an exception since the file logger isn't even the main purpose of this calss.
                // Let's just replace it with something to get it to be quiet.
                _fileLogger = new NullLogger();
            }
        }
Exemple #16
0
        /// ------------------------------------------------------------------------------------
        public void Load()
        {
            try
            {
                // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this
                // using some non-roman collection names...specifically, one involving the Northern Pashto
                // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the
                // implementation of Linq.XElement.Load() the path is converted to a URL and then back
                // to a path and something changes in that process so that a valid path passed to Load()
                // raises an invalid path exception. Reading the file directly and then parsing the string
                // works around this problem.
                var settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8);
                var nameMigrations  = new[]
                {
                    new[] { "LanguageName", "Language1Name" },
                    new[] { "IsShellLibrary", "IsSourceCollection" },
                    new[] { "National1Iso639Code", "Language2Iso639Code" },
                    new[] { "National2Iso639Code", "Language3Iso639Code" },
                    new[] { "IsShellMakingProject", "IsSourceCollection" },
                    new[] { "Local Community", "Local-Community" }                   // migrate for 4.4
                };

                foreach (var fromTo in nameMigrations)
                {
                    settingsContent = settingsContent.Replace(fromTo[0], fromTo[1]);
                }

                var xml = XElement.Parse(settingsContent);
                // The default if we don't find one is the arbitrary ID generated when we initialized
                // the variable (at its declaration).
                CollectionId = ReadString(xml, "CollectionId", CollectionId);

                Language1.ReadFromXml(xml, true, "en");
                Language2.ReadFromXml(xml, true, "self");
                Language3.ReadFromXml(xml, true, Language2.Iso639Code);

                SignLanguageIso639Code = ReadString(xml, "SignLanguageIso639Code",                  /* old name */
                                                    ReadString(xml, "SignLanguageIso639Code", ""));
                XMatterPackName = ReadString(xml, "XMatterPack", "Factory");

                var style = ReadString(xml, "PageNumberStyle", "Decimal");

                //for historical (and maybe future?) reasons, we collect the page number style as one of the
                //CSS counter number styles
                PageNumberStyle           = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal";
                OneTimeCheckVersionNumber = ReadInteger(xml, "OneTimeCheckVersionNumber", 0);
                BrandingProjectKey        = ReadString(xml, "BrandingProjectName", "Default");
                SubscriptionCode          = ReadString(xml, "SubscriptionCode", null);

                if (BrandingProjectKey != "Default" && BrandingProjectKey != "Local-Community" && !Program.RunningHarvesterMode)
                {
                    // Validate branding, so things can't be circumvented by just typing something random into settings
                    var expirationDate = CollectionSettingsApi.GetExpirationDate(SubscriptionCode);
                    if (expirationDate < DateTime.Now)                      // no longer require branding files to exist yet
                    {
                        InvalidBranding    = BrandingProjectKey;
                        BrandingProjectKey = "Default";                         // keep the code, but don't use it as active branding.
                    }
                }
                SignLanguageName   = ReadString(xml, "SignLanguageName", GetSignLanguageName_NoCache());
                Country            = ReadString(xml, "Country", "");
                Province           = ReadString(xml, "Province", "");
                District           = ReadString(xml, "District", "");
                AllowNewBooks      = ReadBoolean(xml, "AllowNewBooks", true);
                IsSourceCollection = ReadBoolean(xml, "IsSourceCollection", false);

                string audioRecordingModeStr = ReadString(xml, "AudioRecordingMode", "Unknown");
                TalkingBookApi.AudioRecordingMode parsedAudioRecordingMode;
                if (!Enum.TryParse(audioRecordingModeStr, out parsedAudioRecordingMode))
                {
                    parsedAudioRecordingMode = TalkingBookApi.AudioRecordingMode.Unknown;
                }
                AudioRecordingMode = parsedAudioRecordingMode;
                AudioRecordingTrimEndMilliseconds = ReadInteger(xml, "AudioRecordingTrimEndMilliseconds",
                                                                kDefaultAudioRecordingTrimEndMilliseconds);
                Administrators = ReadString(xml, "Administrators", "")
                                 .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                var defaultTags         = ReadString(xml, "DefaultBookTags", "").Split(',');
                var defaultBookshelfTag = defaultTags.Where(t => t.StartsWith("bookshelf:")).FirstOrDefault();
                DefaultBookshelf = defaultBookshelfTag == null
                                        ? ""
                                        : defaultBookshelfTag.Substring("bookshelf:".Length);

                var bulkPublishSettingsFromXml = BulkBloomPubPublishSettings.LoadFromXElement(xml);
                if (bulkPublishSettingsFromXml != null)
                {
                    BulkPublishBloomPubSettings = bulkPublishSettingsFromXml;
                }
            }
            catch (Exception)
            {
                string settingsContents;
                try
                {
                    settingsContents = RobustFile.ReadAllText(SettingsFilePath);
                }
                catch (Exception error)
                {
                    settingsContents = error.Message;
                }
                Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents);

                // We used to notify the user of a problem here.
                // But now we decided it is better to catch at a higher level, at OpenProjectWindow(), else we have two different
                // error UI dialogs for the same problem. See BL-9916.
                throw;
            }

            try
            {
                string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css");
                if (RobustFile.Exists(oldcustomCollectionStylesPath))
                {
                    string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css");

                    RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath);
                }
            }
            catch (Exception)
            {
                //ah well, we tried, no big deal, only a couple of beta testers used this old name
            }

            // Check if we need to do a one time check (perhaps migrate to a new Settings value)
            if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber)
            {
                DoOneTimeCheck();
            }

            SetAnalyticsProperties();
        }
        /// ------------------------------------------------------------------------------------
        public void Load()
        {
            try
            {
                XElement library = SIL.IO.RobustIO.LoadXElement(SettingsFilePath);
                Language1Iso639Code = GetValue(library, "Language1Iso639Code", /* old name */ GetValue(library, "Language1Iso639Code", ""));
                Language2Iso639Code = GetValue(library, "Language2Iso639Code", /* old name */ GetValue(library, "National1Iso639Code", "en"));
                Language3Iso639Code = GetValue(library, "Language3Iso639Code", /* old name */ GetValue(library, "National2Iso639Code", ""));
                XMatterPackName     = GetValue(library, "XMatterPack", "Factory");

                var style = GetValue(library, "PageNumberStyle", "Decimal");
                PageNumberStyle = PageNumberStyleKeys.Contains(style) ? style : "Decimal";

                BrandingProjectName = GetValue(library, "BrandingProjectName", "Default");

                Language1Name             = GetValue(library, "Language1Name", /* old name */ GetValue(library, "LanguageName", ""));
                DefaultLanguage1FontName  = GetValue(library, "DefaultLanguage1FontName", GetDefaultFontName());
                DefaultLanguage2FontName  = GetValue(library, "DefaultLanguage2FontName", GetDefaultFontName());
                DefaultLanguage3FontName  = GetValue(library, "DefaultLanguage3FontName", GetDefaultFontName());
                OneTimeCheckVersionNumber = GetIntegerValue(library, "OneTimeCheckVersionNumber", 0);
                IsLanguage1Rtl            = GetBoolValue(library, "IsLanguage1Rtl", false);
                IsLanguage2Rtl            = GetBoolValue(library, "IsLanguage2Rtl", false);
                IsLanguage3Rtl            = GetBoolValue(library, "IsLanguage3Rtl", false);
                Language1LineHeight       = GetDecimalValue(library, "Language1LineHeight", 0);
                Language2LineHeight       = GetDecimalValue(library, "Language2LineHeight", 0);
                Language3LineHeight       = GetDecimalValue(library, "Language3LineHeight", 0);

                Country            = GetValue(library, "Country", "");
                Province           = GetValue(library, "Province", "");
                District           = GetValue(library, "District", "");
                AllowNewBooks      = GetBoolValue(library, "AllowNewBooks", true);
                IsSourceCollection = GetBoolValue(library, "IsSourceCollection", GetBoolValue(library, "IsShellLibrary" /*the old name*/, GetBoolValue(library, "IsShellMakingProject" /*an even older name*/, false)));
            }
            catch (Exception e)
            {
                string settingsContents = "";
                try
                {
                    settingsContents = RobustFile.ReadAllText(SettingsFilePath);
                }
                catch (Exception error)
                {
                    settingsContents = error.Message;
                }
                Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents);
                SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}.  Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath);
                throw;
            }

            try
            {
                string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css");
                if (RobustFile.Exists(oldcustomCollectionStylesPath))
                {
                    string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css");

                    RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath);
                }
            }
            catch (Exception)
            {
                //ah well, we tried, no big deal, only a couple of beta testers used this old name
            }

            // Check if we need to do a one time check (perhaps migrate to a new Settings value)
            if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber)
            {
                DoOneTimeCheck();
            }
        }
Exemple #18
0
        private void CleanUpAfterPressTooShort()
        {
            // Seems sometimes on a very short click the recording actually got started while we were informing the user
            // that he didn't click long enough. Before we try to delete the file where the recording is taking place,
            // we have to stop it; otherwise, we will get an exception trying to delete it.
            while (Recording)
            {
                try
                {
                    Recorder.Stop();
                    Application.DoEvents();
                }
                catch (Exception)
                {
                }
            }
            // Don't kid the user we have a recording for this.
            // Also, the absence of the file is how the UI knows to switch back to the state where 'speak'
            // is the expected action.
            try
            {
                // Delete doesn't throw if the FILE doesn't exist, but if the Directory doesn't, you're toast.
                // And the very first time a user tries this, the audio directory probably doesn't exist...
                if (Directory.Exists(Path.GetDirectoryName(PathToRecordableAudioForCurrentSegment)))
                {
                    RobustFile.Delete(PathToRecordableAudioForCurrentSegment);
                    // BL-6881: "Play btn sometimes enabled after too short audio", because the .mp3 version was left behind.
                    var mp3Version = Path.ChangeExtension(PathToRecordableAudioForCurrentSegment, kPublishableExtension);
                    RobustFile.Delete(mp3Version);
                }
            }
            catch (Exception error)
            {
                Logger.WriteError("Audio Recording trying to delete " + PathToRecordableAudioForCurrentSegment, error);
                Debug.Fail("can't delete the recording even after we stopped:" + error.Message);
            }

            // If we had a prior recording, restore it...button press may have been a mistake.
            if (RobustFile.Exists(_backupPathForRecordableAudio))
            {
                try
                {
                    RobustFile.Move(_backupPathForRecordableAudio, PathToRecordableAudioForCurrentSegment);
                }
                catch (IOException e)
                {
                    Logger.WriteError("Audio Recording could not restore backup " + _backupPathForRecordableAudio, e);
                    // if we can't restore it we can't. Review: are there other exception types we should ignore? Should we bother the user?
                }
            }
            if (RobustFile.Exists(_backupPathForPublishableAudio))
            {
                try
                {
                    RobustFile.Move(_backupPathForPublishableAudio, Path.ChangeExtension(PathToRecordableAudioForCurrentSegment, kPublishableExtension));
                }
                catch (IOException e)
                {
                    Logger.WriteError("Audio Recording could not restore backup " + _backupPathForPublishableAudio, e);
                }
            }
        }
        /// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile, bool removeEvenPages = false)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path, null, removeEvenPages);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.ExitCode != 0)
                    {
                        // On Linux, ghostscript doesn't deal well with some Unicode filenames.  Try renaming the input
                        // file temporarily to something innocuous to see if this makes the ghostscript process succeed.
                        // See https://issues.bloomlibrary.org/youtrack/issue/BL-7177.
                        using (var tempInputFile = TempFile.WithExtension(".pdf"))
                        {
                            RobustFile.Delete(tempInputFile.Path);                                      // Move won't replace even empty files.
                            RobustFile.Move(_inputPdfPath, tempInputFile.Path);
                            arguments = GetArguments(tempPdfFile.Path, tempInputFile.Path, removeEvenPages);
                            res       = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                            RobustFile.Move(tempInputFile.Path, _inputPdfPath);
                        }
                    }
                    if (res.ExitCode != 0 || res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme and we're not removing blank pages, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop || removeEvenPages)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
Exemple #20
0
        public static void CreateDirectoryShortcut(string targetPath, string whereToPutItPath)
        {
            var name          = Path.GetFileName(targetPath);
            var linkPath      = Path.Combine(whereToPutItPath, name) + ".lnk";
            var shortLinkPath = "";

            if (RobustFile.Exists(linkPath))
            {
                RobustFile.Delete(linkPath);
            }

#if !__MonoCS__
            var wshShell = new WshShellClass();
            var shortcut = (IWshShortcut)wshShell.CreateShortcut(linkPath);

            try
            {
                shortcut.TargetPath = targetPath;
            }
            catch (Exception)
            {
                if (targetPath == Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(targetPath)))
                {
                    throw;
                }

                // this exception was caused by non-ascii characters in the path, use 8.3 names instead
                var shortTargetPath = new StringBuilder(MAX_PATH);
                GetShortPathName(targetPath, shortTargetPath, MAX_PATH);

                var shortWhereToPutPath = new StringBuilder(MAX_PATH);
                GetShortPathName(whereToPutItPath, shortWhereToPutPath, MAX_PATH);

                name = Path.GetFileName(shortTargetPath.ToString());

                shortLinkPath = Path.Combine(shortWhereToPutPath.ToString(), name) + ".lnk";
                if (RobustFile.Exists(shortLinkPath))
                {
                    RobustFile.Delete(shortLinkPath);
                }

                shortcut            = (IWshShortcut)wshShell.CreateShortcut(shortLinkPath);
                shortcut.TargetPath = shortTargetPath.ToString();
            }

            shortcut.Save();

            // now rename the link to the correct name if needed
            if (!string.IsNullOrEmpty(shortLinkPath))
            {
                RobustFile.Move(shortLinkPath, linkPath);
            }
#else
            // It's tempting to use symbolic links instead which would work much nicer - iff
            // the UnixSymbolicLinkInfo class wouldn't cause us to crash...
//			var name = Path.GetFileName(targetPath);
//			string linkPath = Path.Combine(whereToPutItPath, name);
//			var shortcut = new Mono.Unix.UnixSymbolicLinkInfo(linkPath);
//			if (shortcut.Exists)
//				shortcut.Delete();
//
//			var target = new Mono.Unix.UnixSymbolicLinkInfo(targetPath);
//			target.CreateSymbolicLink(linkPath);

            RobustFile.WriteAllText(linkPath, targetPath);
#endif
        }