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 }