X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FConverter.cpp;h=664a4bb7180a32fe615384c8a584d277c48b0a99;hb=63c1979401271381e7667f8e55a018a728788aaa;hp=2b83b3d479f46e9537bef98d8797f7b41b488f42;hpb=1a0852630af07b5a5d71eae6f03b385b6f4431ee;p=lyx.git diff --git a/src/Converter.cpp b/src/Converter.cpp index 2b83b3d479..664a4bb718 100644 --- a/src/Converter.cpp +++ b/src/Converter.cpp @@ -19,20 +19,27 @@ #include "Encoding.h" #include "ErrorList.h" #include "Format.h" +#include "InsetList.h" #include "Language.h" #include "LaTeX.h" +#include "LyXRC.h" #include "Mover.h" +#include "ParagraphList.h" +#include "Session.h" #include "frontends/alert.h" +#include "insets/InsetInclude.h" + #include "support/debug.h" #include "support/FileNameList.h" #include "support/filetools.h" #include "support/gettext.h" +#include "support/lassert.h" #include "support/lstrings.h" #include "support/os.h" #include "support/Package.h" -#include "support/Path.h" +#include "support/PathChanger.h" #include "support/Systemcall.h" using namespace std; @@ -50,7 +57,9 @@ string const token_base("$$b"); string const token_to("$$o"); string const token_path("$$p"); string const token_orig_path("$$r"); +string const token_orig_from("$$f"); string const token_encoding("$$e"); +string const token_latex_encoding("$$E"); string const add_options(string const & command, string const & options) @@ -83,69 +92,58 @@ public: ConverterEqual(string const & from, string const & to) : from_(from), to_(to) {} bool operator()(Converter const & c) const { - return c.from == from_ && c.to == to_; + return c.from() == from_ && c.to() == to_; } private: string const from_; string const to_; }; -} // namespace anon +} // namespace Converter::Converter(string const & f, string const & t, string const & c, string const & l) - : from(f), to(t), command(c), flags(l), - From(0), To(0), latex(false), xml(false), - need_aux(false) + : from_(f), to_(t), command_(c), flags_(l), + From_(0), To_(0), latex_(false), xml_(false), + need_aux_(false), nice_(false), need_auth_(false) {} void Converter::readFlags() { - string flag_list(flags); + string flag_list(flags_); while (!flag_list.empty()) { string flag_name, flag_value; flag_list = split(flag_list, flag_value, ','); flag_value = split(flag_value, flag_name, '='); if (flag_name == "latex") { - latex = true; - latex_flavor = flag_value.empty() ? + latex_ = true; + latex_flavor_ = flag_value.empty() ? "latex" : flag_value; } else if (flag_name == "xml") - xml = true; + xml_ = true; else if (flag_name == "needaux") - need_aux = true; + need_aux_ = true; else if (flag_name == "resultdir") - result_dir = (flag_value.empty()) + result_dir_ = (flag_value.empty()) ? token_base : flag_value; else if (flag_name == "resultfile") - result_file = flag_value; + result_file_ = flag_value; else if (flag_name == "parselog") - parselog = flag_value; + parselog_ = flag_value; + else if (flag_name == "nice") + nice_ = true; + else if (flag_name == "needauth") + need_auth_ = true; } - if (!result_dir.empty() && result_file.empty()) - result_file = "index." + formats.extension(to); + if (!result_dir_.empty() && result_file_.empty()) + result_file_ = "index." + theFormats().extension(to_); //if (!contains(command, token_from)) // latex = true; } -bool operator<(Converter const & a, Converter const & b) -{ - // use the compare_ascii_no_case instead of compare_no_case, - // because in turkish, 'i' is not the lowercase version of 'I', - // and thus turkish locale breaks parsing of tags. - int const i = compare_ascii_no_case(a.From->prettyname(), - b.From->prettyname()); - if (i == 0) - return compare_ascii_no_case(a.To->prettyname(), - b.To->prettyname()) < 0; - else - return i < 0; -} - - Converter const * Converters::getConverter(string const & from, string const & to) const { @@ -174,8 +172,8 @@ int Converters::getNumber(string const & from, string const & to) const void Converters::add(string const & from, string const & to, string const & command, string const & flags) { - formats.add(from); - formats.add(to); + theFormats().add(from); + theFormats().add(to); ConverterList::iterator it = find_if(converterlist_.begin(), converterlist_.end(), ConverterEqual(from , to)); @@ -183,23 +181,36 @@ void Converters::add(string const & from, string const & to, Converter converter(from, to, command, flags); if (it != converterlist_.end() && !flags.empty() && flags[0] == '*') { converter = *it; - converter.command = command; - converter.flags = flags; + converter.setCommand(command); + converter.setFlags(flags); } converter.readFlags(); - // If we have both latex & pdflatex, we set latex_command to latex. // The latex_command is used to update the .aux file when running // a converter that uses it. - if (converter.latex - && (latex_command_.empty() || converter.latex_flavor == "latex")) - latex_command_ = subst(command, token_from, ""); + if (converter.latex()) { + if (latex_command_.empty() || + converter.latex_flavor() == "latex") + latex_command_ = subst(command, token_from, ""); + if (dvilualatex_command_.empty() || + converter.latex_flavor() == "dvilualatex") + dvilualatex_command_ = subst(command, token_from, ""); + if (lualatex_command_.empty() || + converter.latex_flavor() == "lualatex") + lualatex_command_ = subst(command, token_from, ""); + if (pdflatex_command_.empty() || + converter.latex_flavor() == "pdflatex") + pdflatex_command_ = subst(command, token_from, ""); + if (xelatex_command_.empty() || + converter.latex_flavor() == "xelatex") + xelatex_command_ = subst(command, token_from, ""); + } if (it == converterlist_.end()) { converterlist_.push_back(converter); } else { - converter.From = it->From; - converter.To = it->To; + converter.setFrom(it->From()); + converter.setTo(it->To()); *it = converter; } } @@ -228,8 +239,8 @@ void Converters::update(Formats const & formats) ConverterList::iterator it = converterlist_.begin(); ConverterList::iterator end = converterlist_.end(); for (; it != end; ++it) { - it->From = formats.getFormat(it->from); - it->To = formats.getFormat(it->to); + it->setFrom(formats.getFormat(it->from())); + it->setTo(formats.getFormat(it->to())); } } @@ -240,34 +251,136 @@ void Converters::updateLast(Formats const & formats) { if (converterlist_.begin() != converterlist_.end()) { ConverterList::iterator it = converterlist_.end() - 1; - it->From = formats.getFormat(it->from); - it->To = formats.getFormat(it->to); + it->setFrom(formats.getFormat(it->from())); + it->setTo(formats.getFormat(it->to())); } } -void Converters::sort() -{ - std::sort(converterlist_.begin(), converterlist_.end()); -} - - -OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path) +OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path, + Buffer const * buffer) { for (Graph::EdgePath::const_iterator cit = path.begin(); cit != path.end(); ++cit) { Converter const & conv = converterlist_[*cit]; - if (conv.latex) - if (conv.latex_flavor == "xelatex") + if (conv.latex()) { + if (conv.latex_flavor() == "latex") + return OutputParams::LATEX; + if (conv.latex_flavor() == "xelatex") return OutputParams::XETEX; - if (conv.latex_flavor == "lualatex") + if (conv.latex_flavor() == "lualatex") return OutputParams::LUATEX; - if (conv.latex_flavor == "pdflatex") + if (conv.latex_flavor() == "dvilualatex") + return OutputParams::DVILUATEX; + if (conv.latex_flavor() == "pdflatex") return OutputParams::PDFLATEX; - if (conv.xml) + } + if (conv.xml()) return OutputParams::XML; } - return OutputParams::LATEX; + return buffer ? buffer->params().getOutputFlavor() + : OutputParams::LATEX; +} + + +bool Converters::checkAuth(Converter const & conv, string const & doc_fname, + bool use_shell_escape) +{ + string conv_command = conv.command(); + bool const has_shell_escape = contains(conv_command, "-shell-escape") + || contains(conv_command, "-enable-write18"); + if (conv.latex() && has_shell_escape && !use_shell_escape) { + docstring const shellescape_warning = + bformat(_("
The following LaTeX backend has been " + "configured to allow execution of external programs " + "for any document:
" + "%1$s
This is a dangerous configuration. Please, " + "consider using the support offered by LyX for " + "allowing this privilege only to documents that " + "actually need it, instead.
"), + from_utf8(conv_command)); + frontend::Alert::error(_("Security Warning"), + shellescape_warning , false); + } else if (!conv.latex()) + use_shell_escape = false; + if (!conv.need_auth() && !use_shell_escape) + return true; + size_t const token_pos = conv_command.find("$$"); + bool const has_token = token_pos != string::npos; + string const command = use_shell_escape && !has_shell_escape + ? (has_token ? conv_command.insert(token_pos, "-shell-escape ") + : conv_command.append(" -shell-escape")) + : conv_command; + docstring const security_warning = (use_shell_escape + ? bformat(_("The following LaTeX backend has been requested " + "to allow execution of external programs:
" + "%1$s
The external programs can execute arbitrary commands on " + "your system, including dangerous ones, if instructed to do " + "so by a maliciously crafted LyX document.
"), + from_utf8(command)) + : bformat(_("The requested operation requires the use of a " + "converter from %2$s to %3$s:
" + "" + "%1$s
This external program can execute arbitrary commands on " + "your system, including dangerous ones, if instructed to do " + "so by a maliciously crafted LyX document.
"), + from_utf8(command), from_utf8(conv.from()), + from_utf8(conv.to()))); + if (lyxrc.use_converter_needauth_forbidden && !use_shell_escape) { + frontend::Alert::error( + _("An external converter is disabled for security reasons"), + security_warning + _( + "Your current preference settings forbid its execution.
" + "(To change this setting, go to Preferences ▹ File " + "Handling ▹ Converters and uncheck Security ▹ " + "Forbid needauth converters.)"), false); + return false; + } + if (!lyxrc.use_converter_needauth && !use_shell_escape) + return true; + docstring const security_title = use_shell_escape + ? _("A LaTeX backend requires your authorization") + : _("An external converter requires your authorization"); + int choice; + docstring const security_warning2 = security_warning + (use_shell_escape + ? _("
Should LaTeX backends be allowed to run external " + "programs?
Allow them only if you trust the " + "origin/sender of the LyX document!
") + : _("Would you like to run this converter?
" + "Only run if you trust the origin/sender of the LyX " + "document!
")); + docstring const no = use_shell_escape + ? _("Do ¬ allow") : _("Do ¬ run"); + docstring const yes = use_shell_escape ? _("A&llow") : _("&Run"); + docstring const always = use_shell_escape + ? _("&Always allow for this document") + : _("&Always run for this document"); + if (!doc_fname.empty()) { + LYXERR(Debug::FILES, "looking up: " << doc_fname); + bool authorized = use_shell_escape + ? theSession().shellescapeFiles().findAuth(doc_fname) + : theSession().authFiles().find(doc_fname); + if (!authorized) { + choice = frontend::Alert::prompt(security_title, + security_warning2, + 0, 0, no, yes, always); + if (choice == 2) { + if (use_shell_escape) + theSession().shellescapeFiles().insert(doc_fname, true); + else + theSession().authFiles().insert(doc_fname); + } + } else { + choice = 1; + } + } else { + choice = frontend::Alert::prompt(security_title, + security_warning2, + 0, 0, no, yes); + } + return choice != 0; } @@ -291,19 +404,21 @@ bool Converters::convert(Buffer const * buffer, // default one from ImageMagic. string const from_ext = from_format.empty() ? getExtension(from_file.absFileName()) : - formats.extension(from_format); - string const to_ext = formats.extension(to_format); + theFormats().extension(from_format); + string const to_ext = theFormats().extension(to_format); string const command = os::python() + ' ' + quoteName(libFileSearch("scripts", "convertDefault.py").toFilesystemEncoding()) + - ' ' + - quoteName(from_ext + ':' + from_file.toFilesystemEncoding()) + - ' ' + - quoteName(to_ext + ':' + to_file.toFilesystemEncoding()); + ' ' + from_ext + ' ' + + quoteName(from_file.toFilesystemEncoding()) + + ' ' + to_ext + ' ' + + quoteName(to_file.toFilesystemEncoding()); LYXERR(Debug::FILES, "No converter defined! " "I use convertDefault.py:\n\t" << command); Systemcall one; - one.startscript(Systemcall::Wait, command); + one.startscript(Systemcall::Wait, command, + buffer ? buffer->filePath() : string(), + buffer ? buffer->layoutPos() : string()); if (to_file.isReadableFile()) { if (conversionflags & try_cache) ConverterCache::get().add(orig_from, @@ -330,15 +445,21 @@ bool Converters::convert(Buffer const * buffer, // buffer is only invalid for importing, and then runparams is not // used anyway. OutputParams runparams(buffer ? &buffer->params().encoding() : 0); - runparams.flavor = getFlavor(edgepath); + runparams.flavor = getFlavor(edgepath, buffer); if (buffer) { - runparams.use_japanese = buffer->bufferFormat() == "platex"; + runparams.use_japanese = + (buffer->params().bufferFormat() == "latex" + || suffixIs(buffer->params().bufferFormat(), "-ja")) + && buffer->params().encoding().package() == Encoding::japanese; runparams.use_indices = buffer->params().use_indices; - runparams.bibtex_command = (buffer->params().bibtex_command == "default") ? - string() : buffer->params().bibtex_command; + runparams.bibtex_command = buffer->params().bibtexCommand(); runparams.index_command = (buffer->params().index_command == "default") ? string() : buffer->params().index_command; + runparams.document_language = buffer->params().language->babel(); + runparams.only_childbibs = !buffer->params().useBiblatex() + && !buffer->params().useBibtopic() + && buffer->params().multibib == "child"; } // Some converters (e.g. lilypond) can only output files to the @@ -346,6 +467,8 @@ bool Converters::convert(Buffer const * buffer, // This has the added benefit that all other files that may be // generated by the converter are deleted when LyX closes and do not // clutter the real working directory. + // FIXME: This does not work if path is an UNC path on windows + // (bug 6127). string const path(onlyPath(from_file.absFileName())); // Prevent the compiler from optimizing away p FileName pp(path); @@ -362,22 +485,25 @@ bool Converters::convert(Buffer const * buffer, for (Graph::EdgePath::const_iterator cit = edgepath.begin(); cit != edgepath.end(); ++cit) { Converter const & conv = converterlist_[*cit]; - bool dummy = conv.To->dummy() && conv.to != "program"; + bool dummy = conv.To()->dummy() && conv.to() != "program"; if (!dummy) { LYXERR(Debug::FILES, "Converting from " - << conv.from << " to " << conv.to); + << conv.from() << " to " << conv.to()); } infile = outfile; - outfile = FileName(conv.result_dir.empty() - ? changeExtension(from_file.absFileName(), conv.To->extension()) - : addName(subst(conv.result_dir, + outfile = FileName(conv.result_file().empty() + ? changeExtension(from_file.absFileName(), conv.To()->extension()) + : addName(subst(conv.result_dir(), token_base, from_base), - subst(conv.result_file, + subst(conv.result_file(), token_base, onlyFileName(from_base)))); // if input and output files are equal, we use a // temporary file as intermediary (JMarc) FileName real_outfile; + if (!conv.result_file().empty()) + real_outfile = FileName(changeExtension(from_file.absFileName(), + conv.To()->extension())); if (outfile == infile) { real_outfile = infile; // when importing, a buffer does not necessarily exist @@ -388,18 +514,88 @@ bool Converters::convert(Buffer const * buffer, "tmpfile.out")); } - if (conv.latex) { + if (buffer && buffer->params().use_minted + && lyxrc.pygmentize_command.empty() && conv.latex()) { + bool dowarn = false; + // Warn only if listings insets are actually used + for (Paragraph const & par : buffer->paragraphs()) { + InsetList const & insets = par.insetList(); + pos_type lstpos = insets.find(LISTINGS_CODE, 0); + pos_type incpos = insets.find(INCLUDE_CODE, 0); + if (incpos >= 0) { + InsetInclude const * include = + static_cast