//=============================================================================
//
// File : AddonFunctions.cpp
// Creation date : Fri 02 May 2008 17:36:07 by Elvio Basello
//
// This file is part of the KVIrc IRC Client distribution
// Copyright (C) 2008 Elvio Basello
//
// This program is FREE software. You can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the HOPE that it will be USEFUL,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================
#include "AddonFunctions.h"
#include "KviPackageReader.h"
#include "KviPackageWriter.h"
#include "KviLocale.h"
#include "KviMessageBox.h"
#include "KviApplication.h"
#include "KviHtmlDialog.h"
#include "KviIconManager.h"
#include "KviFileUtils.h"
#include "KviMiscUtils.h"
#include "kvi_sourcesdate.h"
#include "KviMainWindow.h"
#include "KviKvsScript.h"
#include
#include
#include
#include
#include
#include
#include
namespace AddonFunctions
{
bool notAValidAddonPackage(QString &szError)
{
szError = __tr2qs_ctx("The selected file does not seem to be a valid KVIrc addon package","addon");
return false;
}
bool installAddonPackage(const QString &szAddonPackageFileName,QString &szError,QWidget * pDialogParent)
{
KviPointerHashTable * pInfoFields;
QString * pValue;
QString szErr;
QPixmap pix;
QByteArray * pByteArray;
bool bInstall;
KviHtmlDialogData hd;
const char * check_fields[] = { "Name", "Version", "Author", "Description", "Date", "Application" };
// check if it is a valid addon file
KviPackageReader r;
if(!r.readHeader(szAddonPackageFileName))
{
szErr = r.lastError();
szError = QString(__tr2qs_ctx("The selected file does not seem to be a valid KVIrc package: %1","addon")).arg(szErr);
return false;
}
pInfoFields = r.stringInfoFields();
pValue = pInfoFields->find("PackageType");
if(!pValue)
return notAValidAddonPackage(szError);
if(!KviQString::equalCI(*pValue,"AddonPack"))
return notAValidAddonPackage(szError);
pValue = pInfoFields->find("AddonPackVersion");
if(!pValue)
return notAValidAddonPackage(szError);
// make sure the default fields exist
for(int i=0;i<6;i++)
{
pValue = pInfoFields->find(check_fields[i]);
if(!pValue)
return notAValidAddonPackage(szError);
}
// ok.. it should be really valid at this point
// load its picture
pByteArray = r.binaryInfoFields()->find("Image");
if(pByteArray)
pix.loadFromData(*pByteArray,0,0);
if(pix.isNull())
{
// load the default icon
pix = *(g_pIconManager->getBigIcon(KVI_BIGICON_ADDONS));
}
QString szPackageName;
QString szPackageVersion;
QString szPackageAuthor;
QString szPackageDescription;
QString szPackageDate;
QString szAddonPackVersion;
QString szPackageApplication;
QString szMinKVIrcVersion;
QString szAuthor = __tr2qs_ctx("Author","addon");
QString szCreatedAt = __tr2qs_ctx("Created at","addon");
QString szCreatedWith = __tr2qs_ctx("Created with","addon");
r.getStringInfoField("Name",szPackageName);
r.getStringInfoField("Version",szPackageVersion);
r.getStringInfoField("Author",szPackageAuthor);
r.getStringInfoField("Description",szPackageDescription);
r.getStringInfoField("Application",szPackageApplication);
r.getStringInfoField("Date",szPackageDate);
r.getStringInfoField("AddonPackVersion",szAddonPackVersion);
r.getStringInfoField("MinimumKVIrcVersion",szMinKVIrcVersion);
QString szWarnings;
QString szTmp;
bool bValid = true;
if(szPackageName.isEmpty() || szPackageVersion.isEmpty() || szAddonPackVersion.isEmpty())
bValid = false;
if(KviMiscUtils::compareVersions(szAddonPackVersion,KVI_CURRENT_ADDONS_ENGINE_VERSION) < 0)
bValid = false;
if(!szMinKVIrcVersion.isEmpty())
{
if(KviMiscUtils::compareVersions(szMinKVIrcVersion,KVI_VERSION) < 0)
bValid = false;
}
if(!bValid)
{
szWarnings += "";
szWarnings += __tr2qs_ctx("Warning: The addon might be incompatible with this version of KVIrc","addon");
szWarnings += "
";
}
hd.szHtmlText = QString(
"" \
"" \
"" \
"%1 %2
" \
"" \
"" \
"
" \
"" \
"" \
"%3" \
"" \
"" \
"%4: %5
" \
"%6: %7
" \
"" \
"" \
"" \
"%8: %9
" \
"" \
"" \
"%10" \
"
" \
"" \
"").arg(szPackageName,szPackageVersion,szPackageDescription,szAuthor,szPackageAuthor,szCreatedAt,szPackageDate,szCreatedWith,szPackageApplication).arg(szWarnings);
hd.addImageResource("addon_dialog_pack_image",pix);
hd.addHtmlResource("addon_dialog_main",hd.szHtmlText);
QString beginCenter = "";
QString endCenter = "";
hd.szCaption = __tr2qs_ctx("Install Addon Pack - KVIrc","addon");
hd.szUpperLabelText = beginCenter + __tr2qs_ctx("You're about to install the following addon package","addon") + endCenter;
hd.szLowerLabelText = beginCenter + __tr2qs_ctx("Do you want to proceed with the installation?","addon") + endCenter;
hd.szButton1Text = __tr2qs_ctx("Do Not Install","addon");
hd.szButton2Text = __tr2qs_ctx("Yes, Proceed","addon");
hd.iDefaultButton = 2;
hd.iCancelButton = 1;
hd.pixIcon = *(g_pIconManager->getSmallIcon(KviIconManager::Addons));
hd.iMinimumWidth = 350;
hd.iMinimumHeight = 420;
hd.iFlags = KviHtmlDialogData::ForceMinimumSize;
bInstall = KviHtmlDialog::display(pDialogParent,&hd) == 2;
if(!bInstall)
return true;
// Create a random extraction dir
QString szTmpPath, szUnpackPath;
QString szRandomDir = createRandomDir();
g_pApp->getLocalKvircDirectory(szTmpPath,KviApplication::Tmp);
KviQString::ensureLastCharIs(szTmpPath,QChar(KVI_PATH_SEPARATOR_CHAR));
szUnpackPath = szTmpPath + szRandomDir;
QDir szTmpDir(szUnpackPath);
// Check for dir existence
while(szTmpDir.exists())
{
szRandomDir = createRandomDir();
szUnpackPath = szTmpPath + szRandomDir;
szTmpDir = QDir(szUnpackPath);
}
// Unpack addon package into the random tmp dir
if(!r.unpack(szAddonPackageFileName,szUnpackPath))
{
szErr = r.lastError();
szError = QString(__tr2qs_ctx("Failed to unpack the selected file: %1","addon")).arg(szErr);
return false;
}
// Now we have all stuff in ~/.config/KVIrc/tmp/$rand
KviQString::escapeKvs(&szUnpackPath, KviQString::EscapeSpace);
if(!KviKvsScript::run(QString::fromLatin1("parse %1/install.kvs").arg(szUnpackPath), g_pActiveWindow))
{
// Parsing the script failed
// However, the user should already be notified via normal script output.
}
if(!KviFileUtils::deleteDir(szUnpackPath))
QMessageBox::warning(NULL,__tr2qs_ctx("Addon Unpack Warning","addon"),__tr2qs_ctx("Failed to delete the directory '%1'","addon").arg(szUnpackPath));
return true;
}
QString createRandomDir()
{
QString szDirName;
char chars[] = {
'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','-','_','.'
};
// Generate dir name
for(int i=0;i<10;i++)
{
int n = rand() % sizeof(chars);
szDirName.append(chars[n]);
}
return szDirName;
}
bool checkDirTree(const QString &szDirPath,QString * pszError)
{
if(pszError)
*pszError = "";
QDir addon(szDirPath);
if(!addon.exists())
{
*pszError = __tr2qs_ctx("The selected directory does not exist.","addon");
return false;
}
QFileInfo init(szDirPath + "/install.kvs");
if(!init.exists())
{
*pszError = __tr2qs_ctx("The initialization script (install.kvs) does not exist.","addon");
return false;
}
return true;
}
bool pack(AddonInfo &info,QString &szError)
{
if(!checkDirTree(info.szDirPath,&szError))
return false;
if(info.szMinVersion.isEmpty())
info.szMinVersion = KVI_VERSION;
QString szTmp;
szTmp = QDateTime::currentDateTime().toString(Qt::ISODate);
KviPackageWriter pw;
pw.addInfoField("PackageType","AddonPack");
pw.addInfoField("AddonPackVersion",KVI_CURRENT_ADDONS_ENGINE_VERSION);
pw.addInfoField("Name",info.szName);
pw.addInfoField("Version",info.szVersion);
pw.addInfoField("Author",info.szAuthor);
pw.addInfoField("Description",info.szDescription);
pw.addInfoField("Date",szTmp);
pw.addInfoField("MinimumKVIrcVersion",info.szMinVersion);
pw.addInfoField("Application","KVIrc " KVI_VERSION "." KVI_SOURCES_DATE);
if(!info.szImage.isEmpty())
{
QPixmap pix(info.szImage);
if(pix.isNull())
{
szError = __tr2qs_ctx("Failed to load the image at %1","addon").arg(info.szImage);
return false;
}
QByteArray * pba = new QByteArray();
QBuffer bufferz(pba,0);
bufferz.open(QIODevice::WriteOnly);
pix.save(&bufferz,"PNG");
bufferz.close();
pw.addInfoField("Image",pba);
}
QDir dir(info.szDirPath);
QFileInfoList ls = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::NoDotAndDotDot);
if(ls.isEmpty())
{
szError = __tr2qs_ctx("The package file list is empty","addon");
return false;
}
for(QFileInfoList::Iterator it = ls.begin();it != ls.end();++it)
{
const QFileInfo &inf = *it;
if(inf.isDir())
{
if(!pw.addDirectory(inf.absoluteFilePath(),QString("%1/").arg(inf.fileName())))
{
szError = pw.lastError();
return false;
}
continue;
}
// must be a file
if(!pw.addFile(inf.absoluteFilePath(),inf.fileName()))
{
szError = pw.lastError();
return false;
}
}
// Create the addon package
if(info.szSavePath.isEmpty())
{
szError = __tr2qs_ctx("Save path is empty","addon");
return false;
}
if(!pw.pack(info.szSavePath))
{
szError = pw.lastError();
return false;
}
return true;
}
}