/** \file PluginsManager.cpp \brief Define the class to manage and load the plugins \author alpha_one_x86 \version 0.3 \date 2010 \licence GPL3, see the file COPYING */ #include #include #include #include #include #include "PluginsManager.h" /// \brief Create the manager and load the defaults variables PluginsManager::PluginsManager() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //load the overall instance pluginLoaded=false; resources=ResourcesManager::getInstance(); options=OptionEngine::getInstance(); language="en"; stopIt=false; editionSemList.release(); checkPluginThread=new AuthPlugin(); englishPluginType << "CopyEngine" << "Languages" << "Listener" << "PluginLoader" << "SessionLoader" << "Themes"; //catPlugin << tr("CopyEngine") << tr("Languages") << tr("Listener") << tr("PluginLoader") << tr("SessionLoader") << tr("Themes"); importingPlugin=false; connect(&decodeThread, SIGNAL(decodedIsFinish()), this, SLOT(decodingFinished()),Qt::QueuedConnection); connect(checkPluginThread, SIGNAL(authentifiedPath(QString)), this, SLOT(newAuthPath(QString)),Qt::QueuedConnection); connect(this, SIGNAL(finished()), this, SLOT(post_operation()),Qt::QueuedConnection); connect(this, SIGNAL(newLanguageLoaded()), &pluginInformationWindows, SLOT(retranslateInformation()),Qt::QueuedConnection); // connect(this, SIGNAL(pluginListingIsfinish()), options,SLOT(setInterfaceValue())); //load the plugins list /// \bug bug when I put here: moveToThread(this);, due to the direction connection to remove the plugin start(); } /// \brief Destroy the manager PluginsManager::~PluginsManager() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); int index=0; int loop_size=pluginsList.size(); while(indexisRunning()) this->wait(0); delete checkPluginThread; OptionEngine::destroyInstanceAtTheLastCall(); ResourcesManager::destroyInstanceAtTheLastCall(); } /// \brief set current language void PluginsManager::setLanguage(const QString &language) { this->language=language; } void PluginsManager::post_operation() { pluginLoaded=true; emit pluginListingIsfinish(); } bool PluginsManager::allPluginHaveBeenLoaded() { return pluginLoaded; } void PluginsManager::lockPluginListEdition() { editionSemList.acquire(); } void PluginsManager::unlockPluginListEdition() { editionSemList.release(); } void PluginsManager::run() { //load the path and plugins into the path QStringList readPath; readPath << resources->getReadPath(); pluginsList.clear(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"pluginsList.size(): "+QString::number(pluginsList.size())); foreach(QString basePath,readPath) { foreach(QString dirSub,englishPluginType) { QString pluginComposed=basePath+dirSub+QDir::separator(); QDir dir(pluginComposed); if(stopIt) return; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"search plugin into: "+pluginComposed); if(dir.exists()) { foreach(QString dirName, dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) { if(stopIt) return; loadPluginInformation(pluginComposed+dirName+QDir::separator()); } } } } #ifdef ULTRACOPIER_DEBUG int index=0; int loop_size=pluginsList.size(); while(indexloadSearchPath(readPath,englishPluginType); checkPluginThread->stop(); checkPluginThread->start(); checkDependencies(); } QString PluginsManager::categoryToString(const PluginType &category) { switch(category) { case PluginType_CopyEngine: return "CopyEngine"; break; case PluginType_Languages: return "Languages"; break; case PluginType_Listener: return "Listener"; break; case PluginType_PluginLoader: return "PluginLoader"; break; case PluginType_SessionLoader: return "SessionLoader"; break; case PluginType_Themes: return "Themes"; break; default: ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"cat text not found"); return "Unknow"; break; } } QString PluginsManager::categoryToTranslation(const PluginType &category) { return pluginInformationWindows.categoryToTranslation(category); } bool PluginsManager::isSamePlugin(const PluginsAvailable &pluginA,const PluginsAvailable &pluginB) { /*if(pluginA.category!=pluginB.category) return false;*/ //only this test should be suffisent if(pluginA.path!=pluginB.path) return false; /*if(pluginA.name!=pluginB.name) return false; if(pluginA.writablePath!=pluginB.writablePath) return false; if(pluginA.categorySpecific!=pluginB.categorySpecific) return false; if(pluginA.version!=pluginB.version) return false; if(pluginA.informations!=pluginB.informations) return false;*/ return true; } bool PluginsManager::loadPluginInformation(const QString &path) { PluginsAvailable tempPlugin; tempPlugin.isAuth = false; tempPlugin.path = path; tempPlugin.category = PluginType_Unknow; QDir pluginPath(path); if(pluginPath.cdUp() && pluginPath.cdUp() && resources->getWritablePath()!="" && pluginPath==QDir(resources->getWritablePath())) tempPlugin.isWritable=true; else tempPlugin.isWritable=false; QFile xmlMetaData(path+"informations.xml"); if(xmlMetaData.exists()) { if(xmlMetaData.open(QIODevice::ReadOnly)) { loadPluginXml(&tempPlugin,xmlMetaData.readAll()); xmlMetaData.close(); } else { tempPlugin.errorString=tr("informations.xml is not accessible"); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"informations.xml is not accessible into the plugin: "+path); } } else { tempPlugin.errorString=tr("informations.xml not found into the plugin"); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"informations.xml not found into the plugin: "+path); } editionSemList.acquire(); pluginsList << tempPlugin; if(tempPlugin.errorString=="") pluginsListIndexed.insert(tempPlugin.category,tempPlugin); editionSemList.release(); if(tempPlugin.errorString=="") { emit onePluginAdded(tempPlugin); return true; } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Error detected, the not loaded: "+tempPlugin.errorString+", for path: "+tempPlugin.path); return false; } } void PluginsManager::loadPluginXml(PluginsAvailable * thePlugin,const QByteArray &xml) { QString errorStr; int errorLine; int errorColumn; QDomDocument domDocument; if (!domDocument.setContent(xml, false, &errorStr,&errorLine,&errorColumn)) { thePlugin->errorString=tr("%1, parse error at line %2, column %3: %4").arg("informations.xml").arg(errorLine).arg(errorColumn).arg(errorStr); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("%1, Parse error at line %2, column %3: %4").arg("informations.xml").arg(errorLine).arg(errorColumn).arg(errorStr)); } else { QDomElement root = domDocument.documentElement(); if (root.tagName() != "package") { thePlugin->errorString=tr("\"package\" root tag not found for the xml file"); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"\"package\" root balise not found for the xml file"); } //load the variable if(thePlugin->errorString=="") loadBalise(root,"title",&(thePlugin->informations),&(thePlugin->errorString),true,true,true); if(thePlugin->errorString=="") loadBalise(root,"website",&(thePlugin->informations),&(thePlugin->errorString),false,true); if(thePlugin->errorString=="") loadBalise(root,"description",&(thePlugin->informations),&(thePlugin->errorString),true,true,true); if(thePlugin->errorString=="") loadBalise(root,"author",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") loadBalise(root,"pubDate",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") { loadBalise(root,"version",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") thePlugin->version=thePlugin->informations.last().last(); } if(thePlugin->errorString=="") { loadBalise(root,"category",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") { QString tempCat=thePlugin->informations.last().last(); if(tempCat=="Languages") thePlugin->category=PluginType_Languages; else if(tempCat=="CopyEngine") thePlugin->category=PluginType_CopyEngine; else if(tempCat=="Listener") thePlugin->category=PluginType_Listener; else if(tempCat=="PluginLoader") thePlugin->category=PluginType_PluginLoader; else if(tempCat=="SessionLoader") thePlugin->category=PluginType_SessionLoader; else if(tempCat=="Themes") thePlugin->category=PluginType_Themes; else thePlugin->errorString="Unknow category: "+QString::number((int)thePlugin->category); if(thePlugin->errorString.isEmpty()) { if(thePlugin->category!=PluginType_Languages) { loadBalise(root,"architecture",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") { #ifndef ULTRACOPIER_VERSION_PORTABLE if(thePlugin->informations.last().last()!=ULTRACOPIER_PLATFORM_CODE) thePlugin->errorString="Wrong platform code: "+thePlugin->informations.last().last(); #endif } } } } } if(thePlugin->errorString=="") { loadBalise(root,"name",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") { thePlugin->name=thePlugin->informations.last().last(); int index=0; int loop_size=pluginsList.size(); int sub_index,loop_sub_size; while(indexname && pluginsList.at(index).category==thePlugin->category) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Plugin duplicate found ("+QString::number((int)thePlugin->category)+"/"+pluginsList.at(index).informations.at(sub_index).last()+"), already loaded, actual version skipped: "+thePlugin->version); thePlugin->errorString=tr("Duplicated plugin found, already loaded!"); break; break; } sub_index++; } index++; } } } if(thePlugin->errorString=="") loadBalise(root,"dependencies",&(thePlugin->informations),&(thePlugin->errorString),true,false); if(thePlugin->errorString=="") { QDomElement child = root.firstChildElement("categorySpecific"); if(!child.isNull() && child.isElement()) thePlugin->categorySpecific=child; } } } /// \brief to load the multi-language balise void PluginsManager::loadBalise(const QDomElement &root,const QString &name,QList *informations,QString *errorString,bool needHaveOneEntryMinimum,bool multiLanguage,bool englishNeedBeFound) { int foundElement=0; bool englishTextIsFoundForThisChild=false; QDomElement child = root.firstChildElement(name); while(!child.isNull()) { if(child.isElement()) { QStringList newInformations; if(multiLanguage) { if(child.hasAttribute("xml:lang")) { if(child.attribute("xml:lang")=="en") englishTextIsFoundForThisChild=true; foundElement++; newInformations << child.tagName() << child.attribute("xml:lang") << child.text(); } else ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Have not the attribute xml:lang: child.tagName(): %1, child.text(): %2").arg(child.tagName()).arg(child.text())); } else { foundElement++; newInformations << child.tagName() << child.text(); } *informations << newInformations; } else ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Is not Element: child.tagName(): %1").arg(child.tagName())); child = child.nextSiblingElement(name); } if(multiLanguage && englishTextIsFoundForThisChild==false && englishNeedBeFound) { informations->clear(); *errorString=tr("English text missing into the informations.xml for the tag: %1").arg(name); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("English text missing into the informations.xml for the tag: %1").arg(name)); return; } if(needHaveOneEntryMinimum && foundElement==0) { informations->clear(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Tag not found: %1").arg(name)); *errorString=tr("Tag not found: %1").arg(name); } } /// \brief to load the get dom specific QString PluginsManager::getDomSpecific(const QDomElement &root,const QString &name,const QList > &listChildAttribute) { QDomElement child = root.firstChildElement(name); int index,loop_size; bool allIsFound; while(!child.isNull()) { if(child.isElement()) { allIsFound=true; index=0; loop_size=listChildAttribute.size(); while(index|>=)[a-zA-Z0-9\\-]+-([0-9]+\\.)*[0-9]+$"))) { pluginsList[index].informations.clear(); pluginsList[index].errorString=tr("Dependencies part is wrong"); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Dependencies part is wrong: %1").arg(dependenciesToParse)); break; } QString partName=dependenciesToParse; partName=partName.remove(QRegExp("(<=|<|=|>|>=)")); partName=partName.remove(QRegExp("-([0-9]+\\.)*[0-9]+")); QString partVersion=dependenciesToParse; partVersion=partVersion.remove(QRegExp("(<=|<|=|>|>=)")); partVersion=partVersion.remove(QRegExp("[a-zA-Z0-9\\-]+-")); QString partComp=dependenciesToParse; partComp=partComp.remove(QRegExp("[a-zA-Z0-9\\-]+-([0-9]+\\.)*[0-9]+")); //current version soft QString pluginVersion=getPluginVersion(partName); depCheck=compareVersion(pluginVersion,partComp,partVersion); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"dependencies to resolv, partName: "+partName+", partVersion: "+partVersion+", partComp: "+partComp+", pluginVersion: "+pluginVersion+", depCheck: "+QString::number(depCheck)); if(!depCheck) { pluginsList[index].informations.clear(); pluginsList[index].errorString=tr("Dependencies %1 are not satisfied, for plugin: %2").arg(dependenciesToParse).arg(pluginsList[index].path); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Dependencies %1 are not satisfied, for plugin: %2").arg(dependenciesToParse).arg(pluginsList[index].path)); break; } indexOfDependencies++; } } sub_index++; } index++; } } /// \brief get the version QString PluginsManager::getPluginVersion(const QString &pluginName) { if(pluginName=="ultracopier") return ULTRACOPIER_VERSION; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); int index=0; while(index") defaultReturnValue=false; while(indexreaNumberB) return false; if(reaNumberA") { if(reaNumberAreaNumberB) return true; } if(sign=="<=") { if(reaNumberA>reaNumberB) return false; if(reaNumberA=") { if(reaNumberAreaNumberB) return true; } index++; } return defaultReturnValue; } QList PluginsManager::getPluginsByCategory(const PluginType &category) { return pluginsListIndexed.values(category); } QList PluginsManager::getPlugins() { QList list; int index=0; while(index dataList = tarFile.getDataList(); if(fileList.size()>1) { QString basePluginArchive=""; /* block use less for tar? if(fileList.at(0).contains(QRegExp("[\\/]"))) { bool folderFoundEveryWhere=true; basePluginArchive=fileList.at(0); basePluginArchive.remove(QRegExp("[\\/].*$")); for (int i = 0; i < list.size(); ++i) { if(!fileList.at(i).startsWith(basePluginArchive)) { folderFoundEveryWhere=false; break; } } if(folderFoundEveryWhere) { for (int i = 0; i < fileList.size(); ++i) fileList[i].remove(0,basePluginArchive.size()); } else basePluginArchive=""; }*/ PluginsAvailable tempPlugin; QString categoryFinal=""; for (int i = 0; i < fileList.size(); ++i) if(fileList.at(i)=="informations.xml") { loadPluginXml(&tempPlugin,dataList.at(i)); break; } if(tempPlugin.errorString=="") { categoryFinal=categoryToString(tempPlugin.category); if(categoryFinal!="") { QString writablePath=resources->getWritablePath(); if(writablePath!="") { QDir dir; QString finalPluginPath=writablePath+categoryFinal+QDir::separator()+tempPlugin.name+QDir::separator(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"writablePath: \""+writablePath+"\""); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"basePluginArchive: \""+basePluginArchive+"\""); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"categoryFinal: \""+categoryFinal+"\""); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"finalPluginPath: \""+finalPluginPath+"\""); if(!dir.exists(finalPluginPath)) { bool errorFound=false; for (int i = 0; i < fileList.size(); ++i) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"file "+QString::number(i)+": "+finalPluginPath+fileList.at(i)); fileList[i].remove(QRegExp("^(..?[\\/])+")); QFile currentFile(finalPluginPath+fileList.at(i)); QFileInfo info(currentFile); if(!dir.exists(info.absolutePath())) if(!dir.mkpath(info.absolutePath())) { resources->disableWritablePath(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Unable to make the path: "+info.absolutePath()); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to create a folder to install the plugin:\n%1").arg(info.absolutePath())); errorFound=true; break; } if(currentFile.open(QIODevice::ReadWrite)) { currentFile.write(dataList.at(i)); currentFile.close(); } else { resources->disableWritablePath(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Unable to make the file: "+info.absolutePath()+", error:"+currentFile.errorString()); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to create a file to install the plugin:\n%1\nsince:%2").arg(info.absolutePath()).arg(currentFile.errorString())); errorFound=true; break; } } if(!errorFound) { if(loadPluginInformation(finalPluginPath)) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"push the new plugin into the real list"); checkDependencies(); emit needLangToRefreshPluginList(); } } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Folder with same name is present, skip the plugin installation: "+finalPluginPath); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Folder with same name is present, skip the plugin installation:\n%1").arg(finalPluginPath)); } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Have not writable path, then how add you plugin?"); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it")); } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"category into informations.xml not found!"); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it")); } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Error in the xml: "+tempPlugin.errorString); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it: %1").arg(tempPlugin.errorString)); } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"No file found into the plugin"); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it")); } } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"decodeThread.errorFound(), error: "+decodeThread.errorString()); QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it: %1").arg(decodeThread.errorString())); } importingPlugin=false; } void PluginsManager::newAuthPath(const QString &path) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); int index=0; while(index