00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <QFileInfo>
00025 #include <QDir>
00026 #include <QDateTime>
00027 #include <QByteArray>
00028
00029 #include <klfdefs.h>
00030 #include <klfdebug.h>
00031 #include <klfpobj.h>
00032 #include <klfdatautil.h>
00033
00034 #include "klfbackend.h"
00035 #include "klfbackend_p.h"
00036 #include "klfuserscript.h"
00037
00038
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 struct KLFUserScriptInfo::Private : public KLFPropertizedObject
00086 {
00087 Private()
00088 : KLFPropertizedObject("KLFUserScriptInfo")
00089 {
00090 refcount = 0;
00091 scriptInfoError = KLFERR_NOERROR;
00092
00093 registerBuiltInProperty(ExeScript, QLatin1String("ExeScript"));
00094 registerBuiltInProperty(Category, QLatin1String("Category"));
00095 registerBuiltInProperty(Name, QLatin1String("Name"));
00096 registerBuiltInProperty(Author, QLatin1String("Author"));
00097 registerBuiltInProperty(Version, QLatin1String("Version"));
00098 registerBuiltInProperty(License, QLatin1String("License"));
00099 registerBuiltInProperty(KLFMinVersion, QLatin1String("KLFMinVersion"));
00100 registerBuiltInProperty(KLFMaxVersion, QLatin1String("KLFMaxVersion"));
00101 registerBuiltInProperty(SettingsFormUI, QLatin1String("SettingsFormUI"));
00102 registerBuiltInProperty(CanProvideDefaultSettings, QLatin1String("CanProvideDefaultSettings"));
00103 registerBuiltInProperty(CategorySpecificXmlConfig, QLatin1String("CategorySpecificXmlConfig"));
00104 }
00105
00106 void clear()
00107 {
00108
00109 QList<int> idlist = registeredPropertyIdList();
00110 for (int k = 0; k < idlist.size(); ++k) {
00111 setProperty(idlist[k], QVariant());
00112 }
00113 }
00114
00115 int refcount;
00116 inline int ref() { return ++refcount; }
00117 inline int deref() { return --refcount; }
00118
00119 QString uspath;
00120 QString normalizedfname;
00121 QString sname;
00122 QString basename;
00123 int scriptInfoError;
00124 QString scriptInfoErrorString;
00125
00126 QStringList notices;
00127 QStringList warnings;
00128 QStringList errors;
00129
00130
00131 void _set_xml_read_error(const QString& fullerrmsg)
00132 {
00133 scriptInfoError = 999;
00134 scriptInfoErrorString = fullerrmsg;
00135 }
00136 void _set_xml_parsing_error(const QString& xmlfname, const QString& errmsg)
00137 {
00138 scriptInfoError = 999;
00139 scriptInfoErrorString = QString("Error parsing scriptinfo XML contents: %1: %2")
00140 .arg(xmlfname).arg(errmsg);
00141 }
00142
00143 void read_script_info()
00144 {
00145 scriptInfoError = KLFERR_NOERROR;
00146 scriptInfoErrorString = QString();
00147
00148 QString xmlfname = QDir::toNativeSeparators(uspath + "/scriptinfo.xml");
00149 QFile fxml(xmlfname);
00150 if ( ! fxml.open(QIODevice::ReadOnly) ) {
00151 _set_xml_read_error(QString("Can't open XML file %1: %2").arg(xmlfname).arg(fxml.errorString()));
00152 return;
00153 }
00154
00155 QDomDocument doc("klfuserscript-info");
00156 QString errMsg; int errLine, errCol;
00157 bool r = doc.setContent(&fxml, false, &errMsg, &errLine, &errCol);
00158 if (!r) {
00159 _set_xml_read_error(QString("XML parse error: %1 (file %2 line %3 col %4)")
00160 .arg(errMsg).arg(xmlfname).arg(errLine).arg(errCol));
00161 return;
00162 }
00163 fxml.close();
00164
00165 QDomElement root = doc.documentElement();
00166 if (root.nodeName() != "klfuserscript-info") {
00167 _set_xml_parsing_error(xmlfname, QString("expected <klfuserscript-info> as root document element"));
00168 return;
00169 }
00170
00171
00172 clear();
00173
00174 setProperty(CanProvideDefaultSettings, false);
00175
00176
00177 QDomNode n;
00178 for (n = root.firstChild(); !n.isNull(); n = n.nextSibling()) {
00179
00180 if ( n.nodeType() != QDomNode::ElementNode ) {
00181 continue;
00182 }
00183 QDomElement e = n.toElement();
00184 if ( e.isNull() ) {
00185 continue;
00186 }
00187
00188 QString val = e.text();
00189 if (val.isEmpty()) {
00190 val = QString();
00191 }
00192 if (e.nodeName() == "exe-script") {
00193 if (!property(ExeScript).toString().isEmpty()) {
00194 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <exe-script> element"));
00195 return;
00196 }
00197 setProperty(ExeScript, val);
00198 } else if (e.nodeName() == "name") {
00199 if (!property(Name).toString().isEmpty()) {
00200 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <name> element"));
00201 return;
00202 }
00203 setProperty(Name, val);
00204 } else if (e.nodeName() == "author") {
00205 setProperty(Author, property(Author).toStringList() + (QStringList()<<val));
00206 } else if (e.nodeName() == "version") {
00207 if (!property(Version).toString().isEmpty()) {
00208 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <version> element"));
00209 return;
00210 }
00211 setProperty(Version, val);
00212 } else if (e.nodeName() == "license") {
00213 if (!property(License).toString().isEmpty()) {
00214 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <license> element"));
00215 return;
00216 }
00217 setProperty(License, val);
00218 } else if (e.nodeName() == "klf-min-version") {
00219 if (!property(KLFMinVersion).toString().isEmpty()) {
00220 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <klf-min-version> element"));
00221 return;
00222 }
00223 setProperty(KLFMinVersion, val);
00224 } else if (e.nodeName() == "klf-max-version") {
00225 if (!property(KLFMaxVersion).toString().isEmpty()) {
00226 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <klf-max-version> element"));
00227 return;
00228 }
00229 setProperty(KLFMaxVersion, val);
00230 } else if (e.nodeName() == "category") {
00231 if (!property(Category).toString().isEmpty()) {
00232 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <category> element"));
00233 return;
00234 }
00235 setProperty(Category, val);
00236 } else if (e.nodeName() == "settings-form-ui") {
00237 if (!property(SettingsFormUI).toString().isEmpty()) {
00238 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <settings-form-ui> element"));
00239 return;
00240 }
00241 setProperty(SettingsFormUI, val);
00242 } else if (e.nodeName() == "can-provide-default-settings") {
00243 setProperty(CanProvideDefaultSettings, klfLoadVariantFromText(val.toUtf8(), "bool").toBool());
00244 } else {
00245 const QString category = property(Category).toString();
00246 if (e.nodeName() == category) {
00247 if (!property(CategorySpecificXmlConfig).toByteArray().isEmpty()) {
00248 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <%1> element")
00249 .arg(category));
00250 return;
00251 }
00252
00253 QByteArray xmlrepr;
00254 { QTextStream tstream(&xmlrepr);
00255 e.save(tstream, 2); }
00256 klfDbg("Read category-specific XML: " << xmlrepr);
00257 setProperty(CategorySpecificXmlConfig, xmlrepr);
00258 } else {
00259 _set_xml_parsing_error(xmlfname, QString::fromLatin1("Unexpected element: %1").arg(e.nodeName()));
00260 return;
00261 }
00262 }
00263 }
00264
00265 klfDbg("All properties read: \n" << qPrintable(toString()));
00266 }
00267
00268
00269 static QMap<QString,KLFRefPtr<Private> > userScriptInfoCache;
00270
00271 private:
00272
00273 Private(const Private& ) : KLFPropertizedObject("KLFUserScriptInfo") { }
00274 };
00275
00276
00277
00278 QMap<QString,KLFRefPtr<KLFUserScriptInfo::Private> > KLFUserScriptInfo::Private::userScriptInfoCache;
00279
00280 static QString normalizedFn(const QString& userScriptFileName)
00281 {
00282 return QFileInfo(userScriptFileName).canonicalFilePath();
00283 }
00284
00285
00286 KLFUserScriptInfo KLFUserScriptInfo::forceReloadScriptInfo(const QString& userScriptFileName)
00287 {
00288 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00289
00290 QString normalizedfn = normalizedFn(userScriptFileName);
00291 Private::userScriptInfoCache.remove(normalizedfn);
00292
00293 KLFUserScriptInfo usinfo(userScriptFileName) ;
00294 if (usinfo.scriptInfoError() != KLFERR_NOERROR) {
00295 klfWarning(qPrintable(usinfo.scriptInfoErrorString()));
00296 }
00297
00298 return usinfo;
00299 }
00300
00301 void KLFUserScriptInfo::clearCacheAll()
00302 {
00303
00304 Private::userScriptInfoCache.clear();
00305 }
00306
00307
00308
00309 bool KLFUserScriptInfo::hasScriptInfoInCache(const QString& userScriptFileName)
00310 {
00311 QString normalizedfn = normalizedFn(userScriptFileName);
00312 klfDbg("userScriptFileName = " << userScriptFileName << "; normalizedfn = " << normalizedfn) ;
00313 klfDbg("cache: " << Private::userScriptInfoCache) ;
00314 return Private::userScriptInfoCache.contains(normalizedfn);
00315 }
00316
00317 KLFUserScriptInfo::KLFUserScriptInfo(const QString& userScriptFileName)
00318 {
00319 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00320
00321 QFileInfo fi(userScriptFileName);
00322 QString normalizedfn = fi.canonicalFilePath();
00323 if (Private::userScriptInfoCache.contains(normalizedfn)) {
00324 d = Private::userScriptInfoCache[normalizedfn];
00325 } else {
00326 d = new KLFUserScriptInfo::Private;
00327
00328 d()->uspath = normalizedfn;
00329 d()->normalizedfname = normalizedfn;
00330 d()->sname = fi.fileName();
00331 d()->basename = fi.baseName();
00332
00333 d()->read_script_info();
00334
00335 if (d()->scriptInfoError == KLFERR_NOERROR) {
00336 Private::userScriptInfoCache[normalizedfn] = d();
00337 }
00338 }
00339 }
00340
00341 KLFUserScriptInfo::KLFUserScriptInfo(const KLFUserScriptInfo& copy)
00342 : KLFAbstractPropertizedObject(copy)
00343 {
00344
00345 d = copy.d;
00346 }
00347
00348 KLFUserScriptInfo::~KLFUserScriptInfo()
00349 {
00350 d.setNull();
00351 }
00352
00353 QString KLFUserScriptInfo::userScriptPath() const
00354 {
00355 return d()->uspath;
00356 }
00357 QString KLFUserScriptInfo::userScriptName() const
00358 {
00359 return d()->sname;
00360 }
00361 QString KLFUserScriptInfo::userScriptBaseName() const
00362 {
00363 return d()->basename;
00364 }
00365
00366 int KLFUserScriptInfo::scriptInfoError() const
00367 {
00368 return d()->scriptInfoError;
00369 }
00370 QString KLFUserScriptInfo::scriptInfoErrorString() const
00371 {
00372 return d()->scriptInfoErrorString;
00373 }
00374
00375
00376 void KLFUserScriptInfo::setScriptInfoError(int code, const QString & msg)
00377 {
00378 d()->scriptInfoError = code;
00379 d()->scriptInfoErrorString = msg;
00380 }
00381
00382 QString KLFUserScriptInfo::relativeFile(const QString& fname) const
00383 {
00384 return QDir::toNativeSeparators(userScriptPath()+"/"+fname);
00385 }
00386
00387 QString KLFUserScriptInfo::exeScript() const { return scriptInfo(ExeScript).toString(); }
00388 QString KLFUserScriptInfo::exeScriptFullPath() const
00389 {
00390 return relativeFile(exeScript());
00391 }
00392
00393 QString KLFUserScriptInfo::category() const { return scriptInfo(Category).toString(); }
00394 QString KLFUserScriptInfo::name() const { return scriptInfo(Name).toString(); }
00395 QString KLFUserScriptInfo::author() const { return scriptInfo(Author).toStringList().join("; "); }
00396 QStringList KLFUserScriptInfo::authorList() const { return scriptInfo(Author).toStringList(); }
00397 QString KLFUserScriptInfo::version() const { return scriptInfo(Version).toString(); }
00398 QString KLFUserScriptInfo::license() const { return scriptInfo(License).toString(); }
00399 QString KLFUserScriptInfo::klfMinVersion() const { return scriptInfo(KLFMinVersion).toString(); }
00400 QString KLFUserScriptInfo::klfMaxVersion() const { return scriptInfo(KLFMaxVersion).toString(); }
00401 QString KLFUserScriptInfo::settingsFormUI() const { return scriptInfo(SettingsFormUI).toString(); }
00402
00403 bool KLFUserScriptInfo::canProvideDefaultSettings() const { return scriptInfo(CanProvideDefaultSettings).toBool(); }
00404
00405 QMap<QString,QVariant> KLFUserScriptInfo::queryDefaultSettings(const KLFBackend::klfSettings * settings) const
00406 {
00407 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00408
00409 KLFUserScriptFilterProcess proc(userScriptPath(), settings);
00410
00411
00412
00413 proc.setProcessAppEvents(false);
00414
00415 proc.addArgv(QStringList() << QLatin1String("--query-default-settings"));
00416
00417
00418 QByteArray stdoutdata;
00419 QByteArray stderrdata;
00420 proc.collectStdoutTo(&stdoutdata);
00421 proc.collectStderrTo(&stderrdata);
00422
00423 bool ok = proc.run();
00424 if (!ok) {
00425 klfWarning("Error querying default config for user script "<<userScriptBaseName()<<": "
00426 << qPrintable(proc.resultErrorString())) ;
00427 return QMap<QString,QVariant>();
00428 }
00429
00430 klfDbg("stdoutdata = " << stdoutdata) ;
00431 klfDbg("stderrdata = " << stderrdata) ;
00432
00433 klfDbg("Ran script "<<userScriptPath()<<": stdout="<<stdoutdata<<"\n\tstderr="<<stderrdata) ;
00434
00435
00436
00437
00438
00439
00440
00441
00442 QByteArray trimmedstdoutdata = stdoutdata.trimmed();
00443 if (trimmedstdoutdata.startsWith("<?xml")) {
00444 QDomDocument doc("klfuserscript-default-settings");
00445 QString errMsg; int errLine, errCol;
00446 bool r = doc.setContent(trimmedstdoutdata, false, &errMsg, &errLine, &errCol);
00447 if (!r) {
00448 klfWarning("XML parse error: "<<qPrintable(errMsg)
00449 <<" ("<<qPrintable(userScriptBaseName())<<" default-settings, line "
00450 <<errLine<<" col "<<errCol<<")") ;
00451 return QVariantMap();
00452 }
00453
00454 QDomElement root = doc.documentElement();
00455 if (root.nodeName() != "klfuserscript-default-settings") {
00456 klfWarning("expected <klfuserscript-default-settings> as root document element");
00457 return QVariantMap();
00458 }
00459
00460 QVariantMap config = klfLoadVariantMapFromXML(root);
00461 return config;
00462 }
00463
00464
00465
00466
00467 QMap<QString,QVariant> config;
00468 foreach (QByteArray line, trimmedstdoutdata.split('\n')) {
00469 if (!line.size()) {
00470 continue;
00471 }
00472 int idxeq = line.indexOf('=');
00473 if (idxeq == -1) {
00474 klfWarning("Invalid line in reported userscript default config: " << line) ;
00475 continue;
00476 }
00477 config[QString::fromUtf8(line.left(idxeq)).trimmed()] = line.mid(idxeq+1).trimmed();
00478 }
00479
00480 return config;
00481 }
00482
00483
00484
00485 QByteArray KLFUserScriptInfo::categorySpecificXmlConfig() const
00486 {
00487 return scriptInfo(CategorySpecificXmlConfig).toByteArray();
00488 }
00489
00490
00491 bool KLFUserScriptInfo::hasNotices() const
00492 {
00493 return d->notices.size();
00494 }
00495 bool KLFUserScriptInfo::hasWarnings() const
00496 {
00497 return d->warnings.size();
00498 }
00499 bool KLFUserScriptInfo::hasErrors() const
00500 {
00501 return d->errors.size();
00502 }
00503
00504 KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, notices) ;
00505
00506 KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, warnings) ;
00507
00508 KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, errors) ;
00509
00510
00511
00512 QVariant KLFUserScriptInfo::scriptInfo(int propId) const
00513 {
00514 return d()->property(propId);
00515 }
00516
00517 QVariant KLFUserScriptInfo::scriptInfo(const QString& field) const
00518 {
00519 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00520 QString x = field;
00521
00522 if (x == QLatin1String("Authors")) {
00523 x = QLatin1String("Author");
00524 }
00525
00526 klfDbg("x="<<x) ;
00527 int id = d()->propertyIdForName(x);
00528 if (id < 0) {
00529 klfDbg("KLFUserScriptInfo for "<<userScriptName()<<" does not have any information about "
00530 <<field<<" ("<<x<<")") ;
00531 return QVariant();
00532 }
00533 return scriptInfo(id);
00534 }
00535
00536 QStringList KLFUserScriptInfo::scriptInfosList() const
00537 {
00538 return d()->propertyNameList();
00539 }
00540
00541 QString KLFUserScriptInfo::objectKind() const { return d()->objectKind(); }
00542
00543
00544
00545 void KLFUserScriptInfo::internalSetProperty(const QString& key, const QVariant &val)
00546 {
00547 d()->setProperty(key, val);
00548 }
00549
00550 const KLFPropertizedObject * KLFUserScriptInfo::pobj()
00551 {
00552 return d();
00553 }
00554
00555
00556 static QString escapeListIntoTags(const QStringList& list, const QString& starttag, const QString& endtag)
00557 {
00558 QString html;
00559 foreach (QString s, list) {
00560 html += starttag + s.toHtmlEscaped() + endtag;
00561 }
00562 return html;
00563 }
00564
00565 QString KLFUserScriptInfo::htmlInfo(const QString& extra_css) const
00566 {
00567 QString txt =
00568 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
00569 "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
00570 "p, li { white-space: pre-wrap; }\n"
00571 "p.msgnotice { color: blue; font-weight: bold; margin: 2px 0px; }\n"
00572 "p.msgwarning { color: #a06000; font-weight: bold; margin: 2px 0px; }\n"
00573 "p.msgerror { color: #a00000; font-weight: bold; margin: 2px 0px; }\n"
00574 ".scriptinfokey { }\n"
00575 ".scriptinfovalue { font-weight: bold; }\n"
00576 + extra_css + "\n"
00577 "</style></head>\n"
00578 "<body>\n";
00579
00580
00581 if (hasNotices()) {
00582 txt += escapeListIntoTags(notices(), "<p class=\"msgnotice\">", "</p>\n");
00583 }
00584 if (hasWarnings()) {
00585 txt += escapeListIntoTags(warnings(), "<p class=\"msgwarning\">", "</p>\n");
00586 }
00587 if (hasErrors()) {
00588 txt += escapeListIntoTags(errors(), "<p class=\"msgerror\">", "</p>\n");
00589 }
00590
00591
00592 txt +=
00593 "<p style=\"-qt-block-indent: 0; text-indent: 0px; margin-top: 8px; margin-bottom: 0px\">\n"
00594 "<span class=\"scriptinfokey\">" + QObject::tr("Script Name:", "[[user script info text]]")
00595 + "</span> "
00596 "<span class=\"scriptinfovalue\">" + userScriptName().toHtmlEscaped() + "</span><br />\n";
00597
00598
00599 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Category:", "[[user script info text]]")
00600 + "</span> "
00601 "<span class=\"scriptinfovalue\">" + category().toHtmlEscaped() + "</span><br />\n";
00602
00603 if (!version().isEmpty()) {
00604
00605 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Version:", "[[user script info text]]")
00606 + "</span> "
00607 "<span class=\"scriptinfovalue\">" + version().toHtmlEscaped() + "</span><br />\n";
00608 }
00609 if (!author().isEmpty()) {
00610
00611 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Author:", "[[user script info text]]")
00612 + "</span> "
00613 "<span class=\"scriptinfovalue\">" + author().toHtmlEscaped() + "</span><br />\n";
00614 }
00615
00616 if (!license().isEmpty()) {
00617
00618 txt += "<span class=\"scriptinfokey\">" + QObject::tr("License:", "[[user script info text]]")
00619 + "</span> "
00620 "<span class=\"scriptinfovalue\">" + license().toHtmlEscaped() + "</span><br />\n";
00621 }
00622
00623 return txt;
00624 }
00625
00626
00627
00628
00629 QMap<QString,QString> KLFUserScriptInfo::usConfigToStrMap(const QVariantMap& usconfig)
00630 {
00631 QMap<QString,QString> mdata;
00632 for (QVariantMap::const_iterator it = usconfig.begin(); it != usconfig.end(); ++it)
00633 mdata[QLatin1String("KLF_USCONFIG_") + it.key()] = klfSaveVariantToText(it.value(), true);
00634 return mdata;
00635 }
00636
00637
00638 QStringList KLFUserScriptInfo::usConfigToEnvList(const QVariantMap& usconfig)
00639 {
00640 return klfMapToEnvironmentList(KLFUserScriptInfo::usConfigToStrMap(usconfig));
00641 }
00642
00643
00644 inline QStringList space_sep_values(const QString& val)
00645 {
00646 return val.split(QRegExp("\\s+"), QString::SkipEmptyParts);
00647 }
00648
00649
00650
00651
00652 struct KLFBackendEngineUserScriptInfoPrivate : public KLFPropertizedObject
00653 {
00654 KLF_PRIVATE_INHERIT_HEAD(KLFBackendEngineUserScriptInfo,
00655 : KLFPropertizedObject("KLFBackendEngineUserScriptInfo"))
00656 {
00657 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::SpitsOut, QLatin1String("SpitsOut"));
00658 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::SkipFormats, QLatin1String("SkipFormats"));
00659 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::DisableInputs, QLatin1String("DisableInputs"));
00660 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::InputFormUI, QLatin1String("InputFormUI"));
00661 }
00662 void clear()
00663 {
00664
00665 QList<int> idlist = registeredPropertyIdList();
00666 for (int k = 0; k < idlist.size(); ++k) {
00667 setProperty(idlist[k], QVariant());
00668 }
00669 }
00670
00671 void _set_xml_parsing_error(const QString& errmsg)
00672 {
00673 K->setScriptInfoError(1001, QString("Error parsing klf-backend-engine XML config: %1: %2")
00674 .arg(K->userScriptBaseName()).arg(errmsg));
00675 }
00676 void parse_category_config(const QByteArray & ba)
00677 {
00678 QDomDocument doc("klf-backend-engine");
00679 QString errMsg; int errLine, errCol;
00680 bool r = doc.setContent(ba, false, &errMsg, &errLine, &errCol);
00681 if (!r) {
00682 K->setScriptInfoError(
00683 1001,
00684 QString("XML parse error: %1 (klf-backend-engine in %2, relative line %3 col %4)")
00685 .arg(errMsg).arg(K->userScriptBaseName()).arg(errLine).arg(errCol));
00686 return;
00687 }
00688
00689 QDomElement root = doc.documentElement();
00690 if (root.nodeName() != "klf-backend-engine") {
00691 _set_xml_parsing_error(QString("expected <klf-backend-engine> element"));
00692 return;
00693 }
00694
00695
00696 clear();
00697
00698
00699 QDomNode n;
00700 for (n = root.firstChild(); !n.isNull(); n = n.nextSibling()) {
00701
00702 if ( n.nodeType() != QDomNode::ElementNode ) {
00703 continue;
00704 }
00705 QDomElement e = n.toElement();
00706 if ( e.isNull() ) {
00707 continue;
00708 }
00709
00710 QString val = e.text();
00711 if (val.isEmpty()) {
00712 val = QString();
00713 }
00714 if (e.nodeName() == "spits-out") {
00715 if (!property(KLFBackendEngineUserScriptInfo::SpitsOut).toStringList().isEmpty()) {
00716 _set_xml_parsing_error(QString("duplicate <spits-out> element"));
00717 return;
00718 }
00719 setProperty(KLFBackendEngineUserScriptInfo::SpitsOut, space_sep_values(val));
00720 } else if (e.nodeName() == "skip-formats") {
00721 if (!property(KLFBackendEngineUserScriptInfo::SkipFormats).toString().isEmpty()) {
00722 _set_xml_parsing_error(QString("duplicate <skip-formats> element"));
00723 return;
00724 }
00725 QStringList lst;
00726 if (e.hasAttribute("selector")) {
00727
00728 QString s = e.attribute("selector").toUpper();
00729 lst << space_sep_values(s.replace('-', '_'));
00730 }
00731 lst << space_sep_values(val);
00732 setProperty(KLFBackendEngineUserScriptInfo::SkipFormats, lst);
00733 } else if (e.nodeName() == "disable-inputs") {
00734 if (!property(KLFBackendEngineUserScriptInfo::DisableInputs).toStringList().isEmpty()) {
00735 _set_xml_parsing_error(QString("duplicate <disable-inputs> element"));
00736 return;
00737 }
00738 QStringList lst;
00739 if (e.hasAttribute("selector")) {
00740
00741 QString s = e.attribute("selector").toUpper();
00742 lst << space_sep_values(s.replace('-', '_'));
00743 }
00744 lst << space_sep_values(val);
00745 setProperty(KLFBackendEngineUserScriptInfo::DisableInputs, lst);
00746 } else if (e.nodeName() == "input-form-ui") {
00747 if (!property(KLFBackendEngineUserScriptInfo::InputFormUI).toStringList().isEmpty()) {
00748 _set_xml_parsing_error(QString("duplicate <input-form-ui> element"));
00749 return;
00750 }
00751 setProperty(KLFBackendEngineUserScriptInfo::InputFormUI, val);
00752 } else {
00753 _set_xml_parsing_error(QString("Found unexpected element: %1").arg(e.nodeName()));
00754 return;
00755 }
00756 }
00757
00758 klfDbg("Read all klfbackend-engine properties:\n" << qPrintable(toString()));
00759 }
00760 };
00761
00762
00763
00764 KLFBackendEngineUserScriptInfo::KLFBackendEngineUserScriptInfo(const QString& uspath)
00765 : KLFUserScriptInfo(uspath)
00766 {
00767 KLF_INIT_PRIVATE(KLFBackendEngineUserScriptInfo) ;
00768
00769 if (category() != "klf-backend-engine") {
00770 klfWarning("KLFBackendEngineUserScriptInfo instantiated for user script "
00771 << uspath << ", which is of category " << category()) ;
00772 } else {
00773 d->parse_category_config(categorySpecificXmlConfig());
00774 }
00775 }
00776
00777 KLFBackendEngineUserScriptInfo::~KLFBackendEngineUserScriptInfo()
00778 {
00779 KLF_DELETE_PRIVATE ;
00780 }
00781
00782
00783
00784 QStringList KLFBackendEngineUserScriptInfo::spitsOut() const
00785 {
00786 return klfBackendEngineInfo(SpitsOut).toStringList();
00787 }
00788 QStringList KLFBackendEngineUserScriptInfo::skipFormats() const
00789 {
00790 return klfBackendEngineInfo(SkipFormats).toStringList();
00791 }
00792 QStringList KLFBackendEngineUserScriptInfo::disableInputs() const
00793 {
00794 return klfBackendEngineInfo(DisableInputs).toStringList();
00795 }
00796 QString KLFBackendEngineUserScriptInfo::inputFormUI() const
00797 {
00798 return klfBackendEngineInfo(InputFormUI).toString();
00799 }
00800
00801
00802 QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(int propId) const
00803 {
00804 return d->property(propId);
00805 }
00806
00807 QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(const QString& field) const
00808 {
00809 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00810 QString x = field;
00811
00812 klfDbg("x="<<x) ;
00813 int id = d->propertyIdForName(x);
00814 if (id < 0) {
00815 klfDbg("KLFBackendEngineUserScriptInfo for "<<userScriptName()<<" does not have any information about "
00816 <<field<<" ("<<x<<")") ;
00817 return QVariant();
00818 }
00819 return scriptInfo(id);
00820 }
00821
00822 QStringList KLFBackendEngineUserScriptInfo::klfBackendEngineInfosList() const
00823 {
00824 return d->propertyNameList();
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838 struct KLFUserScriptFilterProcessPrivate
00839 {
00840 KLF_PRIVATE_HEAD(KLFUserScriptFilterProcess)
00841 {
00842 usinfo = NULL;
00843 }
00844
00845 KLFUserScriptInfo * usinfo;
00846
00847
00848 static QStringList log;
00849 };
00850
00851
00852 QStringList KLFUserScriptFilterProcessPrivate::log = QStringList();
00853
00854
00855 KLFUserScriptFilterProcess::KLFUserScriptFilterProcess(const QString& userScriptFileName,
00856 const KLFBackend::klfSettings * settings)
00857 : KLFFilterProcess("User Script " + userScriptFileName, settings, QString(), true)
00858 {
00859 KLF_DEBUG_BLOCK(KLF_FUNC_NAME);
00860 klfDbg("userScriptFileName= "<<userScriptFileName) ;
00861
00862 KLF_INIT_PRIVATE(KLFUserScriptFilterProcess) ;
00863
00864 d->usinfo = new KLFUserScriptInfo(userScriptFileName);
00865
00866 QString exescript = d->usinfo->exeScriptFullPath();
00867 klfDbg("exescript = " << exescript) ;
00868 setArgv(QStringList() << exescript);
00869 }
00870
00871
00872 KLFUserScriptFilterProcess::~KLFUserScriptFilterProcess()
00873 {
00874 delete d->usinfo;
00875 KLF_DELETE_PRIVATE ;
00876 }
00877
00878 void KLFUserScriptFilterProcess::addUserScriptConfig(const QVariantMap& usconfig)
00879 {
00880 QStringList envlist = KLFUserScriptInfo::usConfigToEnvList(usconfig);
00881 addExecEnviron(envlist);
00882 }
00883
00884
00885 bool KLFUserScriptFilterProcess::do_run(const QByteArray& indata, const QMap<QString, QByteArray*> outdatalist)
00886 {
00887 bool ret = KLFFilterProcess::do_run(indata, outdatalist);
00888
00889
00890 QString thislog = QString::fromLatin1("<h1 class=\"userscript-run\">")
00891 + QObject::tr("Output from %1", "KLFUserScriptFilterProcess").arg(QLatin1String("<span class=\"userscriptname\">")
00892 +d->usinfo->userScriptBaseName().toHtmlEscaped()
00893 +QLatin1String("</span>")) +
00894 QLatin1String("</h1>\n") +
00895 QLatin1String("<p class=\"userscript-run-datetime\">") +
00896 QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate).toHtmlEscaped()
00897 + QLatin1String("</p>") ;
00898
00899
00900 QString errstr = resultErrorString();
00901 if (errstr.size()) {
00902 thislog += QString::fromLatin1("<div class=\"userscript-error\">%1</div>").arg(errstr);
00903 }
00904
00905 QString templ = QString::fromLatin1("<p><span class=\"output-type\">%1</span>\n"
00906 "<pre class=\"output\">%2</pre></p>\n") ;
00907
00908 QByteArray bstdout = collectedStdout();
00909 if (bstdout.size()) {
00910 thislog += templ.arg("STDOUT").arg(QString::fromLocal8Bit(bstdout).toHtmlEscaped());
00911 }
00912 QByteArray bstderr = collectedStderr();
00913 if (bstderr.size()) {
00914 thislog += templ.arg("STDERR").arg(QString::fromLocal8Bit(bstderr).toHtmlEscaped());
00915 }
00916
00917
00918 if (KLFUserScriptFilterProcessPrivate::log.size() > 255) {
00919 KLFUserScriptFilterProcessPrivate::log.erase(KLFUserScriptFilterProcessPrivate::log.begin());
00920 }
00921
00922 KLFUserScriptFilterProcessPrivate::log << thislog;
00923
00924 return ret;
00925 }
00926
00927
00928 QString KLFUserScriptFilterProcess::getUserScriptLogHtml(bool include_head)
00929 {
00930 QString loghtml;
00931 QStringList::const_iterator it = KLFUserScriptFilterProcessPrivate::log.cend();
00932 while (it != KLFUserScriptFilterProcessPrivate::log.cbegin()) {
00933 --it;
00934 loghtml += *it;
00935 }
00936 if (!include_head) {
00937 return loghtml;
00938 }
00939 return QLatin1String("<html><head>"
00940 "<meta charset=\"utf-8\">"
00941 "<title>User Script Log</title>"
00942 "<style type=\"text/css\">"
00943 ".userscript-run { font-weight: bold; font-size: 2em; } "
00944 ".userscriptname { font: monospace; } "
00945 ".output-type { font-weight: bold; } "
00946 "</style>"
00947 "</head>"
00948 "<body>") + loghtml + QLatin1String("</body></html>") ;
00949 }